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