Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

ConstBoard.cpp

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 /** @file ConstBoard.cpp
00003  */
00004 //----------------------------------------------------------------------------
00005 
00006 #include "ConstBoard.hpp"
00007 #include "BoardUtils.hpp"
00008 #include "BitsetIterator.hpp"
00009 
00010 using namespace benzene;
00011 
00012 //----------------------------------------------------------------------------
00013 
00014 namespace {
00015 
00016 //----------------------------------------------------------------------------
00017 
00018 int DistanceToEdge(const ConstBoard& brd, HexPoint from, HexPoint edge)
00019 {
00020     HexAssert(HexPointUtil::isEdge(edge));
00021     
00022     if (HexPointUtil::isEdge(from)) 
00023     {
00024     if (from == edge)                             return 0;
00025     if (HexPointUtil::oppositeEdge(from) != edge) return 1;
00026     if (edge == NORTH || edge == SOUTH)           return brd.Height();
00027     return brd.Width();
00028     }
00029     
00030     int r, c;
00031     HexPointUtil::pointToCoords(from, c, r);
00032     switch(edge) 
00033     {
00034     case NORTH: return r + 1;
00035     case SOUTH: return brd.Height() - r;
00036     case EAST:  return brd.Width() - c;
00037     default:    return c + 1;
00038     }
00039 }
00040 
00041 //----------------------------------------------------------------------------
00042 
00043 } // namespace
00044 
00045 //----------------------------------------------------------------------------
00046 
00047 ConstBoard& ConstBoard::Get(int size)
00048 {
00049     return Get(size, size);
00050 }
00051 
00052 ConstBoard& ConstBoard::Get(int width, int height)
00053 {
00054     // Must use a vector of pointers since a vector of ConstBoards could
00055     // resize itself and invalidate all pointers into it.  
00056     // FIXME: how to ensure memory is freed nicely?
00057     static std::vector<ConstBoard*> s_brds;
00058     for (std::size_t i=0; i<s_brds.size(); ++i) {
00059         if (s_brds[i]->Width() == width && s_brds[i]->Height() == height)
00060             return *s_brds[i];
00061     }
00062     s_brds.push_back(new ConstBoard(width, height));
00063     return *s_brds.back();
00064 }
00065 
00066 //----------------------------------------------------------------------------
00067 
00068 ConstBoard::ConstBoard(int size) 
00069     : m_width(size),
00070       m_height(size)
00071 {
00072     HexAssert(1 <= m_width && m_width <= MAX_WIDTH);
00073     HexAssert(1 <= m_height && m_height <= MAX_HEIGHT);
00074     Init();
00075 }
00076 
00077 ConstBoard::ConstBoard(int width, int height)
00078     : m_width(width),
00079       m_height(height)
00080 {
00081     HexAssert(1 <= m_width && m_width <= MAX_WIDTH);
00082     HexAssert(1 <= m_height && m_height <= MAX_HEIGHT);
00083     Init();
00084 }
00085 
00086 ConstBoard::~ConstBoard()
00087 {
00088 }
00089 
00090 //----------------------------------------------------------------------
00091 
00092 bool ConstBoard::Adjacent(HexPoint p1, HexPoint p2) const
00093 {
00094     for (BoardIterator it(Nbs(p1)); it; ++it)
00095         if (*it == p2) 
00096             return true;
00097     return false;
00098 }
00099 
00100 int ConstBoard::Distance(HexPoint x, HexPoint y) const
00101 {
00102     HexAssert(IsValid(x));
00103     HexAssert(IsValid(y));
00104     
00105     if (HexPointUtil::isEdge(y)) 
00106         return DistanceToEdge(*this, x, y);
00107     else if (HexPointUtil::isEdge(x)) 
00108         return DistanceToEdge(*this, y, x);
00109     
00110     int r1, c1, r2, c2;
00111     HexPointUtil::pointToCoords(x, r1, c1);
00112     HexPointUtil::pointToCoords(y, r2, c2);
00113     int dr = r1 - r2;
00114     int dc = c1 - c2;
00115 
00116     return (dr*dc >= 0) 
00117         ? std::abs(dr) + std::abs(dc) 
00118         : std::max(std::abs(dr), std::abs(dc));
00119 }
00120 
00121 //----------------------------------------------------------------------
00122 
00123 void ConstBoard::Init()
00124 {
00125     LogFine() << "--- ConstBoard"
00126               << " (" << Width() << " x " << Height() << ")" << '\n';
00127     ComputePointList();
00128     CreateIterators();
00129     ComputeValid();
00130     ComputeNeighbours();
00131 }
00132 
00133 void ConstBoard::ComputePointList()
00134 {
00135     /** @note There are several pieces of code that rely on the fact
00136         points are visited in the order (a1,b1,...,a2,b2,...,etc)
00137         (StoneBoard::GetBoardID() is one).  Do not change this order
00138         unless you know what you are doing!!.
00139     */
00140     for (int p = FIRST_SPECIAL; p < FIRST_CELL; ++p) 
00141         m_points.push_back(static_cast<HexPoint>(p));
00142 
00143     for (int y = 0; y < Height(); y++)
00144         for (int x = 0; x < Width(); x++)
00145             m_points.push_back(HexPointUtil::coordsToPoint(x, y));
00146 
00147     m_points.push_back(INVALID_POINT);
00148 }
00149 
00150 void ConstBoard::CreateIterators()
00151 {
00152     int p = 0;
00153     while (m_points[p] != FIRST_SPECIAL) p++;
00154     m_all_index = p;
00155 
00156     while (m_points[p] != FIRST_EDGE) p++;
00157     m_locations_index = p;
00158 
00159     while (m_points[p] != FIRST_CELL) p++;
00160     m_cells_index = p;
00161 }
00162 
00163 void ConstBoard::ComputeValid()
00164 {
00165     m_valid.reset();
00166     for (BoardIterator i(AllValid()); i; ++i)
00167         m_valid.set(*i);
00168 
00169     m_locations.reset();
00170     for (BoardIterator i(EdgesAndInterior()); i; ++i)
00171         m_locations.set(*i);
00172 
00173     m_cells.reset();
00174     for (BoardIterator i(Interior()); i; ++i)
00175         m_cells.set(*i);
00176 }
00177 
00178 void ConstBoard::ComputeNeighbours()
00179 {
00180     // Try all directions for interior cells
00181     for (BoardIterator i(Interior()); i; ++i) 
00182     {
00183         int x, y;
00184         HexPoint cur = *i;
00185         HexPointUtil::pointToCoords(cur, x, y);
00186         for (int a = 0; a < NUM_DIRECTIONS; a++) 
00187         {
00188             int fwd = a;
00189             int lft = (a + 2) % NUM_DIRECTIONS;
00190             int x1 = x + HexPointUtil::DeltaX(fwd);
00191             int y1 = y + HexPointUtil::DeltaY(fwd);
00192             for (int r = 1; r <= Pattern::MAX_EXTENSION; r++) 
00193             {
00194                 int x2 = x1;
00195                 int y2 = y1;
00196                 for (int t = 0; t < r; t++) 
00197                 {
00198                     HexPoint p = BoardUtils::CoordsToPoint(*this, x2, y2);
00199                     if (p != INVALID_POINT) 
00200                     {
00201                         // Add p to cur's list and cur to p's list
00202                         // for each radius in [r, MAX_EXTENSION]. 
00203                         for (int v=r; v <= Pattern::MAX_EXTENSION; v++) 
00204                         {
00205                             std::vector<HexPoint>::iterator result;
00206                            
00207                             result = find(m_neighbours[cur][v].begin(), 
00208                                           m_neighbours[cur][v].end(), p);
00209                             if (result == m_neighbours[cur][v].end())
00210                                 m_neighbours[cur][v].push_back(p);
00211                             
00212                             result = find(m_neighbours[p][v].begin(), 
00213                                           m_neighbours[p][v].end(), cur);
00214                             if (result == m_neighbours[p][v].end())
00215                                 m_neighbours[p][v].push_back(cur);
00216                         }
00217                     }
00218                     x2 += HexPointUtil::DeltaX(lft);
00219                     y2 += HexPointUtil::DeltaY(lft);
00220                 }
00221                 x1 += HexPointUtil::DeltaX(fwd);
00222                 y1 += HexPointUtil::DeltaY(fwd);
00223             }
00224         }
00225     }
00226     
00227     /** Add edges to neighbour lists of neighbouring edges.
00228         @bug NORTH is now distance 2 from SOUTH, but won't appear in
00229         the neighbour lists for r >= 2; likewise for EAST/WEST. 
00230     */
00231     for (BoardIterator i(EdgesAndInterior()); i; ++i) 
00232     {
00233     if (!HexPointUtil::isEdge(*i)) 
00234             continue;
00235         for (int r = 1; r <= Pattern::MAX_EXTENSION; r++) 
00236         {
00237         // Edges sharing a corner are distance one apart
00238             m_neighbours[*i][r].push_back(HexPointUtil::leftEdge(*i));
00239             m_neighbours[*i][r].push_back(HexPointUtil::rightEdge(*i));
00240         }
00241     }
00242     // Null terminate the lists.
00243     for (BoardIterator i(EdgesAndInterior()); i; ++i) 
00244         for (int r = 1; r <= Pattern::MAX_EXTENSION; r++) 
00245             m_neighbours[*i][r].push_back(INVALID_POINT);
00246 }
00247 
00248 //----------------------------------------------------------------------------


6 Jan 2011 Doxygen 1.6.3