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