00001
00002
00003
00004
00005
00006 #include "BitsetIterator.hpp"
00007 #include "BoardUtils.hpp"
00008 #include "VCPattern.hpp"
00009 #include "StoneBoard.hpp"
00010
00011 #include <boost/filesystem/path.hpp>
00012
00013 using namespace benzene;
00014
00015
00016
00017
00018 namespace
00019 {
00020
00021
00022 struct BuilderPattern
00023 {
00024 bitset_t black, empty;
00025 HexPoint endpoint;
00026 int height;
00027
00028 BuilderPattern(const bitset_t& b, const bitset_t& em, HexPoint e, int h)
00029 : black(b), empty(em), endpoint(e), height(h)
00030 { };
00031 };
00032
00033
00034
00035 bool ShiftBuilderPattern(BuilderPattern& pat, HexDirection dir,
00036 const StoneBoard& brd)
00037 {
00038 bitset_t black, empty, bad;
00039 HexPoint endpoint = BoardUtils::PointInDir(brd.Const(), pat.endpoint, dir);
00040
00041 if (!BoardUtils::ShiftBitset(brd.Const(), pat.black, dir, black))
00042 return false;
00043 if (!BoardUtils::ShiftBitset(brd.Const(), pat.empty, dir, empty))
00044 return false;
00045 pat = BuilderPattern(black, empty, endpoint, pat.height);
00046 return true;
00047 }
00048
00049
00050
00051
00052 VCPattern RotatePattern(const VCPattern& pat, const StoneBoard& brd)
00053 {
00054 HexPoint endpoint1 = BoardUtils::Rotate(brd.Const(), pat.Endpoint(0));
00055 HexPoint endpoint2 = BoardUtils::Rotate(brd.Const(), pat.Endpoint(1));
00056 bitset_t must = BoardUtils::Rotate(brd.Const(), pat.MustHave());
00057 bitset_t oppt = BoardUtils::Rotate(brd.Const(), pat.NotOpponent());
00058 return VCPattern(endpoint1, endpoint2, must, oppt);
00059 }
00060
00061
00062 VCPattern MirrorPattern(const VCPattern& pat, const StoneBoard& brd)
00063 {
00064 HexPoint endpoint1 = BoardUtils::Mirror(brd.Const(), pat.Endpoint(0));
00065 HexPoint endpoint2 = BoardUtils::Mirror(brd.Const(), pat.Endpoint(1));
00066 bitset_t must = BoardUtils::Mirror(brd.Const(), pat.MustHave());
00067 bitset_t oppt = BoardUtils::Mirror(brd.Const(), pat.NotOpponent());
00068 return VCPattern(endpoint1, endpoint2, must, oppt);
00069 }
00070
00071
00072
00073
00074 HexPoint ReversePoint(HexPoint point, const StoneBoard& brd)
00075 {
00076 if (HexPointUtil::isEdge(point))
00077 return point;
00078
00079 int x, y;
00080 HexPointUtil::pointToCoords(point, x, y);
00081 x = (brd.Width() - 1 - x) + (brd.Height() - 1 - y);
00082 if (x >= brd.Width())
00083 return INVALID_POINT;
00084
00085 return HexPointUtil::coordsToPoint(x, y);
00086 }
00087
00088
00089
00090 bool ReverseBitset(const bitset_t& bs, const StoneBoard& brd, bitset_t& out)
00091 {
00092 out.reset();
00093 for (BitsetIterator p(bs); p; ++p) {
00094 HexPoint rp = ReversePoint(*p, brd);
00095 if (rp == INVALID_POINT) return false;
00096 out.set(rp);
00097 }
00098 return true;
00099 }
00100
00101
00102 bool ReversePattern(VCPattern& pat, const StoneBoard& brd)
00103 {
00104 do {
00105 bitset_t must, oppt, badp;
00106 if (ReverseBitset(pat.MustHave(), brd, must)
00107 && ReverseBitset(pat.NotOpponent(), brd, oppt))
00108 {
00109 HexPoint endpoint1 = ReversePoint(pat.Endpoint(0), brd);
00110 HexPoint endpoint2 = ReversePoint(pat.Endpoint(1), brd);
00111 pat = VCPattern(endpoint1, endpoint2, must, oppt);
00112 return true;
00113 }
00114 } while (pat.ShiftPattern(DIR_EAST, brd));
00115
00116 return false;
00117 }
00118
00119
00120
00121
00122 void ShiftAndAdd(const VCPattern& pat, HexDirection dir,
00123 StoneBoard& brd, std::vector<VCPattern>& out)
00124 {
00125 VCPattern spat(pat);
00126 do {
00127 out.push_back(spat);
00128 } while (spat.ShiftPattern(dir, brd));
00129 }
00130
00131
00132
00133 void RotateAndShift(const VCPattern& pat, StoneBoard& brd,
00134 HexDirection d1, HexDirection d2,
00135 std::vector<VCPattern>& out)
00136 {
00137 ShiftAndAdd(pat, d1, brd, out);
00138 ShiftAndAdd(RotatePattern(pat, brd), d2, brd, out);
00139 }
00140
00141
00142
00143
00144 void ProcessPattern(const VCPattern& pat, StoneBoard& brd,
00145 std::vector<VCPattern> out[BLACK_AND_WHITE])
00146 {
00147 RotateAndShift(pat, brd, DIR_EAST, DIR_WEST, out[BLACK]);
00148 RotateAndShift(MirrorPattern(pat, brd), brd, DIR_SOUTH,
00149 DIR_NORTH, out[WHITE]);
00150
00151 VCPattern rpat(pat);
00152 ReversePattern(rpat, brd);
00153 RotateAndShift(rpat, brd, DIR_WEST, DIR_EAST, out[BLACK]);
00154 RotateAndShift(MirrorPattern(rpat, brd), brd, DIR_NORTH,
00155 DIR_SOUTH, out[WHITE]);
00156 }
00157
00158 }
00159
00160
00161
00162 VCPattern::VCPatternSetMap& VCPattern::GetConstructed(HexColor color)
00163 {
00164 static GlobalData data;
00165 return data.constructed[color];
00166 }
00167
00168 const VCPatternSet&
00169 VCPattern::GetPatterns(int width, int height, HexColor color)
00170 {
00171 std::pair<int, int> key = std::make_pair(width, height);
00172
00173
00174 if (width != height) {
00175 width = 0;
00176 height = 1;
00177 VCPatternSetMap::iterator it = GetConstructed(color).find(key);
00178 if (it == GetConstructed(color).end())
00179 {
00180 VCPatternSet empty;
00181 GetConstructed(BLACK)[key] = empty;
00182 GetConstructed(WHITE)[key] = empty;
00183 }
00184 }
00185 else
00186 {
00187
00188
00189
00190
00191
00192
00193
00194
00195 VCPatternSetMap::iterator it = GetConstructed(color).find(key);
00196 if (it == GetConstructed(color).end())
00197 {
00198 CreatePatterns(width, height);
00199 }
00200 }
00201
00202 return GetConstructed(color)[key];
00203 }
00204
00205 void VCPattern::CreatePatterns(int width, int height)
00206 {
00207 LogFine() << "VCPattern::CreatePatterns("
00208 << width << ", " << height << ")\n";
00209
00210 #ifndef ABS_TOP_SRCDIR
00211 #error "ABS_TOP_SRCDIR not defined!"
00212 #endif
00213
00214 boost::filesystem::path pp = boost::filesystem::path(ABS_TOP_SRCDIR)
00215 / "share" / "vc-patterns.txt";
00216 pp.normalize();
00217 std::string file = pp.native_file_string();
00218 LogFine() << "Loading pattern templates from: '" << file << "'\n";
00219 std::ifstream fin(file.c_str());
00220 if (!fin)
00221 throw BenzeneException("Could not open pattern file!\n");
00222
00223 std::vector<VCPattern> out[BLACK_AND_WHITE];
00224 std::vector<BuilderPattern> start, end;
00225 std::vector<VCPattern> complete;
00226
00227 int numConstructed = 0;
00228 int numComplete = 0;
00229
00230 std::string line;
00231 while (true) {
00232 int patternHeight;
00233 std::string tmp, name, type;
00234 std::vector<std::string> carrier;
00235
00236 std::istringstream is;
00237 if (!getline(fin, line)) break;
00238 if (line == "") break;
00239
00240 is.str(line);
00241 is >> name;
00242 is >> name;
00243 is.clear();
00244
00245 getline(fin, line);
00246 is.str(line);
00247 is >> type;
00248 is >> type;
00249 is.clear();
00250
00251 getline(fin, line);
00252 is.str(line);
00253 is >> tmp;
00254 is >> patternHeight;
00255 is.clear();
00256
00257 while (true) {
00258 getline(fin, line);
00259 if (line == "") break;
00260 carrier.push_back(line);
00261 }
00262 HexAssert(!carrier.empty());
00263 HexAssert(patternHeight == -1 || patternHeight <= (int)carrier.size());
00264
00265
00266 if ((int)carrier.size() > height)
00267 continue;
00268
00269 int row = height-1;
00270 int numcol = -1;
00271 HexPoint endpoint = SOUTH;
00272 bitset_t black, empty;
00273 bool patternFits = true;
00274 for (int i = static_cast<int>(carrier.size() - 1); i >= 0; --i) {
00275 is.clear();
00276 is.str(carrier[i]);
00277
00278 std::string sym;
00279 int col = 0;
00280 while (is >> sym) {
00281 if (col >= width) {
00282 patternFits = false;
00283 break;
00284 }
00285 HexPoint p = HexPointUtil::coordsToPoint(col, row);
00286 switch(sym[0]) {
00287 case '*': empty.set(p); break;
00288 case 'E': endpoint = p; empty.set(p); break;
00289 case 'B': black.set(p); break;
00290 case '.': break;
00291 default: HexAssert(false);
00292 }
00293 col++;
00294 }
00295 if (!patternFits)
00296 break;
00297 if (numcol == -1)
00298 numcol = col;
00299 HexAssert(numcol == col);
00300 row--;
00301 }
00302
00303
00304 if (!patternFits)
00305 continue;
00306
00307 StoneBoard sb(width, height);
00308 sb.StartNewGame();
00309
00310 if (type == "complete") {
00311 numComplete++;
00312 VCPattern pat(endpoint, SOUTH, black, empty);
00313 complete.push_back(pat);
00314 } else if (type == "start") {
00315 if (endpoint == SOUTH)
00316 throw BenzeneException("Start pattern with no endpoint!");
00317 start.push_back(BuilderPattern(black, empty, endpoint,
00318 patternHeight));
00319 } else if (type == "end") {
00320 end.push_back(BuilderPattern(black, empty, endpoint,
00321 patternHeight));
00322 }
00323 }
00324 fin.close();
00325
00326
00327 LogFine() << "Combining start(" << start.size()
00328 << ") and end(" << end.size() << ")...\n";
00329 StoneBoard sb(width, height);
00330 for (std::size_t s=0; s<start.size(); ++s) {
00331 const BuilderPattern& st = start[s];
00332
00333 for (std::size_t e=0; e<end.size(); ++e) {
00334 const BuilderPattern& en = end[e];
00335 if (en.height < st.height) continue;
00336
00337
00338 sb.StartNewGame();
00339 BuilderPattern bp(en);
00340 int col=0;
00341 bool onBoard = true;
00342 while (onBoard) {
00343 if (((bp.empty|bp.black) & (st.empty|st.black)).none()) break;
00344 onBoard = ShiftBuilderPattern(bp, DIR_EAST, sb);
00345 col++;
00346 }
00347
00348
00349 if (!onBoard) continue;
00350
00351 int startCol = col;
00352 while (onBoard) {
00353 bitset_t empty = st.empty | bp.empty;
00354 bitset_t black = st.black | bp.black;
00355
00356 for (int i=startCol; i<col; ++i) {
00357 for (int j=0; j<st.height; ++j) {
00358 HexPoint p
00359 = HexPointUtil::coordsToPoint(i, height-1-j);
00360 empty.set(p);
00361 }
00362 }
00363
00364 VCPattern pat(st.endpoint, bp.endpoint, black, empty);
00365 complete.push_back(pat);
00366 numConstructed++;
00367
00368 onBoard = ShiftBuilderPattern(bp, DIR_EAST, sb);
00369 col++;
00370 }
00371 }
00372 }
00373
00374 LogFine() << "Constructed " << numConstructed << ".\n"
00375 << "Parsed " << numComplete << " complete.\n";
00376
00377
00378 LogFine() << "Translating, rotating, mirroring...\n";
00379 for (std::size_t i=0; i<complete.size(); ++i)
00380 ProcessPattern(complete[i], sb, out);
00381
00382 LogFine() << out[BLACK].size() << " total patterns\n";
00383
00384 GetConstructed(BLACK)[std::make_pair(width, height)] = out[BLACK];
00385 GetConstructed(WHITE)[std::make_pair(width, height)] = out[WHITE];
00386
00387 LogFine() << "Done.\n";
00388 }
00389
00390
00391
00392 VCPattern::VCPattern(HexPoint end1, HexPoint end2, const bitset_t& must_have,
00393 const bitset_t& not_oppt)
00394 : m_must_have(must_have),
00395 m_not_oppt(not_oppt),
00396 m_end1(end1),
00397 m_end2(end2)
00398 {
00399 }
00400
00401 VCPattern::~VCPattern()
00402 {
00403 }
00404
00405
00406
00407 bool VCPattern::Matches(HexColor color, const StoneBoard& brd) const
00408 {
00409 bitset_t my_color = brd.GetColor(color) & brd.Const().GetCells();
00410 bitset_t op_color = brd.GetColor(!color) & brd.Const().GetCells();
00411
00412 return ((m_not_oppt & op_color).none()
00413 && BitsetUtil::IsSubsetOf(m_must_have, my_color));
00414 }
00415
00416
00417
00418 bool VCPattern::ShiftPattern(HexDirection dir, const StoneBoard& brd)
00419 {
00420 bitset_t must, oppt, bad;
00421 if (!BoardUtils::ShiftBitset(brd.Const(), MustHave(), dir, must))
00422 return false;
00423 if (!BoardUtils::ShiftBitset(brd.Const(), NotOpponent(), dir, oppt))
00424 return false;
00425 HexPoint endpoint1 = BoardUtils::PointInDir(brd.Const(), Endpoint(0), dir);
00426 HexPoint endpoint2 = BoardUtils::PointInDir(brd.Const(), Endpoint(1), dir);
00427
00428 m_end1 = endpoint1;
00429 m_end2 = endpoint2;
00430 m_must_have = must;
00431 m_not_oppt = oppt;
00432 return true;
00433 }
00434
00435