00001
00002
00003
00004
00005
00006 #include "EndgameUtils.hpp"
00007 #include "BitsetIterator.hpp"
00008 #include "BoardUtils.hpp"
00009 #include "VCSet.hpp"
00010 #include "VCUtils.hpp"
00011
00012 using namespace benzene;
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051 namespace {
00052
00053 bitset_t ComputeLossesViaStrategyStealingArgument(const StoneBoard& brd,
00054 HexColor color)
00055 {
00056 bitset_t ret;
00057 if ((brd.Width() == brd.Height())
00058 && (brd.GetPlayed(!color).count() - brd.GetPlayed(color).count() == 1))
00059 {
00060 bitset_t mirror1
00061 = BoardUtils::Mirror(brd.Const(), brd.GetPlayed(!color))
00062 - brd.GetPlayed(color);
00063 if (mirror1.count() == 1)
00064 ret |= mirror1;
00065 bitset_t mirror2 =
00066 BoardUtils::Mirror(brd.Const(), BoardUtils::Rotate(brd.Const(),
00067 brd.GetPlayed(!color)))
00068 - brd.GetPlayed(color);
00069 if (mirror2.count() == 1)
00070 ret |= mirror2;
00071 ret &= brd.GetEmpty();
00072 }
00073 return ret;
00074 }
00075
00076 bitset_t RemoveRotations(const StoneBoard& brd, const bitset_t& consider)
00077 {
00078 bitset_t ret;
00079 for (BitsetIterator it(consider); it; ++it)
00080 {
00081 HexPoint rotated = BoardUtils::Rotate(brd.Const(), *it);
00082 if (!ret.test(rotated))
00083 ret.set(*it);
00084 }
00085 return ret;
00086 }
00087
00088 bitset_t ComputeConsiderSet(const HexBoard& brd, HexColor color)
00089 {
00090 bitset_t consider = VCUtils::GetMustplay(brd, color);
00091 const InferiorCells& inf = brd.GetInferiorCells();
00092 consider = consider - inf.Vulnerable()
00093 - inf.Reversible()
00094 - inf.Dominated()
00095 - ComputeLossesViaStrategyStealingArgument(brd.GetPosition(), color);
00096 if (brd.GetPosition().IsSelfRotation())
00097 consider = RemoveRotations(brd.GetPosition(), consider);
00098 return consider;
00099 }
00100
00101 bitset_t StonesInProof(const HexBoard& brd, HexColor color)
00102 {
00103 return brd.GetPosition().GetPlayed(color)
00104 | brd.GetInferiorCells().DeductionSet(color);
00105 }
00106
00107
00108
00109
00110
00111 void TightenMoveBitset(bitset_t& moveBitset, const InferiorCells& inf)
00112 {
00113 BitsetUtil::SubtractIfLeavesAny(moveBitset, inf.Dead());
00114 BitsetUtil::SubtractIfLeavesAny(moveBitset, inf.Vulnerable());
00115 BitsetUtil::SubtractIfLeavesAny(moveBitset, inf.Captured(BLACK));
00116 BitsetUtil::SubtractIfLeavesAny(moveBitset, inf.Captured(WHITE));
00117 BitsetUtil::SubtractIfLeavesAny(moveBitset, inf.Reversible());
00118 BitsetUtil::SubtractIfLeavesAny(moveBitset, inf.Dominated());
00119 HexAssert(moveBitset.any());
00120 }
00121
00122
00123
00124
00125
00126 HexPoint MostOverlappingMove(const std::vector<VC>& VClist,
00127 const InferiorCells& inf)
00128 {
00129 bitset_t intersectSmallest;
00130 intersectSmallest.flip();
00131
00132
00133 std::vector<VC>::const_iterator it;
00134 for (it = VClist.begin(); it != VClist.end(); ++it)
00135 {
00136 bitset_t carrier = it->carrier();
00137 if ((carrier & intersectSmallest).none())
00138 break;
00139 intersectSmallest &= carrier;
00140 }
00141 LogFine() << "Intersection of smallest set is:\n"
00142 << HexPointUtil::ToString(intersectSmallest) << '\n';
00143
00144
00145 TightenMoveBitset(intersectSmallest, inf);
00146
00147 LogFine() << "After elimination of inferior cells:\n"
00148 << HexPointUtil::ToString(intersectSmallest) << '\n';
00149
00150
00151
00152 int numHits[BITSETSIZE];
00153 memset(numHits, 0, sizeof(numHits));
00154 for (it = VClist.begin(); it != VClist.end(); ++it)
00155 {
00156 bitset_t carrier = it->carrier();
00157 for (int i = 0; i < BITSETSIZE; i++)
00158 if (intersectSmallest.test(i) && carrier.test(i))
00159 numHits[i]++;
00160 }
00161
00162 int curBestMove = -1;
00163 int curMostHits = 0;
00164 for (int i = 0; i < BITSETSIZE; i++)
00165 {
00166 if (numHits[i] > curMostHits)
00167 {
00168 HexAssert(intersectSmallest.test(i));
00169 curMostHits = numHits[i];
00170 curBestMove = i;
00171 }
00172 }
00173
00174 if (curMostHits == 0)
00175 LogWarning() << "curMostHits == 0!!\n";
00176 HexAssert(curMostHits > 0);
00177 return (HexPoint)curBestMove;
00178 }
00179
00180
00181 HexPoint PlayWonGame(const HexBoard& brd, HexColor color)
00182 {
00183 HexAssert(EndgameUtils::IsWonGame(brd, color));
00184
00185
00186 VC winningVC;
00187 if (brd.Cons(color).SmallestVC(HexPointUtil::colorEdge1(color),
00188 HexPointUtil::colorEdge2(color),
00189 VC::SEMI, winningVC))
00190 {
00191 LogInfo() << "Winning SC.\n";
00192 return winningVC.key();
00193 }
00194
00195
00196 if (brd.Cons(color).Exists(HexPointUtil::colorEdge1(color),
00197 HexPointUtil::colorEdge2(color),
00198 VC::FULL))
00199 {
00200 LogFine() << "Winning VC.\n";
00201 std::vector<VC> vcs;
00202 brd.Cons(color).VCs(HexPointUtil::colorEdge1(color),
00203 HexPointUtil::colorEdge2(color),
00204 VC::FULL, vcs);
00205 return MostOverlappingMove(vcs, brd.GetInferiorCells());
00206 }
00207
00208 HexAssert(false);
00209 return INVALID_POINT;
00210 }
00211
00212
00213 HexPoint PlayLostGame(const HexBoard& brd, HexColor color)
00214 {
00215 HexAssert(EndgameUtils::IsLostGame(brd, color));
00216
00217
00218 HexColor other = !color;
00219 HexPoint otheredge1 = HexPointUtil::colorEdge1(other);
00220 HexPoint otheredge2 = HexPointUtil::colorEdge2(other);
00221
00222 LogInfo() << "Opponent has won; playing most blocking move.\n";
00223
00224
00225
00226
00227 bool connected = brd.Cons(other).Exists(otheredge1, otheredge2, VC::SEMI);
00228 std::vector<VC> vcs;
00229 brd.Cons(other).VCs(otheredge1, otheredge2,
00230 ((connected) ? VC::SEMI : VC::FULL), vcs);
00231
00232 return MostOverlappingMove(vcs, brd.GetInferiorCells());
00233 }
00234
00235 }
00236
00237
00238
00239 bool EndgameUtils::IsWonGame(const HexBoard& brd, HexColor color,
00240 bitset_t& proof)
00241 {
00242 if (brd.GetGroups().GetWinner() == color)
00243 {
00244 proof = StonesInProof(brd, color);
00245 return true;
00246 }
00247 VC vc;
00248 const HexPoint edge1 = HexPointUtil::colorEdge1(color);
00249 const HexPoint edge2 = HexPointUtil::colorEdge2(color);
00250 if (brd.Cons(color).SmallestVC(edge1, edge2, VC::SEMI, vc))
00251 {
00252 proof = vc.carrier() | StonesInProof(brd, color);
00253 return true;
00254 }
00255 if (brd.Cons(color).SmallestVC(edge1, edge2, VC::FULL, vc))
00256 {
00257 proof = vc.carrier() | StonesInProof(brd, color);
00258 return true;
00259 }
00260 return false;
00261 }
00262
00263 bool EndgameUtils::IsLostGame(const HexBoard& brd, HexColor color,
00264 bitset_t& proof)
00265 {
00266 if (brd.GetGroups().GetWinner() == !color)
00267 {
00268 proof = StonesInProof(brd, !color);
00269 return true;
00270 }
00271 VC vc;
00272 if (brd.Cons(!color).SmallestVC(HexPointUtil::colorEdge1(!color),
00273 HexPointUtil::colorEdge2(!color),
00274 VC::FULL, vc))
00275 {
00276 proof = vc.carrier() | StonesInProof(brd, !color);
00277 return true;
00278 }
00279 if (ComputeConsiderSet(brd, color).none())
00280 {
00281 proof = brd.GetPosition().GetEmpty() | StonesInProof(brd, !color);
00282 return true;
00283 }
00284 return false;
00285 }
00286
00287 bool EndgameUtils::IsDeterminedState(const HexBoard& brd, HexColor color,
00288 HexEval& score, bitset_t& proof)
00289 {
00290 score = 0;
00291 if (IsWonGame(brd, color, proof))
00292 {
00293 score = IMMEDIATE_WIN;
00294 return true;
00295 }
00296 if (IsLostGame(brd, color, proof))
00297 {
00298 score = IMMEDIATE_LOSS;
00299 return true;
00300 }
00301 return false;
00302 }
00303
00304 HexPoint EndgameUtils::PlayDeterminedState(const HexBoard& brd, HexColor color)
00305
00306 {
00307 HexAssert(HexColorUtil::isBlackWhite(color));
00308 HexAssert(IsDeterminedState(brd, color));
00309 HexAssert(!brd.GetGroups().IsGameOver());
00310
00311 if (IsWonGame(brd, color))
00312 return PlayWonGame(brd, color);
00313
00314 HexAssert(IsLostGame(brd, color));
00315 return PlayLostGame(brd, color);
00316 }
00317
00318 bitset_t EndgameUtils::MovesToConsider(const HexBoard& brd, HexColor color)
00319 {
00320 HexAssert(HexColorUtil::isBlackWhite(color));
00321 HexAssert(!IsDeterminedState(brd, color));
00322
00323 bitset_t consider = ComputeConsiderSet(brd, color);
00324 HexAssert(consider.any());
00325
00326 LogFine() << "Moves to consider for " << color << ":"
00327 << brd.Write(consider) << '\n';
00328 return consider;
00329 }
00330
00331