00001 //---------------------------------------------------------------------------- 00002 /** @file HandicapPlayer.cpp 00003 */ 00004 //---------------------------------------------------------------------------- 00005 00006 #include "SgSystem.h" 00007 #include "HandicapPlayer.hpp" 00008 #include "BoardUtils.hpp" 00009 00010 using namespace benzene; 00011 00012 //---------------------------------------------------------------------------- 00013 00014 HandicapPlayer::HandicapPlayer(ICEngine* ice) 00015 : BenzenePlayer(), 00016 m_ice(ice), 00017 m_assume_added_stones(true) 00018 { 00019 LogFine() << "--- HandicapPlayer" << '\n'; 00020 } 00021 00022 HandicapPlayer::~HandicapPlayer() 00023 { 00024 } 00025 00026 //---------------------------------------------------------------------------- 00027 00028 HexPoint HandicapPlayer::Search(HexBoard& brd, 00029 const Game& game_state, 00030 HexColor color, 00031 const bitset_t& consider, 00032 double max_time, 00033 double& score) 00034 { 00035 UNUSED(consider); 00036 UNUSED(max_time); 00037 UNUSED(score); 00038 // NOTE: 'color' is currently used only in a few HexAsserts below. 00039 // Remove this if it will be used outside of the HexAsserts! 00040 #ifdef NDEBUG 00041 UNUSED(color); 00042 #endif 00043 00044 HexPoint lastMove, response; 00045 HexAssert(color == !VERTICAL_COLOR); 00046 00047 m_width = (m_assume_added_stones) ? brd.Width()-1 : brd.Width(); 00048 if (m_width == brd.Height()) 00049 return RESIGN; 00050 00051 /** Handicap player wins playing second, so in this case any random 00052 move will suffice. */ 00053 if (game_state.History().empty()) { 00054 HexAssert(color == FIRST_TO_PLAY); 00055 return BoardUtils::RandomEmptyCell(brd.GetPosition()); 00056 } 00057 00058 lastMove = game_state.History().back().point(); 00059 LogInfo() << "Last move: " << lastMove << '\n'; 00060 /** For future implementation: discard the naive responseMap and 00061 just do it here. Only build the responseMap for the places on 00062 the very edge of the board. Possibly edge and second row from 00063 edge... Depends on whether the theory player will handle all 00064 the edge cases. 00065 */ 00066 buildResponseMap(brd.GetPosition()); 00067 response = m_responseMap[lastMove]; 00068 if (!brd.GetPosition().IsPlayed(response) && response != INVALID_POINT) 00069 return response; 00070 00071 LogInfo() << "Playing random move" << '\n'; 00072 return BoardUtils::RandomEmptyCell(brd.GetPosition()); 00073 } 00074 00075 void HandicapPlayer::buildResponseMap(const StoneBoard& brd) 00076 { 00077 int x, y, offset; 00078 m_responseMap.clear(); 00079 offset = (m_width > brd.Height()) ? 1 : -1; 00080 //Naive mirroring. Ignores handicap stones 00081 for (BoardIterator it = brd.Const().Interior(); it; ++it) 00082 { 00083 HexPointUtil::pointToCoords(*it, x, y); 00084 if (y > x) 00085 y = y + offset; 00086 else 00087 x = x - offset; 00088 if (y >= m_width || x >= brd.Height()) 00089 m_responseMap[*it] = INVALID_POINT; 00090 else 00091 m_responseMap[*it] = HexPointUtil::coordsToPoint(y, x); 00092 } 00093 //Handicap Stones mirroring 00094 if (m_assume_added_stones) 00095 { 00096 x = brd.Width() - 1; 00097 y = 0; 00098 makeMiai(HexPointUtil::coordsToPoint(x, y), 00099 HexPointUtil::coordsToPoint(x, y+1)); 00100 for (y = 6; y < brd.Height() - 1; y = y + 6) 00101 { 00102 makeMiai(HexPointUtil::coordsToPoint(x, y), 00103 HexPointUtil::coordsToPoint(x, y+1)); 00104 threeToOne(brd, 00105 HexPointUtil::coordsToPoint(x-1, y-3), 00106 HexPointUtil::coordsToPoint(x-1, y-4), 00107 HexPointUtil::coordsToPoint(x, y-4), 00108 HexPointUtil::coordsToPoint(x, y-3)); 00109 threeToOne(brd, 00110 HexPointUtil::coordsToPoint(x-1, y-1), 00111 HexPointUtil::coordsToPoint(x-1, y), 00112 HexPointUtil::coordsToPoint(x, y-1), 00113 HexPointUtil::coordsToPoint(x, y-2)); 00114 } 00115 y = y - 6; 00116 if (y == brd.Height() - 6 || y == brd.Height() - 7) 00117 { 00118 y = y + 2; 00119 makeMiai(HexPointUtil::coordsToPoint(x, y), 00120 HexPointUtil::coordsToPoint(x, y+1)); 00121 } 00122 if (y + 3 < brd.Height()) 00123 { 00124 threeToOne(brd, 00125 HexPointUtil::coordsToPoint(x-1, y+3), 00126 HexPointUtil::coordsToPoint(x-1, y+2), 00127 HexPointUtil::coordsToPoint(x, y+2), 00128 HexPointUtil::coordsToPoint(x, y+3)); 00129 } 00130 if (y + 4 < brd.Height()) 00131 { 00132 if (brd.IsPlayed(HexPointUtil::coordsToPoint(x-1, y+3))) 00133 { 00134 m_responseMap[HexPointUtil::coordsToPoint(x, y+4)] = 00135 HexPointUtil::coordsToPoint(x, y+3); 00136 } 00137 else 00138 { 00139 m_responseMap[HexPointUtil::coordsToPoint(x, y+4)] = 00140 HexPointUtil::coordsToPoint(x-1, y+3); 00141 } 00142 } 00143 } 00144 } 00145 00146 void HandicapPlayer::makeMiai(HexPoint p1, HexPoint p2) 00147 { 00148 m_responseMap[p1] = p2; 00149 m_responseMap[p2] = p1; 00150 } 00151 00152 void HandicapPlayer::threeToOne(const StoneBoard& brd, 00153 HexPoint dest, HexPoint p1, HexPoint p2, 00154 HexPoint p3) 00155 { 00156 if (brd.IsPlayed(dest) && brd.IsBlack(dest)) 00157 { 00158 m_responseMap[p3] = (p3 > p2) 00159 ? static_cast<HexPoint>(p3 + MAX_WIDTH) 00160 : static_cast<HexPoint>(p3 - MAX_WIDTH); 00161 } 00162 else if (brd.IsPlayed(dest)) 00163 { 00164 if (brd.IsPlayed(p2) && brd.IsPlayed(p3)) 00165 { 00166 m_responseMap[p2] = p1; 00167 m_responseMap[p3] = p1; 00168 return; 00169 } 00170 else if (brd.IsPlayed(p1) && brd.IsPlayed(p3)) 00171 { 00172 m_responseMap[p1] = p2; 00173 m_responseMap[p3] = p2; 00174 return; 00175 } 00176 else if (brd.IsPlayed(p1) && brd.IsPlayed(p2)) 00177 { 00178 m_responseMap[p1] = p3; 00179 m_responseMap[p2] = p3; 00180 return; 00181 } 00182 else 00183 { 00184 makeMiai(p1, p2); 00185 m_responseMap[p3] = (p3 > p2) 00186 ? static_cast<HexPoint>(p3 + MAX_WIDTH) 00187 : static_cast<HexPoint>(p3 - MAX_WIDTH); 00188 } 00189 } 00190 else if (brd.IsWhite(p1) || brd.IsWhite(p2) || brd.IsWhite(p3)) 00191 { 00192 m_responseMap[p3] = (p3 > p2) 00193 ? static_cast<HexPoint>(p3 + MAX_WIDTH) 00194 : static_cast<HexPoint>(p3 - MAX_WIDTH); 00195 } 00196 else 00197 { 00198 m_responseMap[p1] = dest; 00199 m_responseMap[p2] = dest; 00200 m_responseMap[p3] = dest; 00201 } 00202 } 00203 00204 //----------------------------------------------------------------------------