00001 //---------------------------------------------------------------------------- 00002 /** @file SgBoardConst.cpp 00003 See SgBoardConst.h 00004 */ 00005 //---------------------------------------------------------------------------- 00006 00007 #include "SgSystem.h" 00008 #include "SgBoardConst.h" 00009 00010 #include <algorithm> 00011 #include "SgInit.h" 00012 #include "SgStack.h" 00013 00014 using namespace std; 00015 using SgPointUtil::Pt; 00016 00017 //---------------------------------------------------------------------------- 00018 00019 SgBoardConst::BoardConstImpl::BoardConstImpl(SgGrid size) 00020 : m_size(size), 00021 m_firstBoardPoint(Pt(1, 1)), 00022 m_lastBoardPoint(Pt(size, size)) 00023 { 00024 m_gridToLine.Fill(0); 00025 m_gridToPos.Fill(0); 00026 m_up.Fill(0); 00027 for (SgGrid line = 0; line <= SG_MAX_SIZE / 2; ++line) 00028 m_line[line].Clear(); 00029 00030 // Set up values for points on the board. 00031 m_boardIterEnd = m_boardIter; 00032 SgGrid halfSize = (m_size + 1) / 2; 00033 for (SgGrid row = 1; row <= m_size; ++row) 00034 { 00035 for (SgGrid col = 1; col <= m_size; ++col) 00036 { 00037 SgPoint p = Pt(col, row); 00038 SgGrid lineRow = row > halfSize ? m_size + 1 - row : row; 00039 SgGrid lineCol = col > halfSize ? m_size + 1 - col : col; 00040 SgGrid line = min(lineRow, lineCol); 00041 SgGrid pos = max(lineRow, lineCol); 00042 m_gridToLine[p] = line; 00043 m_gridToPos[p] = pos; 00044 m_line[line - 1].Include(p); 00045 const int MAX_EDGE = m_size > 11 ? 4 : 3; 00046 if (line <= MAX_EDGE) 00047 { 00048 if (pos <= MAX_EDGE + 1) 00049 m_corners.Include(p); 00050 else 00051 m_edges.Include(p); 00052 } 00053 else 00054 m_centers.Include(p); 00055 int nuNb = 0; 00056 if (row > 1) 00057 m_neighbors[p][nuNb++] = Pt(col, row - 1); 00058 if (col > 1) 00059 m_neighbors[p][nuNb++] = Pt(col - 1, row); 00060 if (col < m_size) 00061 m_neighbors[p][nuNb++] = Pt(col + 1, row); 00062 if (row < m_size) 00063 m_neighbors[p][nuNb++] = Pt(col, row + 1); 00064 m_neighbors[p][nuNb] = SG_ENDPOINT; 00065 *(m_boardIterEnd++) = p; 00066 } 00067 } 00068 00069 // Set up direction to point on line above. 00070 for (SgPoint p = 0; p < SG_MAXPOINT; ++p) 00071 { 00072 if (m_gridToLine[p] != 0) 00073 { 00074 SgGrid line = m_gridToLine[p]; 00075 if (m_gridToLine[p - SG_NS] == line + 1) 00076 m_up[p] = -SG_NS; 00077 if (m_gridToLine[p - SG_WE] == line + 1) 00078 m_up[p] = -SG_WE; 00079 if (m_gridToLine[p + SG_WE] == line + 1) 00080 m_up[p] = SG_WE; 00081 if (m_gridToLine[p + SG_NS] == line + 1) 00082 m_up[p] = SG_NS; 00083 00084 // If no line above vertically or horizontally, try diagonally. 00085 if (m_up[p] == 0) 00086 { 00087 if (m_gridToLine[p - SG_NS - SG_WE] == line + 1) 00088 m_up[p] = -SG_NS - SG_WE; 00089 if (m_gridToLine[p - SG_NS + SG_WE] == line + 1) 00090 m_up[p] = -SG_NS + SG_WE; 00091 if (m_gridToLine[p + SG_NS - SG_WE] == line + 1) 00092 m_up[p] = SG_NS - SG_WE; 00093 if (m_gridToLine[p + SG_NS + SG_WE] == line + 1) 00094 m_up[p] = SG_NS + SG_WE; 00095 } 00096 } 00097 } 00098 00099 // Set up direction to the sides, based on Up. Always list clockwise 00100 // direction first. 00101 { 00102 for (int i = 0; i <= 2 * (SG_NS + SG_WE); ++i) 00103 { 00104 m_side[0][i] = 0; 00105 m_side[1][i] = 0; 00106 } 00107 00108 // When Up is towards center, sides are orthogonal to Up. 00109 m_side[0][-SG_NS + (SG_NS + SG_WE)] = -SG_WE; 00110 m_side[1][-SG_NS + (SG_NS + SG_WE)] = +SG_WE; 00111 m_side[0][-SG_WE + (SG_NS + SG_WE)] = +SG_NS; 00112 m_side[1][-SG_WE + (SG_NS + SG_WE)] = -SG_NS; 00113 m_side[0][+SG_WE + (SG_NS + SG_WE)] = -SG_NS; 00114 m_side[1][+SG_WE + (SG_NS + SG_WE)] = +SG_NS; 00115 m_side[0][+SG_NS + (SG_NS + SG_WE)] = +SG_WE; 00116 m_side[1][+SG_NS + (SG_NS + SG_WE)] = -SG_WE; 00117 00118 // When Up is diagonal, sides are along different sides of board. 00119 m_side[0][-SG_NS - SG_WE + (SG_NS + SG_WE)] = -SG_WE; 00120 m_side[1][-SG_NS - SG_WE + (SG_NS + SG_WE)] = -SG_NS; 00121 m_side[0][-SG_NS + SG_WE + (SG_NS + SG_WE)] = -SG_NS; 00122 m_side[1][-SG_NS + SG_WE + (SG_NS + SG_WE)] = +SG_WE; 00123 m_side[0][+SG_NS - SG_WE + (SG_NS + SG_WE)] = +SG_NS; 00124 m_side[1][+SG_NS - SG_WE + (SG_NS + SG_WE)] = -SG_WE; 00125 m_side[0][+SG_NS + SG_WE + (SG_NS + SG_WE)] = +SG_WE; 00126 m_side[1][+SG_NS + SG_WE + (SG_NS + SG_WE)] = +SG_NS; 00127 } 00128 00129 // Terminate board iterator. 00130 *m_boardIterEnd = SG_ENDPOINT; 00131 00132 // Set up line iterators. 00133 { 00134 int lineIndex = 0; 00135 for (SgGrid line = 1; line <= (SG_MAX_SIZE / 2) + 1; ++line) 00136 { 00137 m_lineIterAddress[line-1] = &m_lineIter[lineIndex]; 00138 for (SgPoint p = m_firstBoardPoint; p <= m_lastBoardPoint; ++p) 00139 { 00140 if (m_gridToLine[p] == line) 00141 m_lineIter[lineIndex++] = p; 00142 } 00143 m_lineIter[lineIndex++] = SG_ENDPOINT; 00144 SG_ASSERT(lineIndex 00145 <= SG_MAX_SIZE * SG_MAX_SIZE + (SG_MAX_SIZE / 2) + 1); 00146 } 00147 SG_ASSERT(lineIndex == m_size * m_size + (SG_MAX_SIZE / 2) + 1); 00148 } 00149 00150 // Set up corner iterator. 00151 m_cornerIter[0] = Pt(1, 1); 00152 m_cornerIter[1] = Pt(m_size, 1); 00153 m_cornerIter[2] = Pt(1, m_size); 00154 m_cornerIter[3] = Pt(m_size, m_size); 00155 m_cornerIter[4] = SG_ENDPOINT; 00156 00157 m_sideExtensions = m_line[2 - 1] | m_line[3 - 1] | m_line[4 - 1]; 00158 // LineSet(line) == m_line[line-1], see .h 00159 // exclude diagonals, so that different sides from corner are in different 00160 // sets. 00161 m_sideExtensions.Exclude(Pt(2, 2)); 00162 m_sideExtensions.Exclude(Pt(2, m_size + 1 - 2)); 00163 m_sideExtensions.Exclude(Pt(m_size + 1 - 2, 2)); 00164 m_sideExtensions.Exclude(Pt(m_size + 1 - 2, m_size + 1 - 2)); 00165 if (m_size > 2) 00166 { 00167 m_sideExtensions.Exclude(Pt(3, 3)); 00168 m_sideExtensions.Exclude(Pt(3, m_size + 1 - 3)); 00169 m_sideExtensions.Exclude(Pt(m_size + 1 - 3, 3)); 00170 m_sideExtensions.Exclude(Pt(m_size + 1 - 3, m_size + 1 - 3)); 00171 if (m_size > 3) 00172 { 00173 m_sideExtensions.Exclude(Pt(4, 4)); 00174 m_sideExtensions.Exclude(Pt(4, m_size + 1 - 4)); 00175 m_sideExtensions.Exclude(Pt(m_size + 1 - 4, 4)); 00176 m_sideExtensions.Exclude(Pt(m_size + 1 - 4, m_size + 1 - 4)); 00177 } 00178 } 00179 } 00180 00181 //---------------------------------------------------------------------------- 00182 00183 SgBoardConst::BoardConstImplArray SgBoardConst::s_const; 00184 00185 void SgBoardConst::Create(SgGrid size) 00186 { 00187 SG_ASSERT_GRIDRANGE(size); 00188 if (! s_const[size]) 00189 s_const[size] = 00190 boost::shared_ptr<BoardConstImpl>(new BoardConstImpl(size)); 00191 m_const = s_const[size]; 00192 SG_ASSERT(m_const); 00193 } 00194 00195 SgBoardConst::SgBoardConst(SgGrid size) 00196 { 00197 SG_ASSERT_GRIDRANGE(size); 00198 SgInitCheck(); 00199 Create(size); 00200 } 00201 00202 void SgBoardConst::ChangeSize(SgGrid newSize) 00203 { 00204 SG_ASSERT_GRIDRANGE(newSize); 00205 SG_ASSERT(m_const); 00206 // Don't do anything if called with same size. 00207 SgGrid oldSize = m_const->m_size; 00208 if (newSize != oldSize) 00209 Create(newSize); 00210 } 00211 00212 //---------------------------------------------------------------------------- 00213