00001 //---------------------------------------------------------------------------- 00002 /** @file SpDumbTacticalPlayer.cpp 00003 See SpDumbTacticalPlayer.h */ 00004 //---------------------------------------------------------------------------- 00005 00006 #include "SgSystem.h" 00007 #include "SpDumbTacticalPlayer.h" 00008 00009 #include "GoBensonSolver.h" 00010 #include "GoBoardUtil.h" 00011 #include "GoLadder.h" 00012 #include "GoModBoard.h" 00013 #include "SgEvaluatedMoves.h" 00014 #include "SgNbIterator.h" 00015 00016 using GoLadderUtil::LadderStatus; 00017 00018 //---------------------------------------------------------------------------- 00019 00020 SpDumbTacticalMoveGenerator::SpDumbTacticalMoveGenerator(const GoBoard& board) 00021 : SpStaticMoveGenerator(board), m_useLadders(false) 00022 { } 00023 00024 int SpDumbTacticalMoveGenerator::Score(SgPoint p) 00025 { 00026 SG_UNUSED(p); 00027 // DumbTacticalMoveGenerator uses whole-board move generation, 00028 // it does not work by scoring individual moves. 00029 SG_ASSERT(false); 00030 return INT_MIN; 00031 } 00032 00033 void SpDumbTacticalMoveGenerator::GenerateMoves(SgEvaluatedMoves& eval, 00034 SgBlackWhite toPlay) 00035 { 00036 GoModBoard modBoard(m_board); 00037 GoBoard& bd = modBoard.Board(); 00038 GoRestoreToPlay restoreToPlay(bd); 00039 bd.SetToPlay(toPlay); 00040 // Don't permit player to kill its own groups. 00041 GoRestoreSuicide restoreSuicide(bd, false); 00042 GenerateDefendMoves(eval); 00043 GenerateAttackMoves(eval); 00044 // Otherwise make a random legal move that doesn't fill own eye 00045 // This will be done automatically by the simple player if no moves 00046 // have been generated. 00047 } 00048 00049 void SpDumbTacticalMoveGenerator::GenerateDefendMoves(SgEvaluatedMoves& eval) 00050 { 00051 const int stoneweight = 1000; 00052 // Do any of own blocks have just one liberty? 00053 for (GoBlockIterator anchorit(m_board); anchorit; ++anchorit) 00054 { 00055 // Ignore opponent blocks 00056 if (m_board.IsColor(*anchorit, m_board.Opponent())) 00057 continue; 00058 00059 // Try to save blocks in atari 00060 if (! m_board.InAtari(*anchorit)) 00061 continue; 00062 00063 // Don't waste saving blocks that will be laddered to death anyway 00064 if (m_useLadders) 00065 { 00066 GoLadderStatus status = LadderStatus(m_board, *anchorit, false); 00067 if (status == GO_LADDER_CAPTURED) 00068 continue; 00069 } 00070 00071 int score = stoneweight * m_board.NumStones(*anchorit); 00072 00073 // Generate liberty 00074 eval.AddMove(m_board.TheLiberty(*anchorit), score); 00075 00076 // Generate any captures that will save the group 00077 for (GoAdjBlockIterator<GoBoard> adjbit(m_board, *anchorit, 1); 00078 adjbit; ++adjbit) 00079 { 00080 int bonus = stoneweight * m_board.NumStones(*adjbit); 00081 if (m_board.InAtari(*adjbit)) 00082 // should always be true but just in case 00083 { 00084 eval.AddMove(m_board.TheLiberty(*adjbit), score + bonus); 00085 } 00086 } 00087 } 00088 } 00089 00090 void SpDumbTacticalMoveGenerator::GenerateAttackMoves(SgEvaluatedMoves& eval) 00091 { 00092 const int capturestoneweight = 100; 00093 const int firstlibweight = 100; 00094 const int secondlibweight = 20; 00095 const int stoneweight = 1; 00096 00097 // Do Benson life test 00098 SgBWSet safepoints; 00099 GoModBoard modBoard(m_board); 00100 GoBoard& bd = modBoard.Board(); 00101 GoBensonSolver benson(bd); 00102 benson.FindSafePoints(&safepoints); 00103 00104 // Find opponent blocks without two eyes (using Benson algorithm) 00105 for (GoBlockIterator anchorit(bd); anchorit; ++anchorit) 00106 { 00107 // Ignore own blocks 00108 if (bd.IsColor(*anchorit, bd.ToPlay())) 00109 continue; 00110 00111 // Ignore opponent blocks that are unconditionally alive 00112 if (safepoints[bd.Opponent()].Contains(*anchorit)) 00113 continue; 00114 00115 // Generate all ladder captures 00116 if (m_useLadders) 00117 { 00118 SgPoint tocapture, toescape; 00119 GoLadderStatus status = LadderStatus(bd, *anchorit, false, 00120 &tocapture, &toescape); 00121 if (status == GO_LADDER_CAPTURED) 00122 { 00123 int score = bd.NumStones(*anchorit) * capturestoneweight; 00124 eval.AddMove(tocapture, score); 00125 } 00126 } 00127 00128 // Score according to: 00129 // 1. -First liberties 00130 // 2. +Second liberties 00131 // 3. +Size of group 00132 // [4]. Own liberties? 00133 int firstlibs = bd.NumLiberties(*anchorit); 00134 int size = bd.NumStones(*anchorit); 00135 for (GoBoard::LibertyIterator libit(bd, *anchorit); libit; 00136 ++libit) 00137 { 00138 int secondlibs = 0; 00139 for (SgNb4Iterator nbit(*libit); nbit; ++nbit) 00140 { 00141 if (bd.IsValidPoint(*nbit) && bd.IsEmpty(*nbit)) 00142 { 00143 secondlibs++; 00144 } 00145 } 00146 int score = size * stoneweight 00147 + secondlibs * secondlibweight 00148 - firstlibs * firstlibweight; 00149 eval.AddMove(*libit, score); 00150 } 00151 } 00152 } 00153 00154