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