00001 //---------------------------------------------------------------------------- 00002 /** @file GoGtpCommandUtil.cpp */ 00003 //---------------------------------------------------------------------------- 00004 00005 #include "SgSystem.h" 00006 #include "GoGtpCommandUtil.h" 00007 00008 #include <limits> 00009 #include "GoBoard.h" 00010 #include "GtpEngine.h" 00011 #include "SgDebug.h" 00012 #include "SgPointArray.h" 00013 00014 using namespace std; 00015 using SgPointUtil::Pt; 00016 00017 //---------------------------------------------------------------------------- 00018 00019 namespace { 00020 00021 /** Comparison of gogui-analyze_commands lines for 00022 SortResponseAnalyzeCommands */ 00023 bool LessAnalyzeLabel(const string& line1, const string& line2) 00024 { 00025 // Analyze label is the second entry in the line, separator is '/' 00026 size_t pos1 = line1.find("/"); 00027 size_t pos2 = line2.find("/"); 00028 if (pos1 == string::npos || pos2 == string::npos) 00029 { 00030 // Shouldn't happen in well-formed lines 00031 SG_ASSERT(false); 00032 return true; 00033 } 00034 return (line1.substr(pos1) < line2.substr(pos2)); 00035 } 00036 00037 } // namespace 00038 00039 //---------------------------------------------------------------------------- 00040 00041 SgEmptyBlackWhite GoGtpCommandUtil::EmptyBlackWhiteArg(const GtpCommand& cmd, 00042 std::size_t number) 00043 { 00044 string value = cmd.ArgToLower(number); 00045 if (value == "e" || value == "empty") 00046 return SG_EMPTY; 00047 if (value == "b" || value == "black") 00048 return SG_BLACK; 00049 if (value == "w" || value == "white") 00050 return SG_WHITE; 00051 throw GtpFailure() << "argument " << (number + 1) 00052 << " must be black, white or empty"; 00053 } 00054 00055 SgBlackWhite GoGtpCommandUtil::BlackWhiteArg(const GtpCommand& cmd, 00056 std::size_t number) 00057 { 00058 string value = cmd.ArgToLower(number); 00059 if (value == "b" || value == "black") 00060 return SG_BLACK; 00061 if (value == "w" || value == "white") 00062 return SG_WHITE; 00063 throw GtpFailure() << "argument " << (number + 1) 00064 << " must be black or white"; 00065 } 00066 00067 SgPoint GoGtpCommandUtil::EmptyPointArg(const GtpCommand& cmd, 00068 std::size_t number, 00069 const GoBoard& board) 00070 { 00071 SgPoint point = PointArg(cmd, number, board); 00072 if (board.GetColor(point) != SG_EMPTY) 00073 throw GtpFailure() << "point " << SgWritePoint(point) 00074 << " must be empty"; 00075 return point; 00076 } 00077 00078 SgVector<SgPoint> GoGtpCommandUtil::GetHandicapStones(int size, int n) 00079 { 00080 SgVector<SgPoint> stones; 00081 if (n == 0) 00082 return stones; 00083 // GTP locations are defined up to size 25, but SG_MAX_SIZE could be 00084 // smaller 00085 if (size > SG_MAX_SIZE || size > 25) 00086 throw GtpFailure("no standard handicap locations defined"); 00087 int line1 = -1; 00088 int line2 = -1; 00089 int line3 = -1; 00090 if (size >= 13) 00091 { 00092 line1 = 4; 00093 line3 = size - 3; 00094 } 00095 else if (size >= 7) 00096 { 00097 line1 = 3; 00098 line3 = size - 2; 00099 } 00100 if (size >= 9 && size % 2 != 0) 00101 line2 = size / 2 + 1; 00102 if (line1 < 0 || n == 1 || n > 9 || (n > 4 && line2 < 0)) 00103 throw GtpFailure("no standard handicap locations defined"); 00104 if (n >= 1) 00105 stones.PushBack(Pt(line1, line1)); 00106 if (n >= 2) 00107 stones.PushBack(Pt(line3, line3)); 00108 if (n >= 3) 00109 stones.PushBack(Pt(line1, line3)); 00110 if (n >= 4) 00111 stones.PushBack(Pt(line3, line1)); 00112 if (n >= 5 && n % 2 != 0) 00113 { 00114 stones.PushBack(Pt(line2, line2)); 00115 --n; 00116 } 00117 if (n >= 5) 00118 stones.PushBack(Pt(line1, line2)); 00119 if (n >= 6) 00120 stones.PushBack(Pt(line3, line2)); 00121 if (n >= 7) 00122 stones.PushBack(Pt(line2, line1)); 00123 if (n >= 8) 00124 stones.PushBack(Pt(line2, line3)); 00125 return stones; 00126 } 00127 00128 SgMove GoGtpCommandUtil::MoveArg(const GtpCommand& cmd, std::size_t number, 00129 const GoBoard& board) 00130 { 00131 if (cmd.ArgToLower(number) == "pass") 00132 return SG_PASS; 00133 return PointArg(cmd, number, board); 00134 } 00135 00136 void GoGtpCommandUtil::ParseMultiStoneArgument(GtpCommand& cmd, 00137 const GoBoard& board, 00138 SgBlackWhite& toPlay, 00139 SgBlackWhite& defender, 00140 SgVector<SgPoint>& crucial) 00141 { 00142 toPlay = GoGtpCommandUtil::BlackWhiteArg(cmd, 0); 00143 SgDebug() << "Set " << SgBW(toPlay) << " to play\n"; 00144 SgPoint point = GoGtpCommandUtil::StoneArg(cmd, 1, board); 00145 defender = board.GetColor(point); 00146 SG_ASSERT(defender == SG_BLACK || defender == SG_WHITE); 00147 crucial.PushBack(point); 00148 for (size_t i = 2; i < cmd.NuArg(); ++i) 00149 { 00150 SgPoint p = GoGtpCommandUtil::StoneArg(cmd, i, board); 00151 if (board.GetColor(p) != defender) 00152 throw GtpFailure("Crucial stones must be same color"); 00153 else 00154 crucial.PushBack(p); 00155 } 00156 } 00157 00158 SgPoint GoGtpCommandUtil::PointArg(const GtpCommand& cmd, 00159 const GoBoard& board) 00160 { 00161 cmd.CheckNuArg(1); 00162 return PointArg(cmd, 0, board); 00163 } 00164 00165 SgPoint GoGtpCommandUtil::PointArg(const GtpCommand& cmd, std::size_t number, 00166 const GoBoard& board) 00167 { 00168 string arg = cmd.Arg(number); 00169 istringstream in(arg); 00170 SgPoint p; 00171 in >> SgReadPoint(p); 00172 if (! in) 00173 throw GtpFailure() << "invalid point " << arg; 00174 if (p == SG_PASS) 00175 throw GtpFailure("expected point, not pass"); 00176 if (SgMoveUtil::IsCouponMove(p)) 00177 throw GtpFailure("expected point, not coupon move"); 00178 if (! board.IsValidPoint(p)) 00179 throw GtpFailure() << "point outside board " << arg; 00180 return p; 00181 } 00182 00183 SgVector<SgPoint> GoGtpCommandUtil::PointListArg(const GtpCommand& cmd, 00184 std::size_t number, 00185 const GoBoard& board) 00186 { 00187 SgVector<SgPoint> result; 00188 for (size_t i = number; i < cmd.NuArg(); ++i) 00189 result.PushBack(PointArg(cmd, i, board)); 00190 return result; 00191 } 00192 00193 void GoGtpCommandUtil::RespondNumberArray(GtpCommand& cmd, 00194 const SgPointArray<int>& array, 00195 int scale, const GoBoard& board) 00196 { 00197 SgPointArray<string> result("\"\""); 00198 for (GoBoard::Iterator it(board); it; ++it) 00199 { 00200 SgPoint p(*it); 00201 if (array[p] != numeric_limits<int>::min()) 00202 { 00203 ostringstream out; 00204 out << (array[p] / scale); 00205 result[p] = out.str(); 00206 } 00207 } 00208 cmd << '\n' << SgWritePointArray<string>(result, board.Size()); 00209 } 00210 00211 string GoGtpCommandUtil::SortResponseAnalyzeCommands(const string& response) 00212 { 00213 vector<string> allLines; 00214 istringstream in(response); 00215 string line; 00216 while (getline(in, line)) 00217 allLines.push_back(line); 00218 sort(allLines.begin(), allLines.end(), LessAnalyzeLabel); 00219 ostringstream sortedResponse; 00220 for (vector<string>::const_iterator it = allLines.begin(); 00221 it != allLines.end(); ++it) 00222 sortedResponse << *it << '\n'; 00223 return sortedResponse.str(); 00224 } 00225 00226 SgPoint GoGtpCommandUtil::StoneArg(const GtpCommand& cmd, std::size_t number, 00227 const GoBoard& board) 00228 { 00229 SgPoint point = PointArg(cmd, number, board); 00230 if (board.GetColor(point) == SG_EMPTY) 00231 throw GtpFailure() << "point " << SgWritePoint(point) 00232 << " must be occupied"; 00233 return point; 00234 } 00235 00236 //---------------------------------------------------------------------------- 00237