org.moyoman.module.tactics.tacticsimpl
Class TacticsImpl

java.lang.Object
  |
  +--org.moyoman.module.Module
        |
        +--org.moyoman.module.tactics.tacticsimpl.TacticsImpl
All Implemented Interfaces:
Cloneable, Component, ModuleInterface, Serializable, Tactics

public class TacticsImpl
extends Module
implements Tactics

This module implements the Tactics interface. It is responsible for finding sequences of moves for playing tactically. It is a low level module which does not do any strategic analysis.

This Tactics implementation is meant to be a tradeoff between skill and development time. It is meant to be sophisticated enough to produce the tactical play of at least a 10 kyu player, but simple enough that it can be implemented reasonably quickly. It is also meant to be extensible so that it can grow more sophisticated over time.

Currently, this module is stateless, but eventually results will be reused across moves. This is because most moves will only have a tactical effect on a small part of the board and so an incremental update will be much faster. If a large group is captured, then a full analysis of the board can be done.

This module implements ideas from volume 5 of Janice Kim's Learn to Play Go series, "The Palace of Memory", and from Bruce Wilcox's book "EZGO Oriental Strategy in a Nutshell" based on his three decades of experience in the field of computer go. Neither Janice or Bruce endorse the work here, and any mistakes are my responsibility alone.

The algorithm will use the following features:

This module will also use the output from other low-level modules such as Proverbs, Connection, and Ladder.

See Also:
Serialized Form

Field Summary
private  MoveDescriptorForest blackMDF
          The MoveDescriptorForest object containing sequences of good moves for Black.
private static DebugType[] dt
          The debug types that this module supports.
private  Stone[] important
          The stones which should try to be saved.
private  boolean isGenerated
          This flag is used to determine when to clear variables set by generateMove().
private  Board lastBoard
          The last board obtained from makeMove().
private  Groups lastGroups
          The last groups obtained from makeMove().
private  LooseGroups lastLooseGroups
          The last loose groups obtained from makeMove().
private  Move lastMove
          The last Stone played.
private  ModuleType[] mt
          The modules that this module requires.
private  RatedMove[] rm
          The moves that were rated by this module.
private  MoveDescriptorForest whiteMDF
          The MoveDescriptorForest object containing sequences of good moves for White.
 
Fields inherited from class org.moyoman.module.Module
 
Fields inherited from interface org.moyoman.module.tactics.Tactics
CONFIDENCE
 
Constructor Summary
TacticsImpl(GameId id, ModuleName name)
          Create the TacticsImpl object.
 
Method Summary
private  void analyzeLibertyCount(SingleLooseGroup slg)
          Increase the liberties of friendly groups, and decrease the liberties of opponents groups.
private  boolean areLegalCoordinates(int x, int y)
           
private  void calculateTacticsForSingleLooseGroup(SingleLooseGroup slg)
          Compute tactics for the loose group.
private  boolean canCuttingStoneBeCaptured(SingleGroup sg1, SingleGroup sg2, Stone st)
          Determine if an opponents stone played at the cutting point could be captured.
 Object clone()
          Clone the module.
private  boolean findConnectedDiagonal(SingleGroup sg1, SingleGroup sg2)
          This is true if the two groups are connected by a diagonal.
 void generateMove(Module[] modules)
          Generate the move for this module.
private  void generateRatedMoves(Color color)
           
private  void generateTacticalSequences(Color color)
          Generate the rated moves, and the related tactical sequences.
 MoveDescriptorForest getCurrentPlayerKoThreats()
          Get sequences of moves where the current player makes the first two moves.
 MoveDescriptorForest getCurrentPlayerSequences()
          Get sequences of moves that might occur in tactical play for the current player.
private  Point getCuttingPoint(SingleGroup sg1, SingleGroup sg2)
          Find the cutting point for the diagonal connection between two groups.
 Debug[] getDebugInformation(DebugType[] types)
          Return the debug information for this module.
 DebugType[] getDebugTypes()
          Return the types of debug information that this module supports.
private  short getLibertyCount(SingleLooseGroup slg)
          Get the liberty count for the loose group if it acts like a single group.
 RatedMove[] getMoves()
          Return the moves generated by the module.
 MoveDescriptorForest getOpponentPlayerKoThreats()
          Get sequences of moves where the opponent player makes the first two moves.
 MoveDescriptorForest getOpponentPlayerSequences()
          Get sequences of moves that might occur in tactical play for the opponent player.
 ModuleType[] getRequiredModuleList()
          Return the modules that this module requires to perform its task.
 boolean isMoveUrgent(SingleGroup sg)
          Determine if the group is stable, or if another move is required.
 boolean isMoveUrgent(SingleLooseGroup slg)
          Determine if the loose group is stable, or if another move is required.
 void makeMove(Move move, Module[] modules)
          Update the internal data structures of this module with the new move.
private  void recompute()
          Calculate tactics for all loose groups on the board.
 void setImportantStones(Stone[] stones)
          Set the stones which should preferentially be saved.
private  boolean singleALC(SingleLooseGroup slg)
          Analyze the possible sequences of moves if the loose group only has one single group.
 
Methods inherited from class org.moyoman.module.Module
checkTime, create, createHelper, debug, error, error, fatal, fatal, getAllHelpers, getHelper, getId, getKomi, getModule, getModuleName, getScheduler, information, setTime, warning, warning
 
Methods inherited from class java.lang.Object
equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 
Methods inherited from interface org.moyoman.module.ModuleInterface
getScheduler
 

Field Detail

dt

private static DebugType[] dt
The debug types that this module supports.


mt

private ModuleType[] mt
The modules that this module requires.


rm

private RatedMove[] rm
The moves that were rated by this module.


lastBoard

private Board lastBoard
The last board obtained from makeMove().


lastGroups

private Groups lastGroups
The last groups obtained from makeMove().


lastLooseGroups

private LooseGroups lastLooseGroups
The last loose groups obtained from makeMove().


blackMDF

private MoveDescriptorForest blackMDF
The MoveDescriptorForest object containing sequences of good moves for Black.


whiteMDF

private MoveDescriptorForest whiteMDF
The MoveDescriptorForest object containing sequences of good moves for White.


isGenerated

private boolean isGenerated
This flag is used to determine when to clear variables set by generateMove().


important

private Stone[] important
The stones which should try to be saved.


lastMove

private Move lastMove
The last Stone played.

Constructor Detail

TacticsImpl

public TacticsImpl(GameId id,
                   ModuleName name)
            throws InternalErrorException
Create the TacticsImpl object.

Parameters:
id - The id of the game.
name - The name of this module.
Throws:
InternalErrorException - Thrown if the operation fails for any reason.
Method Detail

generateMove

public void generateMove(Module[] modules)
Generate the move for this module. The side effect of calling this method is that an array of RatedMove objects is stored which is returned by the getMoves() method.

Specified by:
generateMove in class Module
Parameters:
modules - An array of modules which this module needs in order to perform its work. Those modules reflect the current state of the board but are copies of the actual modules, so this method is free to manipulate them.

generateTacticalSequences

private void generateTacticalSequences(Color color)
Generate the rated moves, and the related tactical sequences.


generateRatedMoves

private void generateRatedMoves(Color color)

getDebugInformation

public Debug[] getDebugInformation(DebugType[] types)
Return the debug information for this module.

Specified by:
getDebugInformation in class Module
Parameters:
types - Only return a subset of the debug types in this array.
Returns:
The debug information that this module supports.

getDebugTypes

public DebugType[] getDebugTypes()
Return the types of debug information that this module supports.

Specified by:
getDebugTypes in class Module
Returns:
The types of debug information that this module supports.

getMoves

public RatedMove[] getMoves()
Return the moves generated by the module. Note that both good and bad moves can be returned.

Specified by:
getMoves in interface ModuleInterface
Specified by:
getMoves in class Module
Returns:
An array of RatedMove objects.

getRequiredModuleList

public ModuleType[] getRequiredModuleList()
Return the modules that this module requires to perform its task.

Specified by:
getRequiredModuleList in class Module
Returns:
An array of module types that the module requires.

makeMove

public void makeMove(Move move,
                     Module[] modules)
Update the internal data structures of this module with the new move. Note that this method is called both when the client makes a move, and when the server makes a move.

Specified by:
makeMove in class Module
Parameters:
move - The move that was just made.
modules - The modules that this method needs to perform its job.

recompute

private void recompute()
Calculate tactics for all loose groups on the board. This method is called if caching is not used, or if an event such as a large group being captured affects a large part of the board and it is less error prone to recompute everything rather than try to do an incremental analysis.


calculateTacticsForSingleLooseGroup

private void calculateTacticsForSingleLooseGroup(SingleLooseGroup slg)
Compute tactics for the loose group.

Parameters:
slg - The SingleLooseGroup in question.

getLibertyCount

private short getLibertyCount(SingleLooseGroup slg)
Get the liberty count for the loose group if it acts like a single group. A fairly strict criteria must be met in order for the group to be functionally connected. For every single group in the loose group, a single string must be formed where the single groups are connected by a diagonal move where no opponent stone threatens the connection, or where the cutting stone could be captured.

Parameters:
slg - The single loose group.
Returns:
A short which is the number of liberties if a single functional group, or -1.

findConnectedDiagonal

private boolean findConnectedDiagonal(SingleGroup sg1,
                                      SingleGroup sg2)
This is true if the two groups are connected by a diagonal. That is, if there is at least one stone in each group such that the following pattern occurs: X. .X then return true, otherwise false.

Parameters:
sg1 - A SingleGroup object.
sg2 - Another SingleGroup object.
Returns:
true if the diagonal move is found, or false.

getCuttingPoint

private Point getCuttingPoint(SingleGroup sg1,
                              SingleGroup sg2)
Find the cutting point for the diagonal connection between two groups. That is, if the following pattern occurs: XO .X where the X represent a stone from each of the two groups, and the O represents a stone from the opponent, then return the empty point.

Parameters:
sg1 - A SingleGroup object.
sg2 - Another SingleGroup object.
Returns:
The point that could be cut in the diagonal connection, or null.

canCuttingStoneBeCaptured

private boolean canCuttingStoneBeCaptured(SingleGroup sg1,
                                          SingleGroup sg2,
                                          Stone st)
Determine if an opponents stone played at the cutting point could be captured. The color of the cutting stone gets to make the first move.

Parameters:
sg1 - A SingleGroup object.
sg2 - Another SingleGroup object.
st - The opponents stone to be captured.
Returns:
true if the stone can be captured, or false.

analyzeLibertyCount

private void analyzeLibertyCount(SingleLooseGroup slg)
Increase the liberties of friendly groups, and decrease the liberties of opponents groups. There are several cases to consider:
  1. If the loose group has one single group, maximize liberties if less than 5.
  2. If the opponents loose group has one single group, minimize liberties if less than 5.
  3. If the loose group is functionally a single group, maximize liberties if less than 5.
  4. If the opponents loose group is functionally a single group, minimize liberties if less than 5.


singleALC

private boolean singleALC(SingleLooseGroup slg)
Analyze the possible sequences of moves if the loose group only has one single group. Sequences of moves to both help and hurt this group are found and stored in the instance variables blackMDF and whiteMDF.

Parameters:
slg - The SingleLooseGroup in question.
Returns:
true if the group was appropriate for this method, or false.

areLegalCoordinates

private boolean areLegalCoordinates(int x,
                                    int y)

getCurrentPlayerSequences

public MoveDescriptorForest getCurrentPlayerSequences()
                                               throws NoSuchDataException
Get sequences of moves that might occur in tactical play for the current player. The sequences are not considered to be equally good, since non-optimal responses might be made by the opponent, and since non-optimal moves from a tactical perspective may be better from a higher-level view. Use the getMoves() method to determine which move this module considers to be best.

Specified by:
getCurrentPlayerSequences in interface Tactics
Returns:
A MoveDescriptorForest object which contains sequences of moves for tactical play with the current player moving first.
Throws:
NoSuchDataException - Thrown if the last move made was not generated by this player.

getOpponentPlayerSequences

public MoveDescriptorForest getOpponentPlayerSequences()
                                                throws NoSuchDataException
Get sequences of moves that might occur in tactical play for the opponent player. The sequences are not considered to be equally good. Use the getMoves() method to determine which move this module considers to be best.

Specified by:
getOpponentPlayerSequences in interface Tactics
Returns:
A MoveDescriptorForest object which contains sequences of moves for tactical play with the current player moving first.
Throws:
NoSuchDataException - Thrown if the last move made was not generated by this player.

getCurrentPlayerKoThreats

public MoveDescriptorForest getCurrentPlayerKoThreats()
                                               throws NoSuchDataException
Description copied from interface: Tactics
Get sequences of moves where the current player makes the first two moves.

Specified by:
getCurrentPlayerKoThreats in interface Tactics
Returns:
A MoveDescriptorForest, which describes various sequences of moves where the current player gets the first two moves. The first move is probably not rated very highly, but would be a good ko threat.
NoSuchDataException

getOpponentPlayerKoThreats

public MoveDescriptorForest getOpponentPlayerKoThreats()
                                                throws NoSuchDataException
Description copied from interface: Tactics
Get sequences of moves where the opponent player makes the first two moves.

Specified by:
getOpponentPlayerKoThreats in interface Tactics
Returns:
A MoveDescriptorForest, which describes various sequences of moves where the opponent player gets the first two moves. The first move is probably not rated very highly, but would be a good ko threat.
NoSuchDataException

setImportantStones

public void setImportantStones(Stone[] stones)
Set the stones which should preferentially be saved.

Specified by:
setImportantStones in interface Tactics
Parameters:
stones - The stones which are important.

isMoveUrgent

public boolean isMoveUrgent(SingleGroup sg)
Description copied from interface: Tactics
Determine if the group is stable, or if another move is required.

Specified by:
isMoveUrgent in interface Tactics
Parameters:
sg - The group in question.
Returns:
true if another move is required, or false.

isMoveUrgent

public boolean isMoveUrgent(SingleLooseGroup slg)
Description copied from interface: Tactics
Determine if the loose group is stable, or if another move is required.

Specified by:
isMoveUrgent in interface Tactics
Parameters:
slg - The loose group in question.
Returns:
true if another move is required, or false.

clone

public Object clone()
Clone the module.

Specified by:
clone in interface ModuleInterface
Overrides:
clone in class Module
Returns:
The A TacticsImpl object which is a clone of this one.