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 //----------------------------------------------------------------------------