From a16d52fca980d40a56fd8d12bb63f5fab723a893 Mon Sep 17 00:00:00 2001 From: mmueller65 Date: Sun, 16 Aug 2015 17:58:24 +0000 Subject: [PATCH] Utility function for distance to stones and GTP command to show distance git-svn-id: svn://svn.code.sf.net/p/fuego/code/trunk@2003 2e953b5c-c64d-0410-be54-f773e93e544c --- go/GoGtpEngine.cpp | 13 ++++++ go/GoGtpEngine.h | 1 + go/GoInfluence.cpp | 86 ++++++++++++++++++++++++++----------- go/GoInfluence.h | 8 ++++ go/test/GoInfluenceTest.cpp | 63 +++++++++++++++++++++++++++ 5 files changed, 145 insertions(+), 26 deletions(-) create mode 100644 go/test/GoInfluenceTest.cpp diff --git a/go/GoGtpEngine.cpp b/go/GoGtpEngine.cpp index 7d83ba83..c129b699 100644 --- a/go/GoGtpEngine.cpp +++ b/go/GoGtpEngine.cpp @@ -18,6 +18,7 @@ #include "GoBoardRestorer.h" #include "GoEyeUtil.h" #include "GoGtpCommandUtil.h" +#include "GoInfluence.h" #include "GoModBoard.h" #include "GoNodeUtil.h" #include "GoPlayer.h" @@ -111,6 +112,7 @@ GoGtpEngine::GoGtpEngine(int fixedBoardSize, const char* programPath, Register("get_komi", &GoGtpEngine::CmdGetKomi, this); Register("gg-undo", &GoGtpEngine::CmdGGUndo, this); Register("go_board", &GoGtpEngine::CmdBoard, this); + Register("go_distance", &GoGtpEngine::CmdDistance, this); Register("go_param", &GoGtpEngine::CmdParam, this); Register("go_param_rules", &GoGtpEngine::CmdParamRules, this); Register("go_player_board", &GoGtpEngine::CmdPlayerBoard, this); @@ -336,6 +338,7 @@ void GoGtpEngine::CmdAnalyzeCommands(GtpCommand& cmd) "sboard/Go Point Numbers/go_point_numbers\n" "none/Go Rules/go_rules %s\n" "plist/All Legal/all_legal %c\n" + "sboard/Go Distance/go_distance %c\n" "string/ShowBoard/showboard\n" "string/CpuTime/cputime\n" "string/Get Komi/get_komi\n" @@ -403,6 +406,16 @@ void GoGtpEngine::CmdClock(GtpCommand& cmd) cmd << '\n' << m_game.Time(); } +void GoGtpEngine::CmdDistance(GtpCommand& cmd) +{ + cmd.CheckNuArg(1); + SgBlackWhite color = GoGtpCommandUtil::BlackWhiteArg(cmd, 0); + SgPointArray distance; + GoInfluence::FindDistanceToStones(Board(), color, distance); + cmd << '\n' << SgWritePointArray(distance, Board().Size()); +} + + /** Compute final score. Computes score only if GoRules::CaptureDead() == true. Otherwise it returns an error. Override this function for players that diff --git a/go/GoGtpEngine.h b/go/GoGtpEngine.h index 68a9fdb6..201f783e 100644 --- a/go/GoGtpEngine.h +++ b/go/GoGtpEngine.h @@ -85,6 +85,7 @@ class GoGtpEngine virtual void CmdBoardSize(GtpCommand&); virtual void CmdClearBoard(GtpCommand&); virtual void CmdClock(GtpCommand&); + virtual void CmdDistance(GtpCommand& cmd); virtual void CmdFinalScore(GtpCommand&); virtual void CmdFixedHandicap(GtpCommand&); virtual void CmdGameOver(GtpCommand&); diff --git a/go/GoInfluence.cpp b/go/GoInfluence.cpp index 2892595f..c3d9eebd 100644 --- a/go/GoInfluence.cpp +++ b/go/GoInfluence.cpp @@ -6,7 +6,9 @@ #include "SgSystem.h" #include "GoInfluence.h" +#include #include "SgNbIterator.h" +#include "SgPointset.h" //---------------------------------------------------------------------------- namespace { @@ -31,11 +33,65 @@ void Spread(const GoBoard& bd, SgPoint p, const SgPointSet& stopPts, } // namespace //---------------------------------------------------------------------------- +void GoInfluence::ComputeInfluence(const GoBoard& bd, + const SgBWSet& stopPts, + SgBWArray >* influence) +{ + const int MAX_INFLUENCE = 64; + for (SgBWIterator cit; cit; ++cit) + { + SgBlackWhite color = *cit; + ((*influence)[color]).Fill(0); + for (GoBoard::Iterator it(bd); it; ++it) + { + SgPoint p(*it); + if (bd.IsColor(p, color)) + Spread(bd, p, stopPts[color], MAX_INFLUENCE, + (*influence)[color]); + } + } +} + +void GoInfluence::FindDistanceToStones(const GoBoard& bd, + SgBlackWhite color, + SgPointArray& distance) +{ + for (GoBoard::Iterator it(bd); it; ++it) + distance[*it] = DISTANCE_INFINITE; + + std::vector queue; + SgMarker marker; + for (SgSetIterator it(bd.All(color)); it; ++it) + { + queue.push_back(*it); + marker.Include(*it); + } + + int d = 0; + while (! queue.empty()) + { + std::vector next; + for(std::vector::const_iterator it = queue.begin(); it != queue.end(); ++it) + { + const SgPoint p = *it; + distance[p] = d; + for (GoNbIterator it2(bd, p); it2; ++it2) + { + const SgPoint nb = *it2; + if (marker.NewMark(nb) && bd.IsEmpty(nb)) + next.push_back(nb); + } + } + ++d; + queue.swap(next); + } +} + void GoInfluence::FindInfluence(const GoBoard& board, - int nuExpand, - int nuShrink, - SgBWSet* influence) -{ + int nuExpand, + int nuShrink, + SgBWSet* influence) +{ SgBWSet result = SgBWSet(board.All(SG_BLACK), board.All(SG_WHITE)); SgBWSet next; const int size = board.Size(); @@ -68,25 +124,3 @@ int GoInfluence::Influence(const GoBoard& board, FindInfluence(board, nuExpand, nuShrink, &result); return result[color].Size(); } - - -void GoInfluence::ComputeInfluence(const GoBoard& bd, - const SgBWSet& stopPts, - SgBWArray >* influence) -{ - const int MAX_INFLUENCE = 64; - for (SgBWIterator cit; cit; ++cit) - { - SgBlackWhite color = *cit; - ((*influence)[color]).Fill(0); - for (GoBoard::Iterator it(bd); it; ++it) - { - SgPoint p(*it); - if (bd.IsColor(p, color)) - Spread(bd, p, stopPts[color], MAX_INFLUENCE, - (*influence)[color]); - } - } -} - - diff --git a/go/GoInfluence.h b/go/GoInfluence.h index aad7e660..d0ef5869 100644 --- a/go/GoInfluence.h +++ b/go/GoInfluence.h @@ -13,6 +13,14 @@ namespace GoInfluence { +const int DISTANCE_INFINITE = 99; + +/** Find Manhattan distance to nearest stone of color. Does not + go through opponent stones. Set distance to DISTANCE_INFINITE if no stone + is reachable. */ +void FindDistanceToStones(const GoBoard& board, SgBlackWhite color, + SgPointArray& distance); + /** Compute influence by nuExpand expansions followed by nuShrink contractions. Starts from the player's stones. diff --git a/go/test/GoInfluenceTest.cpp b/go/test/GoInfluenceTest.cpp new file mode 100644 index 00000000..b320a884 --- /dev/null +++ b/go/test/GoInfluenceTest.cpp @@ -0,0 +1,63 @@ +//---------------------------------------------------------------------------- +/** @file GoInfluenceTest.cpp + Unit tests for GoInfluence. */ +//---------------------------------------------------------------------------- + +#include "SgSystem.h" + +#include +#include "GoInfluence.h" + +#include "GoSetupUtil.h" + +using SgPointUtil::Pt; + +//---------------------------------------------------------------------------- + +namespace { + + //---------------------------------------------------------------------------- + + BOOST_AUTO_TEST_CASE(GoInfluenceTest_Distance_Black) + { + std::string s(". . . .\n" + ". . . .\n" + ". . X .\n" + ". . . .\n"); + int boardSize; + GoSetup setup = GoSetupUtil::CreateSetupFromString(s, boardSize); + GoBoard bd(boardSize, setup); + SgPointArray distance; + GoInfluence::FindDistanceToStones(bd, SG_BLACK, distance); + BOOST_CHECK_EQUAL(distance[Pt(3, 2)], 0); + BOOST_CHECK_EQUAL(distance[Pt(2, 2)], 1); + BOOST_CHECK_EQUAL(distance[Pt(3, 1)], 1); + BOOST_CHECK_EQUAL(distance[Pt(3, 3)], 1); + BOOST_CHECK_EQUAL(distance[Pt(1, 3)], 3); + BOOST_CHECK_EQUAL(distance[Pt(1, 4)], 4); + BOOST_CHECK_EQUAL(distance[Pt(4, 3)], 2); + } + + BOOST_AUTO_TEST_CASE(GoInfluenceTest_Distance_White) + { + std::string s(". . . .\n" + ". . . .\n" + ". . . .\n" + ". . . O\n"); + int boardSize; + GoSetup setup = GoSetupUtil::CreateSetupFromString(s, boardSize); + GoBoard bd(boardSize, setup); + SgPointArray distance; + GoInfluence::FindDistanceToStones(bd, SG_WHITE, distance); + BOOST_CHECK_EQUAL(distance[Pt(4, 1)], 0); + BOOST_CHECK_EQUAL(distance[Pt(4, 2)], 1); + BOOST_CHECK_EQUAL(distance[Pt(3, 1)], 1); + BOOST_CHECK_EQUAL(distance[Pt(3, 2)], 2); + BOOST_CHECK_EQUAL(distance[Pt(1, 3)], 5); + BOOST_CHECK_EQUAL(distance[Pt(1, 4)], 6); + BOOST_CHECK_EQUAL(distance[Pt(4, 3)], 2); + } + + //---------------------------------------------------------------------------- + +} // namespace