Index   Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

GoLadder.cpp

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 /** @file GoLadder.cpp */
00003 //----------------------------------------------------------------------------
00004 
00005 #include "SgSystem.h"
00006 #include "GoLadder.h"
00007 
00008 #include <algorithm>
00009 #include <memory>
00010 #include "GoBoard.h"
00011 #include "GoBoardUtil.h"
00012 #include "GoModBoard.h"
00013 #include "SgVector.h"
00014 #include "SgStack.h"
00015 
00016 using namespace std;
00017 using GoBoardUtil::NeighborsOfColor;
00018 using GoBoardUtil::PlayIfLegal;
00019 
00020 //----------------------------------------------------------------------------
00021 
00022 namespace {
00023 
00024 const int GOOD_FOR_PREY = 1000;
00025 
00026 const int GOOD_FOR_HUNTER = -1000;
00027 
00028 } // namespace
00029 
00030 //----------------------------------------------------------------------------
00031 
00032 GoLadder::GoLadder()
00033 {
00034 }
00035 
00036 inline bool GoLadder::CheckMoveOverflow() const
00037 {
00038     return (m_bd->MoveNumber() >= m_maxMoveNumber);
00039 }
00040 
00041 void GoLadder::InitMaxMoveNumber()
00042 {
00043     // reserve is the maximum number of moves played before recursion
00044     // 5 is an optimistic bound
00045     const int RESERVE = 5;
00046     m_maxMoveNumber = min(m_bd->MoveNumber() + MAX_LADDER_MOVES,
00047                           GO_MAX_NUM_MOVES - RESERVE);
00048 }
00049 
00050 /** Marks all stones in the block p as part of the prey.
00051     If 'stones' is not 0, then append the stones to the existing list. */
00052 void GoLadder::MarkStonesAsPrey(SgPoint p, SgVector<SgPoint>* stones)
00053 {
00054     SG_ASSERT(m_bd->IsValidPoint(p));
00055     if (m_bd->Occupied(p))
00056     {
00057         for (GoBoard::StoneIterator it(*m_bd, p); it; ++it)
00058         {
00059             SgPoint p = *it;
00060             m_partOfPrey.Include(p);
00061             if (stones)
00062                 stones->PushBack(p);
00063         }
00064     }
00065 }
00066 
00067 /** Filter out captured blocks, blocks not in atari, and blocks not adjacent
00068     to the prey.
00069     The latter are found by checking whether blocks adjacent to the block in
00070     question are the prey or not. Does not return the correct blocks if the
00071     prey has more than three liberties, but in that case, the prey has
00072     escaped anyway. */
00073 void GoLadder::FilterAdjacent(GoPointList& adjBlocks)
00074 {
00075     GoPointList temp;
00076     for (GoPointList::Iterator it(adjBlocks); it; ++it)
00077     {
00078         SgPoint block = *it;
00079         if (m_bd->IsColor(block, m_hunterColor)
00080             && m_bd->InAtari(block)
00081             && BlockIsAdjToPrey(block, 1))
00082             temp.PushBack(block);
00083     }
00084     ReduceToBlocks(temp);
00085     adjBlocks = temp;
00086 }
00087 
00088 bool GoLadder::PointIsAdjToPrey(SgPoint p)
00089 {
00090     return  m_partOfPrey[p - SG_NS]
00091          || m_partOfPrey[p - SG_WE]
00092          || m_partOfPrey[p + SG_WE]
00093          || m_partOfPrey[p + SG_NS];
00094 }
00095 
00096 bool GoLadder::BlockIsAdjToPrey(SgPoint p, int numAdj)
00097 {
00098     SG_ASSERT(m_bd->IsColor(p, m_hunterColor));
00099     for (GoBoard::StoneIterator it(*m_bd, p); it; ++it)
00100         if (PointIsAdjToPrey(*it) && --numAdj == 0)
00101             return true;
00102     return false;
00103 }
00104 
00105 /** Play hunter move and update all the relevant information.
00106     Play at one of the two liberties of the prey. */
00107 int GoLadder::PlayHunterMove(int depth, SgPoint move, SgPoint lib1,
00108                              SgPoint lib2, const GoPointList& adjBlk,
00109                              SgVector<SgPoint>* sequence)
00110 {
00111     SG_ASSERT(move == lib1 || move == lib2);
00112     // TODO: only pass move and otherLib
00113     int result = 0;
00114     if (PlayIfLegal(*m_bd, move, m_hunterColor))
00115     {
00116         // Find new adjacent blocks: only block just played can be new
00117         // in atari.
00118         // But other blocks previously in atari may have gained new liberties
00119         // because the move captured a stone, or the move may have extended a
00120         // block previously in atari.
00121         //   If it was in atari before, and the move doesn't capture
00122         // anything, then the block will still be in atari afterwards - no
00123         // need to check again.
00124         GoPointList newAdj;
00125         if (m_bd->InAtari(move))
00126             newAdj.PushBack(move);
00127         for (GoPointList::Iterator it(adjBlk); it; ++it)
00128         {
00129             SgPoint block = *it;
00130             if (! m_bd->AreInSameBlock(block, move))
00131             {
00132                 if (! m_bd->CapturingMove() || m_bd->InAtari(block))
00133                     newAdj.PushBack(block);
00134             }
00135         }
00136         if (move == lib1)
00137             lib1 = lib2;
00138         result = PreyLadder(depth + 1, lib1, newAdj, sequence);
00139         if (sequence)
00140             sequence->PushBack(move);
00141         m_bd->Undo();
00142     }
00143     else
00144     {
00145         if (sequence)
00146             sequence->Clear();
00147         result = GOOD_FOR_PREY - depth;
00148     }
00149     return result;
00150 }
00151 
00152 /** Play prey move and update all the relevant information.
00153     Extend the prey by playing at its only liberty, or capture a block
00154     adjacent to the prey. */
00155 int GoLadder::PlayPreyMove(int depth, SgPoint move, SgPoint lib1,
00156                            const GoPointList& adjBlk,
00157                            SgVector<SgPoint>* sequence)
00158 {
00159     int result = 0;
00160     GoPointList newAdj(adjBlk);
00161     SgVector<SgPoint> newLib;
00162     SgVector<SgPoint> newStones;
00163     SgVector<SgPoint> neighbors;
00164     if (move == lib1)
00165     {
00166         NeighborsOfColor(*m_bd, move, m_preyColor, &neighbors);
00167         for (SgVectorIterator<SgPoint> iter(neighbors); iter; ++iter)
00168         {
00169             SgPoint block = *iter;
00170             if (! m_partOfPrey[block])
00171             {
00172                 MarkStonesAsPrey(block, &newStones);
00173                 GoPointList temp =
00174                     GoBoardUtil::AdjacentStones(*m_bd, block);
00175                 newAdj.PushBackList(temp);
00176                 for (GoBoard::LibertyIterator it(*m_bd, block); it; ++it)
00177                     newLib.Include(*it);
00178             }
00179         }
00180         m_partOfPrey.Include(move);
00181     }
00182     if (PlayIfLegal(*m_bd, move, m_preyColor))
00183     {
00184         if (move == lib1)
00185         {
00186             NeighborsOfColor(*m_bd, move, SG_EMPTY, &neighbors);
00187             for (SgVectorIterator<SgPoint> iter(newLib); iter; ++iter)
00188             {
00189                 SgPoint point = *iter;
00190                 // Test for Empty is necessary because newLib will include
00191                 // the move just played.
00192                 if (m_bd->IsEmpty(point))
00193                     neighbors.Include(point);
00194             }
00195         }
00196         else
00197         {
00198             neighbors.PushBack(lib1);
00199         }
00200         if (m_bd->CapturingMove())
00201         {   // Add the points at the captured stones that are adjacent to the
00202             // prey to the liberties, at least if exactly one stone captured.
00203             for (GoPointList::Iterator it(m_bd->CapturedStones()); it;
00204                  ++it)
00205             {
00206                 SgPoint stone = *it;
00207                 if (PointIsAdjToPrey(stone))
00208                     neighbors.Include(stone);
00209             }
00210         }
00211         SG_ASSERT(! neighbors.IsEmpty());
00212         lib1 = neighbors[0];
00213         SG_ASSERT(m_bd->IsEmpty(lib1));
00214         SgArrayList<SgPoint,4> temp =
00215             NeighborsOfColor(*m_bd, move, m_hunterColor);
00216         newAdj.PushBackList(temp);
00217         FilterAdjacent(newAdj);
00218 
00219         if (neighbors.Length() == 1)
00220             result = HunterLadder(depth + 1, lib1, newAdj, sequence);
00221         else if (neighbors.Length() == 2)
00222         {
00223             SgPoint lib2 = neighbors[1];
00224             SG_ASSERT(m_bd->IsEmpty(lib2));
00225             result = HunterLadder(depth + 1, lib1, lib2, newAdj, sequence);
00226         } 
00227         else // 3 <= numLib
00228         {
00229             if (sequence)
00230                 sequence->Clear();
00231             result = GOOD_FOR_PREY - (depth + 1);
00232         }
00233         if (sequence)
00234             sequence->PushBack(move);
00235         m_bd->Undo();
00236     }
00237     else
00238     {
00239         if (sequence)
00240             sequence->Clear();
00241         result = GOOD_FOR_HUNTER + depth;
00242     }
00243     m_partOfPrey.Exclude(move);
00244     m_partOfPrey.Exclude(newStones);
00245 
00246     return result;
00247 }
00248 
00249 int GoLadder::PreyLadder(int depth, SgPoint lib1,
00250                          const GoPointList& adjBlk,
00251                          SgVector<SgPoint>* sequence)
00252 {
00253     if (CheckMoveOverflow())
00254         return GOOD_FOR_PREY;
00255     int result = 0;
00256     for (GoPointList::Iterator iter(adjBlk); iter; ++iter)
00257     {
00258         SgPoint block = *iter;
00259         SgPoint move = *GoBoard::LibertyIterator(*m_bd, block);
00260         if (BlockIsAdjToPrey(block, 2))
00261         {
00262             if (sequence)
00263                 sequence->SetTo(move);
00264             result = GOOD_FOR_PREY - depth;
00265         }
00266         else if (move != lib1)
00267         {
00268             result = PlayPreyMove(depth, move, lib1, adjBlk, sequence);
00269         }
00270         if (0 < result)
00271             break;
00272     }
00273     if (result <= 0)
00274     {
00275         if (sequence)
00276         {
00277             SgVector<SgPoint> seq2;
00278             int result2 = PlayPreyMove(depth, lib1, lib1, adjBlk, &seq2);
00279             if (result < result2 || result == 0)
00280             {
00281                 result = result2;
00282                 sequence->SwapWith(&seq2);
00283             }
00284         }
00285         else
00286         {
00287             int result2 = PlayPreyMove(depth, lib1, lib1, adjBlk, 0);
00288             if (result < result2 || result == 0)
00289                 result = result2;
00290         }
00291     }
00292     return result;
00293 }
00294 
00295 int GoLadder::HunterLadder(int depth, SgPoint lib1, const GoPointList& adjBlk,
00296                            SgVector<SgPoint>* sequence)
00297 {
00298     SG_UNUSED(adjBlk);
00299     if (CheckMoveOverflow())
00300         return GOOD_FOR_PREY;
00301     if (sequence)
00302         sequence->SetTo(lib1);
00303     // TODO: should probably test for IsSnapback here, but don't have
00304     // the right information available.
00305     return GOOD_FOR_HUNTER + depth;
00306 }
00307 
00308 int GoLadder::HunterLadder(int depth, SgPoint lib1, SgPoint lib2, 
00309                            const GoPointList& adjBlk,
00310                            SgVector<SgPoint>* sequence)
00311 {
00312     if (CheckMoveOverflow())
00313         return GOOD_FOR_PREY;
00314     int result = 0;
00315     if (m_bd->NumEmptyNeighbors(lib1) < m_bd->NumEmptyNeighbors(lib2))
00316     {
00317         swap(lib1, lib2);
00318     }
00319     if (m_bd->NumEmptyNeighbors(lib1) == 3
00320         && ! SgPointUtil::AreAdjacent(lib1, lib2))
00321     {
00322         // If not playing at lib1, then prey will play at lib1 and
00323         // get three liberties; little to update in this case.
00324         m_bd->Play(lib1, m_hunterColor);
00325         result = PreyLadder(depth + 1, lib2, adjBlk, sequence);
00326         if (sequence)
00327             sequence->PushBack(lib1);
00328         m_bd->Undo();
00329     }
00330     else
00331     {
00332         // Two liberties, hunter to play, but not standard case.
00333         if (! adjBlk.IsEmpty()
00334             && *GoBoard::LibertyIterator(*m_bd, adjBlk[0]) == lib2)
00335         {
00336             swap(lib1, lib2); // protect hunter blocks in atari
00337         }
00338         result = PlayHunterMove(depth, lib1, lib1, lib2,
00339                                 adjBlk, sequence);
00340         if (0 <= result) // escaped
00341         {
00342             if (sequence)
00343             {
00344                 SgVector<SgPoint> seq2;
00345                 int result2 = PlayHunterMove(depth, lib2, lib1, lib2,
00346                                              adjBlk, &seq2);
00347                 if (result2 < result)
00348                 {   result = result2;
00349                     sequence->SwapWith(&seq2);
00350                 }
00351             }
00352             else
00353             {
00354                 int result2 = PlayHunterMove(depth, lib2, lib1, lib2,
00355                                              adjBlk, 0);
00356                 if (result2 < result)
00357                     result = result2;
00358             }
00359         }
00360     }
00361     return result;
00362 }
00363 
00364 void GoLadder::ReduceToBlocks(GoPointList& stones)
00365 {
00366     // Single block is frequent case, don't compute block.
00367     if (stones.IsEmpty())
00368         ; // nothing to do
00369     else if (stones.Length() <= 1)
00370     {
00371         if (m_bd->IsEmpty(stones[0]))
00372             stones.Clear();
00373     }
00374     else
00375     {
00376         GoPointList visited;
00377         // TODO: create SgMarker member in GoLadder and use it for visited
00378         // points
00379         GoPointList result;
00380         for (GoPointList::Iterator it(stones); it; ++it)
00381         {
00382             SgPoint stone = *it;
00383             if (m_bd->Occupied(stone) && ! visited.Contains(stone))
00384             {
00385                 result.PushBack(stone);
00386                 for (GoBoard::StoneIterator it(*m_bd, stone); it; ++it)
00387                     visited.PushBack(*it);
00388             }
00389         }
00390         stones = result;
00391     }
00392 }
00393 
00394 /** Main ladder routine */
00395 int GoLadder::Ladder(const GoBoard& bd, SgPoint prey, SgBlackWhite toPlay,
00396                      SgVector<SgPoint>* sequence, bool twoLibIsEscape)
00397 {
00398     GoModBoard modBoard(bd);
00399     m_bd = &modBoard.Board();
00400     InitMaxMoveNumber();
00401     if (sequence)
00402         sequence->Clear();
00403     if (! m_bd->Occupied(prey))
00404         return 0;
00405     if (CheckMoveOverflow())
00406         return GOOD_FOR_PREY;
00407     int result = 0;
00408     m_preyColor = m_bd->GetStone(prey);
00409     m_hunterColor = SgOppBW(m_preyColor);
00410     int numLib = m_bd->NumLiberties(prey);
00411     if (2 < numLib)
00412         result = GOOD_FOR_PREY;
00413     else
00414     {
00415         GoBoard::LibertyIterator libit(*m_bd, prey);
00416         SgPoint lib1 = *libit;
00417         m_partOfPrey.Clear();
00418         MarkStonesAsPrey(prey);
00419         GoPointList adjBlk = GoBoardUtil::AdjacentStones(*m_bd, prey);
00420         FilterAdjacent(adjBlk);
00421         if (toPlay == m_preyColor)
00422         {
00423             if (numLib == 1)
00424                 result = PreyLadder(0, lib1, adjBlk, sequence);
00425             else if (twoLibIsEscape) // prey to play, numLib >= 2
00426                 // For example, Explorer cannot treat this case as a ladder,
00427                 // it messes up the logic
00428                 result = GOOD_FOR_PREY;
00429             else
00430             {
00431                 // Prey to play, two liberties. This is usually good, but
00432                 // need to prove that there is some move that really
00433                 //  escapes laddercapture.
00434                 // Try liberties of adjacent blocks with at most two
00435                 // liberties, try lib1 and lib2, and try moves one away
00436                 // from the two liberties.
00437                 // Good example with three blocks that test this case:
00438                 // (;GM[1]SZ[19]FF[3]
00439                 // AB[qa][pa][pb][pd][pc][qe][re][rd][rc][se]
00440                 // AW[pe][pf][qf][qd][qc][rb][qb][sa][sc][rf][rg][sg])
00441                 SgVector<SgPoint> movesToTry;
00442 
00443                 // Liberties of adj. blocks with at most two liberties.
00444                 adjBlk = GoBoardUtil::AdjacentStones(*m_bd, prey);
00445                 ReduceToBlocks(adjBlk);
00446                 for (GoPointList::Iterator iterAdj(adjBlk); iterAdj;
00447                      ++iterAdj)
00448                 {
00449                     SgPoint block = *iterAdj;
00450                     SG_ASSERT(m_bd->IsColor(block, m_hunterColor));
00451                     SG_ASSERT(BlockIsAdjToPrey(block, 1));
00452                     if (m_bd->NumLiberties(block) <= 2)
00453                         for (GoBoard::LibertyIterator it(*m_bd, block); it;
00454                              ++it)
00455                             movesToTry.PushBack(*it);
00456                 }
00457 
00458                 // Liberties of blocks.
00459                 ++libit;
00460                 SgPoint lib2 = *libit;
00461                 movesToTry.PushBack(lib1);
00462                 movesToTry.PushBack(lib2);
00463 
00464                 // Moves one away from liberties.
00465                 SgVector<SgPoint> neighbors;
00466                 NeighborsOfColor(*m_bd, lib1, SG_EMPTY, &neighbors);
00467                 movesToTry.Concat(&neighbors);
00468                 NeighborsOfColor(*m_bd, lib2, SG_EMPTY, &neighbors);
00469                 movesToTry.Concat(&neighbors);
00470 
00471                 // Try whether any of these moves lead to escape.
00472                 for (SgVectorIterator<SgPoint> it(movesToTry); it; ++it)
00473                 {
00474                     if (PlayIfLegal(*m_bd, *it, m_preyColor))
00475                     {
00476                         if (Ladder(bd, prey, m_hunterColor, 0, twoLibIsEscape)
00477                             > 0)
00478                         {
00479                             if (sequence)
00480                                 sequence->PushBack(*it); 
00481                             result = GOOD_FOR_PREY;
00482                         }
00483                         m_bd->Undo();
00484                     }
00485                     if (result != 0)
00486                         break;
00487                 }
00488 
00489                 // If none of those moves worked, prey can't escape.
00490                 // This is a bit pessimistic, there may be other moves
00491                 // that do lead to escape (e.g. approach moves), but
00492                 // ladder algorithm doesn't know about those.
00493                 if (result == 0)
00494                     result = GOOD_FOR_HUNTER;
00495             }
00496         }
00497         else
00498         {
00499             if (IsSnapback(prey))
00500                 result = GOOD_FOR_PREY;
00501             else
00502             {
00503                 ++libit;
00504                 if (libit) // two liberties
00505                     result = HunterLadder(0, lib1, *libit, adjBlk, sequence);
00506                 else // one liberty
00507                     result = HunterLadder(0, lib1, adjBlk, sequence);
00508             }
00509         }
00510     }
00511     if (sequence)
00512         sequence->Reverse(); // built as a stack, with first move at end.
00513     return result;
00514 }
00515 
00516 /** Check whether the block at 'prey' is caught in a snapback.
00517     Snapback means that it can be captured, but it's only a single stone, and
00518     the prey can capture right back. */
00519 bool GoLadder::IsSnapback(SgPoint prey)
00520 {
00521     bool isSnapback = false;
00522     if (m_bd->IsSingleStone(prey) && m_bd->InAtari(prey))
00523     {
00524         SgPoint liberty = *GoBoard::LibertyIterator(*m_bd, prey);
00525         if (PlayIfLegal(*m_bd, liberty, SgOppBW(m_bd->GetStone(prey))))
00526         {
00527             isSnapback = (m_bd->InAtari(liberty)
00528                           && ! m_bd->IsSingleStone(liberty));
00529             m_bd->Undo();
00530         }
00531     }
00532     return isSnapback;
00533 }
00534 
00535 //----------------------------------------------------------------------------
00536 
00537 bool GoLadderUtil::Ladder(const GoBoard& bd, SgPoint prey,
00538                           SgBlackWhite toPlay, bool twoLibIsEscape,
00539                           SgVector<SgPoint>* sequence)
00540 {
00541     SG_ASSERT(bd.IsValidPoint(prey));
00542     SG_ASSERT(bd.Occupied(prey));
00543     // AR: from Martin: for an unsettled block with 2 liberties, it
00544     // immediately says it can escape, but does not return a move.
00545     // Sequence is empty.  So I have to special case this and look for
00546     // moves that escape from ladder myself.
00547     // ---> need to tell Martin if I find this
00548 #ifndef NDEBUG
00549     SgHashCode oldHash = bd.GetHashCode();
00550 #endif
00551     GoLadder ladder;
00552     int result = ladder.Ladder(bd, prey, toPlay, sequence, twoLibIsEscape);
00553 #ifndef NDEBUG
00554     // Make sure Ladder didn't change the board position.
00555     SG_ASSERT(oldHash == bd.GetHashCode());
00556 #endif
00557     SG_ASSERT(result != 0);
00558     return (result < 0);
00559 }
00560 
00561 GoLadderStatus GoLadderUtil::LadderStatus(const GoBoard& bd, SgPoint prey,
00562                                           bool twoLibIsEscape,
00563                                           SgPoint* toCapture,
00564                                           SgPoint* toEscape)
00565 {
00566     SG_ASSERT(bd.IsValidPoint(prey));
00567     SG_ASSERT(bd.Occupied(prey));
00568 #ifndef NDEBUG
00569     SgHashCode oldHash = bd.GetHashCode();
00570 #endif
00571     // Unsettled only if can capture when hunter plays first, and can escape
00572     // if prey plays first.
00573     GoLadder ladder;
00574     SgBlackWhite preyColor = bd.GetStone(prey);
00575     SgVector<SgPoint> captureSequence;
00576     GoLadderStatus status = GO_LADDER_ESCAPED;
00577     if (ladder.Ladder(bd, prey, SgOppBW(preyColor), &captureSequence,
00578                       twoLibIsEscape) < 0)
00579     {
00580         SgVector<SgPoint> escapeSequence;
00581         if (ladder.Ladder(bd, prey, preyColor, &escapeSequence,
00582                           twoLibIsEscape) < 0)
00583             status = GO_LADDER_CAPTURED;
00584         else
00585         {
00586             status = GO_LADDER_UNSETTLED;
00587             // Unsettled = ladder depends on who plays first, so there must
00588             // be a move that can be played.
00589             SG_ASSERT(captureSequence.NonEmpty());
00590             // escapeSequence can be empty in 2 libs, prey to play case
00591             SG_ASSERT(twoLibIsEscape || escapeSequence.NonEmpty());
00592             if (toCapture)
00593                 *toCapture = captureSequence.Front();
00594             if (toEscape)
00595                 *toEscape = escapeSequence.IsEmpty() ? SG_PASS :
00596                                                        escapeSequence.Front();
00597         }
00598     }
00599 #ifndef NDEBUG
00600     // Make sure Ladder didn't change the board position.
00601     SG_ASSERT(oldHash == bd.GetHashCode());
00602 #endif
00603     return status;
00604 }
00605 
00606 bool GoLadderUtil::IsProtectedLiberty(const GoBoard& bd, SgPoint liberty,
00607                                       SgBlackWhite color)
00608 {
00609     bool ignoreLadder;
00610     bool ignoreKo;
00611     return IsProtectedLiberty(bd, liberty, color, ignoreLadder, ignoreKo,
00612                               true);
00613 }
00614 
00615 bool GoLadderUtil::IsProtectedLiberty(const GoBoard& bd1, SgPoint liberty,
00616                                       SgBlackWhite col, bool& byLadder,
00617                                       bool& isKoCut, bool tryLadder)
00618 {
00619     byLadder = false;
00620     isKoCut = false;
00621     GoModBoard mbd(bd1);
00622     GoBoard& bd = mbd.Board();
00623 
00624     const SgBlackWhite toPlay = bd1.ToPlay();
00625     bd.SetToPlay(SgOppBW(col));
00626     bool isProtected;
00627     if (! PlayIfLegal(bd, liberty))
00628         isProtected = bd.LastMoveInfo(GO_MOVEFLAG_SUICIDE);
00629         // opponent cannot play there
00630     else
00631     {
00632         if (bd.LastMoveInfo(GO_MOVEFLAG_SUICIDE))
00633            isProtected = true;
00634         else
00635         {
00636             if (bd.InAtari(liberty))
00637             {
00638                 if (bd.NumStones(liberty) > 1)
00639                     isProtected = true;
00640                 else
00641                 {
00642                     SgPoint p = bd.TheLiberty(liberty);
00643                     if (PlayIfLegal(bd, p))
00644                     {
00645                         isProtected =    (bd.NumStones(p) != 1)
00646                                       || (bd.NumLiberties(p) != 1);
00647                                       // yes, can re-capture there
00648                         bd.Undo();
00649                     }
00650                     else
00651                         isProtected = false;
00652 
00653                     if (! isProtected)
00654                         isKoCut = true;
00655                 }
00656             }
00657             else if (tryLadder)
00658             {
00659                 isProtected = Ladder(bd, liberty, bd.ToPlay(), true);
00660                 if (isProtected)
00661                     byLadder = true;
00662             }
00663             else // don't try ladder
00664                 isProtected = false;
00665         }
00666         bd.Undo();
00667     }
00668     bd.SetToPlay(toPlay);
00669     return isProtected;
00670 }
00671 
00672 /** try to escape/capture prey block
00673     Possible return values:
00674     - SG_PASS if already escaped/captured
00675     - the point to play
00676     - SG_NULLMOVE in case of failure */
00677 SgPoint GoLadderUtil::TryLadder(const GoBoard& bd, SgPoint prey,
00678                                 SgBlackWhite firstPlayer)
00679 {
00680     SgVector<SgPoint> sequence;
00681     bool isCaptured = Ladder(bd, prey, firstPlayer, true, &sequence);
00682     // if move is same color as prey, we want to escape
00683     // else we want to capture.
00684     SgPoint p;
00685     if (isCaptured != (firstPlayer == bd.GetStone(prey)))
00686         p = sequence.IsEmpty() ? SG_PASS : sequence.Front();
00687     else
00688         p = SG_NULLMOVE;
00689     return p;
00690 }
00691 
00692 //----------------------------------------------------------------------------
00693 


Sun Mar 13 2011 Doxygen 1.7.1