Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

BenzeneHtpEngine.cpp

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 /** @file BenzeneHtpEngine.cpp
00003  */
00004 //----------------------------------------------------------------------------
00005 
00006 #include "SgSystem.h"
00007 #include "SgGameReader.h"
00008 
00009 #include <cmath>
00010 #include <functional>
00011 #include "BoardUtils.hpp"
00012 #include "BitsetIterator.hpp"
00013 #include "GraphUtils.hpp"
00014 #include "HexProgram.hpp"
00015 #include "HexSgUtil.hpp"
00016 #include "BenzeneHtpEngine.hpp"
00017 #include "Resistance.hpp"
00018 #include "DfsSolver.hpp"
00019 #include "SwapCheck.hpp"
00020 #include "TwoDistance.hpp"
00021 #include "VCSet.hpp"
00022 #include "VCUtils.hpp"
00023 
00024 using namespace benzene;
00025 
00026 //----------------------------------------------------------------------------
00027 
00028 BenzeneHtpEngine::BenzeneHtpEngine(int boardsize)
00029     : HexHtpEngine(boardsize),
00030       m_pe(m_board.Width(), m_board.Height()),
00031       m_se(m_board.Width(), m_board.Height()),
00032       m_dfsSolver(),
00033       m_dfpnSolver(),
00034       m_dfsHashTable(new DfsHashTable(20)), // TT with 2^20 entries
00035       m_dfpnHashTable(new DfpnHashTable(21)), // TT with 2^21 entries
00036       m_dfsDB(0),
00037       m_dfpnDB(0),
00038       m_dfsParam(),
00039       m_dfpnParam(),
00040       m_dfsPositions(m_dfsHashTable, m_dfsDB, m_dfsParam),
00041       m_dfpnPositions(m_dfpnHashTable, m_dfpnDB, m_dfpnParam),
00042       m_playerEnvCommands(m_pe),
00043       m_solverEnvCommands(m_se),
00044       m_vcCommands(m_game, m_pe),
00045       m_dfsSolverCommands(m_game, m_se, m_dfsSolver, m_dfsHashTable, m_dfsDB,
00046                           m_dfsPositions),
00047       m_dfpnSolverCommands(m_game, m_se, m_dfpnSolver, m_dfpnHashTable,
00048                            m_dfpnDB, m_dfpnPositions),
00049       m_useParallelSolver(false)
00050 {
00051     RegisterCmd("benzene-license", &BenzeneHtpEngine::CmdLicense);
00052 
00053     RegisterCmd("get_absorb_group", &BenzeneHtpEngine::CmdGetAbsorbGroup);
00054 
00055     RegisterCmd("handbook-add", &BenzeneHtpEngine::CmdHandbookAdd);
00056 
00057     RegisterCmd("compute-inferior", &BenzeneHtpEngine::CmdComputeInferior);
00058     RegisterCmd("compute-fillin", &BenzeneHtpEngine::CmdComputeFillin);
00059     RegisterCmd("compute-vulnerable", &BenzeneHtpEngine::CmdComputeVulnerable);
00060     RegisterCmd("compute-reversible", &BenzeneHtpEngine::CmdComputeReversible);
00061     RegisterCmd("compute-dominated", &BenzeneHtpEngine::CmdComputeDominated);
00062     RegisterCmd("compute-dominated-cell",
00063                 &BenzeneHtpEngine::CmdComputeDominatedOnCell);
00064     RegisterCmd("find-comb-decomp", &BenzeneHtpEngine::CmdFindCombDecomp);
00065     RegisterCmd("find-split-decomp", &BenzeneHtpEngine::CmdFindSplitDecomp);
00066     RegisterCmd("encode-pattern", &BenzeneHtpEngine::CmdEncodePattern);
00067 
00068     m_playerEnvCommands.Register(*this, "player");
00069     m_solverEnvCommands.Register(*this, "solver");
00070     m_vcCommands.Register(*this);
00071     m_dfsSolverCommands.Register(*this);
00072     m_dfpnSolverCommands.Register(*this);
00073 
00074     RegisterCmd("eval-twod", &BenzeneHtpEngine::CmdEvalTwoDist);
00075     RegisterCmd("eval-resist", &BenzeneHtpEngine::CmdEvalResist);
00076     RegisterCmd("eval-resist-delta", &BenzeneHtpEngine::CmdEvalResistDelta);
00077     RegisterCmd("eval-influence", &BenzeneHtpEngine::CmdEvalInfluence);
00078 
00079     RegisterCmd("misc-debug", &BenzeneHtpEngine::CmdMiscDebug);
00080 }
00081 
00082 BenzeneHtpEngine::~BenzeneHtpEngine()
00083 {
00084 }
00085 
00086 //----------------------------------------------------------------------------
00087 
00088 void BenzeneHtpEngine::RegisterCmd(const std::string& name,
00089                                GtpCallback<BenzeneHtpEngine>::Method method)
00090 {
00091     Register(name, new GtpCallback<BenzeneHtpEngine>(this, method));
00092 }
00093 
00094 void BenzeneHtpEngine::NewGame(int width, int height)
00095 {
00096     HexHtpEngine::NewGame(width, height);
00097 
00098     m_pe.NewGame(width, height);
00099     m_se.NewGame(width, height);
00100 }
00101 
00102 ////////////////////////////////////////////////////////////////////////
00103 // Commands
00104 ////////////////////////////////////////////////////////////////////////
00105 
00106 /** Displays usage license. */
00107 void BenzeneHtpEngine::CmdLicense(HtpCommand& cmd)
00108 {
00109     cmd << 
00110         HexProgram::Get().getName() << " " <<
00111         HexProgram::Get().getVersion() << " " <<
00112         HexProgram::Get().getDate() << "\n"
00113         "Copyright (C) 2010 by the authors of the Benzene project.\n"
00114         "See http://benzene.sourceforge.net for information about benzene.\n"
00115         "Benzene comes with NO WARRANTY to the extent permitted by law.\n"
00116         "This program is free software; you can redistribute it and/or\n"
00117         "modify it under the terms of the GNU Lesser General Public License\n"
00118         "as published by the Free Software Foundation - version 3. For more\n"
00119 "information about these matters, see the files COPYING and COPYING.LESSER.\n";
00120 }
00121 
00122 /** Returns the set of stones this stone is part of. */
00123 void BenzeneHtpEngine::CmdGetAbsorbGroup(HtpCommand& cmd)
00124 {
00125     cmd.CheckNuArg(1);
00126     HexPoint cell = HtpUtil::MoveArg(cmd, 0);
00127     if (m_game.Board().GetColor(cell) == EMPTY)
00128         return;
00129 
00130     Groups groups;
00131     GroupBuilder::Build(m_game.Board(), groups);
00132 
00133     const Group& group = groups.GetGroup(cell);
00134     cmd << group.Captain();
00135     for (BitsetIterator p(group.Members()); p; ++p) 
00136         if (*p != group.Captain()) 
00137             cmd << ' ' << *p;
00138 }
00139 
00140 //----------------------------------------------------------------------------
00141 
00142 /** Pulls moves out of the game for given color and appends them to
00143     the given handbook file. Skips the first move (ie, the move from
00144     the empty board). Performs no duplicate checking.
00145     Usage: 
00146       handbook-add [handbook.txt] [sgf file] [color] [max move #] 
00147 */
00148 void BenzeneHtpEngine::CmdHandbookAdd(HtpCommand& cmd)
00149 {
00150     cmd.CheckNuArg(4);
00151     std::string bookfilename = cmd.Arg(0);
00152     std::string sgffilename = cmd.Arg(1);
00153     HexColor colorToSave = HtpUtil::ColorArg(cmd, 2);
00154     int maxMove = cmd.IntArg(3, 0);
00155     
00156     std::ifstream sgffile(sgffilename.c_str());
00157     if (!sgffile)
00158         throw HtpFailure() << "cannot load sgf";
00159 
00160     SgGameReader sgreader(sgffile, 11);
00161     SgNode* root = sgreader.ReadGame(); 
00162     if (root == 0)
00163         throw HtpFailure() << "cannot load file";
00164     sgreader.PrintWarnings(std::cerr);
00165 
00166     if (HexSgUtil::NodeHasSetupInfo(root)) 
00167         throw HtpFailure() << "Root has setup info!";
00168 
00169     int size = root->GetIntProp(SG_PROP_SIZE);
00170     if (size != m_game.Board().Width() || 
00171         size != m_game.Board().Height())
00172         throw HtpFailure() << "Sgf boardsize does not match board";
00173 
00174     StoneBoard brd(m_game.Board());
00175     HexColor color = FIRST_TO_PLAY;
00176     PointSequence responses;
00177     std::vector<hash_t> hashes;
00178     SgNode* cur = root;
00179     for (int moveNum = 0; moveNum < maxMove;) 
00180     {
00181         cur = cur->NodeInDirection(SgNode::NEXT);
00182         if (!cur) 
00183             break;
00184 
00185         if (HexSgUtil::NodeHasSetupInfo(cur)) 
00186             throw HtpFailure() << "Node has setup info";
00187 
00188         // SgGameReader does not support reading "resign" moves from
00189         // an sgf, so any such node will have no move. This should not
00190         // be treated as an error if it is the last node in the game.
00191         // This isn't exact, but close enough.
00192         if (!cur->HasNodeMove() && !cur->HasSon())
00193             break;
00194 
00195         // If node does not have a move and is *not* the last node in
00196         // the game, then this sgf should not be passed in here.
00197         if (!cur->HasNodeMove()) 
00198             throw HtpFailure() << "Node has no move";
00199 
00200         HexColor sgfColor = HexSgUtil::SgColorToHexColor(cur->NodePlayer());
00201         HexPoint sgfPoint = HexSgUtil::SgPointToHexPoint(cur->NodeMove(), 
00202                                                          brd.Height());
00203         if (color != sgfColor)
00204             throw HtpFailure() << "Unexpected color to move";
00205 
00206         if (moveNum && color == colorToSave)
00207         {
00208             hashes.push_back(brd.Hash());
00209             responses.push_back(sgfPoint);
00210         }
00211         brd.PlayMove(color, sgfPoint);
00212         color = !color;
00213         ++moveNum;
00214     }
00215     HexAssert(hashes.size() == responses.size());
00216  
00217     std::ofstream out(bookfilename.c_str(), std::ios_base::app);
00218     for (std::size_t i = 0 ; i < hashes.size(); ++i)
00219         out << HashUtil::toString(hashes[i]) << ' ' << responses[i] << '\n';
00220     out.close();
00221 }
00222 
00223 //----------------------------------------------------------------------
00224 
00225 /** Outputs inferior cell info for current state.
00226     Usage: "compute-inferior [color]"
00227  */
00228 void BenzeneHtpEngine::CmdComputeInferior(HtpCommand& cmd)
00229 {
00230     cmd.CheckNuArg(1);
00231     HexColor color = HtpUtil::ColorArg(cmd, 0);
00232     HexBoard& brd = m_pe.SyncBoard(m_game.Board());
00233     brd.GetPatternState().Update();
00234     GroupBuilder::Build(brd.GetPosition(), brd.GetGroups());
00235     InferiorCells inf;
00236     m_pe.ice.ComputeInferiorCells(color, brd.GetGroups(), 
00237                                   brd.GetPatternState(), inf);
00238     cmd << inf.GuiOutput();
00239     cmd << '\n';
00240 }
00241 
00242 /** Computes fillin for the given board. Color argument affects order
00243     for computing vulnerable/presimplicial pairs. */
00244 void BenzeneHtpEngine::CmdComputeFillin(HtpCommand& cmd)
00245 {
00246     cmd.CheckNuArg(1);
00247     HexColor color = HtpUtil::ColorArg(cmd, 0);
00248     HexBoard& brd = m_pe.SyncBoard(m_game.Board());
00249     brd.GetPatternState().Update();
00250     GroupBuilder::Build(brd.GetPosition(), brd.GetGroups());
00251     InferiorCells inf;
00252     m_pe.ice.ComputeFillin(color, brd.GetGroups(), brd.GetPatternState(), inf);
00253     inf.ClearVulnerable();
00254     cmd << inf.GuiOutput();
00255     cmd << '\n';
00256 }
00257 
00258 /** Computes vulnerable cells on the current board for the given color. */
00259 void BenzeneHtpEngine::CmdComputeVulnerable(HtpCommand& cmd)
00260 {
00261     cmd.CheckNuArg(1);
00262     HexColor col = HtpUtil::ColorArg(cmd, 0);
00263     HexBoard& brd = m_pe.SyncBoard(m_game.Board());
00264     brd.GetPatternState().Update();
00265     GroupBuilder::Build(brd.GetPosition(), brd.GetGroups());
00266     InferiorCells inf;
00267     m_pe.ice.FindVulnerable(brd.GetPatternState(), col, 
00268                             brd.GetPosition().GetEmpty(), inf);
00269     cmd << inf.GuiOutput();
00270     cmd << '\n';
00271 }
00272 
00273 /** Computes reversible cells on the current board for the given color. */
00274 void BenzeneHtpEngine::CmdComputeReversible(HtpCommand& cmd)
00275 {
00276     cmd.CheckNuArg(1);
00277     HexColor col = HtpUtil::ColorArg(cmd, 0);
00278     HexBoard& brd = m_pe.SyncBoard(m_game.Board());
00279     brd.GetPatternState().Update();
00280     GroupBuilder::Build(brd.GetPosition(), brd.GetGroups());
00281     InferiorCells inf;
00282     m_pe.ice.FindReversible(brd.GetPatternState(), col, 
00283                             brd.GetPosition().GetEmpty(), inf);
00284     cmd << inf.GuiOutput();
00285     cmd << '\n';
00286 }
00287 
00288 /** Computes dominated cells on the current board for the given color. */
00289 void BenzeneHtpEngine::CmdComputeDominated(HtpCommand& cmd)
00290 {
00291     cmd.CheckNuArg(1);
00292     HexColor col = HtpUtil::ColorArg(cmd, 0);
00293     HexBoard& brd = m_pe.SyncBoard(m_game.Board());
00294     brd.GetPatternState().Update();
00295     GroupBuilder::Build(brd.GetPosition(), brd.GetGroups());
00296     InferiorCells inf;
00297     m_pe.ice.FindDominated(brd.GetPatternState(), col, 
00298                            brd.GetPosition().GetEmpty(), inf);
00299     cmd << inf.GuiOutput();
00300     cmd << '\n';
00301 }
00302 
00303 void BenzeneHtpEngine::CmdComputeDominatedOnCell(HtpCommand& cmd)
00304 {
00305     cmd.CheckNuArg(2);
00306     HexColor col = HtpUtil::ColorArg(cmd, 0);
00307     HexPoint cell = HtpUtil::MoveArg(cmd, 1);
00308     HexBoard& brd = m_pe.SyncBoard(m_game.Board());
00309     if (m_game.Board().GetColor(cell) != EMPTY)
00310         return;
00311     brd.GetPatternState().Update();
00312     PatternHits hits;
00313     m_pe.ice.FindDominatedOnCell(brd.GetPatternState(), col, 
00314                                  cell, hits);
00315     for (std::size_t i=0; i<hits.size(); ++i)
00316         cmd << " " << hits[i].pattern()->getName();
00317     cmd << '\n';
00318 }
00319 
00320 /** Tries to find a combinatorial decomposition of the board state.
00321     Outputs cells in the vc if there is a decomposition.
00322     Usage: 'find-comb-decomp [color]'
00323 */
00324 void BenzeneHtpEngine::CmdFindCombDecomp(HtpCommand& cmd)
00325 {
00326     cmd.CheckNuArg(1);
00327     HexColor color = HtpUtil::ColorArg(cmd, 0);
00328     HexBoard& brd = m_pe.SyncBoard(m_game.Board());
00329     // Turn of decomps in the board, then call ComputeAll(). Otherwise
00330     // decomps will be found and filled-in by ComputeAll().
00331     bool useDecomps = brd.UseDecompositions();
00332     brd.SetUseDecompositions(false);
00333     brd.ComputeAll(BLACK);
00334     brd.SetUseDecompositions(useDecomps);
00335     bitset_t capturedVC;
00336     if (BoardUtils::FindCombinatorialDecomposition(brd, color, capturedVC)) 
00337         cmd << HexPointUtil::ToString(capturedVC);
00338 }
00339 
00340 /** Tries to find a group that crowds both opponent edges. Outputs
00341     group that crowds both edges if one exists.  
00342     Usage: 'find-split-decomp [color]'
00343 
00344     FIXME: Dump inferior cell info as well? It's hard to see what's
00345     actually going on if it is not displayed.
00346 */
00347 void BenzeneHtpEngine::CmdFindSplitDecomp(HtpCommand& cmd)
00348 {
00349     cmd.CheckNuArg(1);
00350     HexColor color = HtpUtil::ColorArg(cmd, 0);
00351     HexBoard& brd = m_pe.SyncBoard(m_game.Board());
00352     brd.ComputeAll(BLACK);
00353     HexPoint group;
00354     if (BoardUtils::FindSplittingDecomposition(brd, color, group))
00355         cmd << group;
00356 }
00357 
00358 /** Outputs pattern in encoded form. 
00359     Takes a list of cells, the first cell being the center of the
00360     pattern (that is not actually in the pattern).
00361     FIXME: clean this up!
00362 */
00363 void BenzeneHtpEngine::CmdEncodePattern(HtpCommand& cmd)
00364 {
00365     HexAssert(cmd.NuArg() > 0);
00366 
00367     // Build direction offset look-up matrix.
00368     int xoffset[Pattern::NUM_SLICES][32];
00369     int yoffset[Pattern::NUM_SLICES][32];
00370     for (int s=0; s<Pattern::NUM_SLICES; s++)
00371     {
00372         int fwd = s;
00373         int lft = (s + 2) % NUM_DIRECTIONS;
00374         int x1 = HexPointUtil::DeltaX(fwd);
00375         int y1 = HexPointUtil::DeltaY(fwd);
00376         for (int i=1, g=0; i<=Pattern::MAX_EXTENSION; i++)
00377         {
00378             int x2 = x1;
00379             int y2 = y1;
00380             for (int j=0; j<i; j++)
00381             {
00382                 xoffset[s][g] = x2;
00383                 yoffset[s][g] = y2;
00384                 x2 += HexPointUtil::DeltaX(lft);
00385                 y2 += HexPointUtil::DeltaY(lft);
00386                 g++;
00387             }
00388             x1 += HexPointUtil::DeltaX(fwd);
00389             y1 += HexPointUtil::DeltaY(fwd);
00390         }
00391     }
00392 
00393     int pattOut[Pattern::NUM_SLICES * 5];
00394     memset(pattOut, 0, sizeof(pattOut));
00395     StoneBoard brd(m_game.Board());
00396     HexPoint center = HtpUtil::MoveArg(cmd, 0);
00397     LogInfo() << "Center of pattern: " << center << '\n' << "Includes: ";
00398     int x1, y1, x2, y2;
00399     HexPointUtil::pointToCoords(center, x1, y1);
00400     std::size_t i = 1;
00401     while (i < cmd.NuArg())
00402     {
00403         HexPoint p = HtpUtil::MoveArg(cmd, i++);
00404         HexPointUtil::pointToCoords(p, x2, y2);
00405         x2 = x2 - x1;
00406         y2 = y2 - y1;
00407         int sliceNo;
00408         if (y2 > 0)
00409         {
00410             if ((x2 + y2) < 0)          // Point is in bottom of 4th slice
00411                 sliceNo = 3;
00412             else if ((x2 < 0))          // Point is in 5th slice
00413                 sliceNo = 4;
00414             else                        // point is in 6th slice
00415                 sliceNo = 5;
00416         }
00417         else
00418         {
00419             if ((x2 + y2) > 0)          // Point is in 1st slice
00420                 sliceNo = 0;
00421             else if (x2 > 0)            // Point is in 2nd slice
00422                 sliceNo = 1;
00423             else if (x2 < 0 && y2 == 0) // Point is in upper part of 4th slice
00424                 sliceNo = 3;
00425             else                        // Point is in 3rd slice
00426                 sliceNo = 2;
00427         }
00428         int j = 0;
00429         while (j < 32 && (xoffset[sliceNo][j] != x2 ||
00430                           yoffset[sliceNo][j] != y2))
00431             j++;
00432         HexAssert(j != 32);
00433         pattOut[sliceNo*5] += (1 << j);
00434 
00435         if (brd.IsBlack(p))
00436             pattOut[(sliceNo*5) + 1] += (1 << j);
00437         else if (brd.IsWhite(p))
00438             pattOut[(sliceNo*5) + 2] += (1 << j);
00439         LogInfo() << p << ":" << brd.GetColor(p) << ", ";
00440     }
00441     LogInfo() << '\n';
00442     
00443     std::string encPattStr = "d:";
00444 
00445     for (int k = 0; k < Pattern::NUM_SLICES; k++)
00446     {
00447         for (int l = 0; l < 4; l++)
00448         {
00449             std::stringstream out; //FIXME: Isn't there a better way??
00450            out << (pattOut[(k*5) + l]) << ",";
00451            encPattStr.append(out.str());
00452         }
00453            std::stringstream out;
00454            out << (pattOut[(k*5) + 4]) << ";";
00455            encPattStr.append(out.str());
00456     }
00457     LogInfo() << encPattStr << '\n';
00458 }
00459 
00460 //----------------------------------------------------------------------------
00461 // Evaluation commands
00462 //----------------------------------------------------------------------------
00463 
00464 void BenzeneHtpEngine::CmdEvalTwoDist(HtpCommand& cmd)
00465 {
00466     cmd.CheckNuArg(1);
00467     HexColor color = HtpUtil::ColorArg(cmd, 0);
00468 
00469     HexBoard& brd = m_pe.SyncBoard(m_game.Board());
00470     brd.ComputeAll(color);
00471     TwoDistance twod(TwoDistance::ADJACENT);
00472     twod.Evaluate(brd);
00473 
00474     for (BoardIterator it(brd.Const().Interior()); it; ++it) 
00475     {
00476         if (brd.GetPosition().IsOccupied(*it)) continue;
00477         HexEval energy = twod.Score(*it, color);
00478         if (energy == EVAL_INFINITY)
00479             energy = -1;
00480         cmd << " " << *it << " " << energy;
00481     }
00482 }
00483 
00484 void BenzeneHtpEngine::CmdEvalResist(HtpCommand& cmd)
00485 {
00486     cmd.CheckNuArg(1);
00487     HexColor color = HtpUtil::ColorArg(cmd, 0);
00488 
00489     HexBoard& brd = *m_pe.brd;
00490     Resistance resist;
00491     resist.Evaluate(brd);
00492 
00493     cmd << " res " << std::fixed << std::setprecision(3) << resist.Score()
00494         << " rew " << std::fixed << std::setprecision(3) << resist.Resist(WHITE)
00495         << " reb " << std::fixed << std::setprecision(3) << resist.Resist(BLACK);
00496 
00497     for (BoardIterator it(brd.Const().Interior()); it; ++it) {
00498         if (brd.GetPosition().IsOccupied(*it)) continue;
00499         HexEval energy = resist.Score(*it, color);
00500         if (energy == EVAL_INFINITY)
00501             energy = -1;
00502         cmd << " " << *it << " " 
00503             << std::fixed << std::setprecision(3) << energy;
00504     }
00505 }
00506 
00507 void BenzeneHtpEngine::CmdEvalResistDelta(HtpCommand& cmd)
00508 {
00509     cmd.CheckNuArg(1);
00510     HexColor color = HtpUtil::ColorArg(cmd, 0);
00511 
00512     HexBoard& brd = m_pe.SyncBoard(m_game.Board());
00513     brd.ComputeAll(color);
00514     Resistance resist;
00515     resist.Evaluate(brd);
00516     HexEval base = resist.Score();
00517 
00518     cmd << " res " << std::fixed << std::setprecision(3) << base;
00519     for (BitsetIterator it(brd.GetPosition().GetEmpty()); it; ++it) 
00520     {
00521         brd.PlayMove(color, *it);
00522         resist.Evaluate(brd);
00523         HexEval cur = resist.Score();
00524         cmd << " " << *it << " " 
00525             << std::fixed << std::setprecision(3) << (cur - base);
00526         brd.UndoMove();
00527     }
00528 }
00529 
00530 void BenzeneHtpEngine::CmdEvalInfluence(HtpCommand& cmd)
00531 {
00532     cmd.CheckNuArg(1);
00533     HexColor color = HtpUtil::ColorArg(cmd, 0);
00534 
00535     HexBoard& brd = m_pe.SyncBoard(m_game.Board());
00536     brd.ComputeAll(color);
00537 
00538     // Pre-compute edge adjacencies
00539     const Groups& groups = brd.GetGroups();
00540     bitset_t northNbs 
00541         = VCSetUtil::ConnectedTo(brd.Cons(BLACK), groups, NORTH, VC::FULL);
00542     bitset_t southNbs 
00543         = VCSetUtil::ConnectedTo(brd.Cons(BLACK), groups, SOUTH, VC::FULL);
00544     bitset_t eastNbs 
00545         = VCSetUtil::ConnectedTo(brd.Cons(WHITE), groups, EAST, VC::FULL);
00546     bitset_t westNbs 
00547         = VCSetUtil::ConnectedTo(brd.Cons(WHITE), groups, WEST, VC::FULL);
00548 
00549     for (BoardIterator it(brd.Const().Interior()); it; ++it) {
00550         if (brd.GetPosition().IsOccupied(*it)) continue;
00551 
00552     // Compute neighbours, giving over-estimation to edges
00553     bitset_t b1 = VCSetUtil::ConnectedTo(brd.Cons(BLACK), brd.GetGroups(),
00554                                              *it, VC::FULL);
00555     if (b1.test(NORTH)) b1 |= northNbs;
00556     if (b1.test(SOUTH)) b1 |= southNbs;
00557     b1 &= brd.GetPosition().GetEmpty();
00558     bitset_t b2 = VCSetUtil::ConnectedTo(brd.Cons(WHITE), brd.GetGroups(),
00559                                              *it, VC::FULL);
00560     if (b2.test(EAST)) b2 |= eastNbs;
00561     if (b2.test(WEST)) b2 |= westNbs;
00562     b2 &= brd.GetPosition().GetEmpty();
00563 
00564     // Compute ratio of VCs at this cell, and use as measure of influence
00565     double v1 = (double) b1.count();
00566     double v2 = (double) b2.count();
00567     HexAssert(v1+v2 >= 1.0);
00568     double influence;
00569     if (color == BLACK)
00570         influence = v1 / (v1 + v2);
00571     else
00572         influence = v2 / (v1 + v2);
00573 
00574         cmd << " " << *it << " "
00575         << std::fixed << std::setprecision(2) << influence;
00576     }
00577 }
00578 
00579 //----------------------------------------------------------------------------
00580 
00581 void BenzeneHtpEngine::CmdMiscDebug(HtpCommand& cmd)
00582 {
00583 //     cmd.CheckNuArg(1);
00584 //     HexPoint point = HtpUtil::MoveArg(cmd, 0);
00585     cmd << *m_pe.brd << '\n';
00586 }
00587 
00588 //----------------------------------------------------------------------------


6 Jan 2011 Doxygen 1.6.3