/** Find global moves that match a playout pattern or set a block into atari. @param[out] pattern @param[out] atari @param[out] empty As a side effect, this function finds all empty points on the board @return @c true if any such moves was found */ bool GoUctDefaultPriorKnowledge::FindGlobalPatternAndAtariMoves( SgPointSet& pattern, SgPointSet& atari, GoPointList& empty) { // Minimum value for pattern gamma to be used. static const float EPSILON = 0.00000000001; const GoBoard& bd = Board(); SG_ASSERT(empty.IsEmpty()); const GoUctPatterns<GoBoard>& patterns = m_policy.GlobalPatterns(); bool result = false; m_maxPatternGamma = -1.f; for (GoBoard::Iterator it(bd); it; ++it) if (bd.IsEmpty(*it)) { empty.PushBack(*it); float gamma = patterns.GetPatternGamma(bd, *it, bd.ToPlay()); if (gamma > EPSILON) { pattern.Include(*it); result = true; m_patternGammas[*it] = gamma; if (gamma > m_maxPatternGamma) m_maxPatternGamma = gamma; } if (SetsAtari(bd, *it)) { atari.Include(*it); result = true; } } return result; }
/** Find global moves that match a playout pattern or set a block into atari. @param[out] pattern @param[out] atari @param[out] empty As a side effect, this function finds all empty points on the board @return @c true if any such moves was found */ bool GoUctDefaultPriorKnowledge::FindGlobalPatternAndAtariMoves( SgPointSet& pattern, SgPointSet& atari, GoPointList& empty) const { SG_ASSERT(empty.IsEmpty()); const GoUctPatterns<GoBoard>& patterns = m_policy.Patterns(); bool result = false; for (GoBoard::Iterator it(m_bd); it; ++it) if (m_bd.IsEmpty(*it)) { empty.PushBack(*it); if (patterns.MatchAny(*it)) { pattern.Include(*it); result = true; } if (SetsAtari(m_bd, *it)) { atari.Include(*it); result = true; } } return result; }
/** Filter out captured blocks, blocks not in atari, and blocks not adjacent to the prey. The latter are found by checking whether blocks adjacent to the block in question are the prey or not. Does not return the correct blocks if the prey has more than three liberties, but in that case, the prey has escaped anyway. */ void GoLadder::FilterAdjacent(GoPointList& adjBlocks) { GoPointList temp; for (GoPointList::Iterator it(adjBlocks); it; ++it) { SgPoint block = *it; if (m_bd->IsColor(block, m_hunterColor) && m_bd->InAtari(block) && BlockIsAdjToPrey(block, 1)) temp.PushBack(block); } ReduceToBlocks(temp); adjBlocks = temp; }
void GoLadder::ReduceToBlocks(GoPointList& stones) { // Single block is frequent case, don't compute block. if (stones.IsEmpty()) ; // nothing to do else if (stones.Length() <= 1) { if (m_bd->IsEmpty(stones[0])) stones.Clear(); } else { GoPointList visited; // TODO: create SgMarker member in GoLadder and use it for visited // points GoPointList result; for (GoPointList::Iterator it(stones); it; ++it) { SgPoint stone = *it; if (m_bd->Occupied(stone) && ! visited.Contains(stone)) { result.PushBack(stone); for (GoBoard::StoneIterator it(*m_bd, stone); it; ++it) visited.PushBack(*it); } } stones = result; } }
/** Play hunter move and update all the relevant information. Play at one of the two liberties of the prey. */ int GoLadder::PlayHunterMove(int depth, SgPoint move, SgPoint lib1, SgPoint lib2, const GoPointList& adjBlk, SgVector<SgPoint>* sequence) { SG_ASSERT(move == lib1 || move == lib2); // TODO: only pass move and otherLib int result = 0; if (PlayIfLegal(*m_bd, move, m_hunterColor)) { // Find new adjacent blocks: only block just played can be new // in atari. // But other blocks previously in atari may have gained new liberties // because the move captured a stone, or the move may have extended a // block previously in atari. // If it was in atari before, and the move doesn't capture // anything, then the block will still be in atari afterwards - no // need to check again. GoPointList newAdj; if (m_bd->InAtari(move)) newAdj.PushBack(move); for (GoPointList::Iterator it(adjBlk); it; ++it) { SgPoint block = *it; if (! m_bd->AreInSameBlock(block, move)) { if (! m_bd->CapturingMove() || m_bd->InAtari(block)) newAdj.PushBack(block); } } if (move == lib1) lib1 = lib2; result = PreyLadder(depth + 1, lib1, newAdj, sequence); if (sequence) sequence->PushBack(move); m_bd->Undo(); } else { if (sequence) sequence->Clear(); result = GOOD_FOR_PREY - depth; } return result; }
int GoLadder::HunterLadder(int depth, SgPoint lib1, SgPoint lib2, const GoPointList& adjBlk, SgVector<SgPoint>* sequence) { if (CheckMoveOverflow()) return GOOD_FOR_PREY; int result = 0; if (m_bd->NumEmptyNeighbors(lib1) < m_bd->NumEmptyNeighbors(lib2)) { swap(lib1, lib2); } if (m_bd->NumEmptyNeighbors(lib1) == 3 && ! SgPointUtil::AreAdjacent(lib1, lib2)) { // If not playing at lib1, then prey will play at lib1 and // get three liberties; little to update in this case. m_bd->Play(lib1, m_hunterColor); result = PreyLadder(depth + 1, lib2, adjBlk, sequence); if (sequence) sequence->PushBack(lib1); m_bd->Undo(); } else { // Two liberties, hunter to play, but not standard case. if (! adjBlk.IsEmpty() && *GoBoard::LibertyIterator(*m_bd, adjBlk[0]) == lib2) { swap(lib1, lib2); // protect hunter blocks in atari } result = PlayHunterMove(depth, lib1, lib1, lib2, adjBlk, sequence); if (0 <= result) // escaped { if (sequence) { SgVector<SgPoint> seq2; int result2 = PlayHunterMove(depth, lib2, lib1, lib2, adjBlk, &seq2); if (result2 < result) { result = result2; sequence->SwapWith(&seq2); } } else { int result2 = PlayHunterMove(depth, lib2, lib1, lib2, adjBlk, 0); if (result2 < result) result = result2; } } } return result; }