Knight's Tour Generator
Tourneys and the Fast Generation and Obfuscation of Closed Knight's Tours
BaseBoard.cpp
Go to the documentation of this file.
1 
4 // MIT License
5 //
6 // Copyright (c) 2019 Ian Parberry
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to
10 // deal in the Software without restriction, including without limitation the
11 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12 // sell copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
14 //
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
17 //
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 // IN THE SOFTWARE.
25 
26 #include "BaseBoard.h"
27 
28 #include "Defines.h"
29 #include "Includes.h"
30 #include "Helpers.h"
31 
32 extern MoveDeltas g_vecDeltas;
33 
35 
37 } //constructor
38 
41 
43 } //constructor
44 
48 
50  m_nWidth(w), m_nHeight(h), m_nSize(w*h)
51 {
52  if(!(m_nSize & 1)){ //size must be even
53  m_nMove = new int[m_nSize]; //create move table
54 
55  for(UINT i=0; i<m_nSize; i++) //initialize move table
56  m_nMove[i] = UNUSED;
57  } //if
58 
59  ::srand(timeGetTime());
60  m_cRandom.srand();
61 } //constructor
62 
67 
68 CBaseBoard::CBaseBoard(int move[], UINT w, UINT h):
69  m_nWidth(w), m_nHeight(h), m_nSize(w*h)
70 {
71  if(!(m_nSize & 1)){ //size must be even
72  m_nMove = new int[m_nSize]; //create move table
73 
74  for(UINT i=0; i<m_nSize; i++) //copy move table
75  m_nMove[i] = move[i];
76  } //if
77 } //constructor
78 
80 
82  delete [] m_nMove;
83  delete [] m_nMove2;
84 } //destructor
85 
88 
90  for(UINT i=0; i<m_nSize; i++)
91  m_nMove[i] = UNUSED;
92 
93  delete [] m_nMove2;
94  m_nMove2 = nullptr;
95 } //Clear
96 
101 
103  return 0 <= index && index < (int)m_nSize;
104 } //CellIndexInRange
105 
109 
111  return 0 <= x && x < (int)m_nWidth;
112 } //InRangeX
113 
117 
119  return 0 <= y && y < (int)m_nHeight;
120 } //InRangeY
121 
126 
127 bool CBaseBoard::IsMove(int i, int j){
128  return CellIndexInRange(i) && CellIndexInRange(j) &&
129  (m_nMove[i] == j || m_nMove2[i] == j ||
130  m_nMove[j] == i || m_nMove2[j] == i);
131 } //IsMove
132 
137 
138 bool CBaseBoard::IsKnightMove(int i, int j){
139  const int n = (int)m_nSize;
140 
141  if(0 <= i && i < n && 0 <= j && j < n) //safety check
142  for(MoveDelta delta: g_vecDeltas)
143  if(IsOnBoard(i, delta)){
144  const int x = i%m_nWidth + delta.first;
145  const int y = i/m_nWidth + delta.second;
146 
147  if(j == y*m_nWidth + x)
148  return true;
149  } //if
150 
151  return false;
152 } //IsKnightMove
153 
160 
161 bool CBaseBoard::IsUnused(int index){
162  assert(IsDirected()); //safety
163  return CellIndexInRange(index) && m_nMove[index] == UNUSED;
164 } //IsUnused
165 
173 
174 bool CBaseBoard::IsUnused(int pos, const MoveDelta& d){
175  assert(IsUndirected()); //safety
176  if(!CellIndexInRange(pos))return false;
177 
178  const int x = pos%m_nWidth + d.first; //destination column
179  const int y = pos/m_nWidth + d.second; //destination row
180 
181  return InRangeX(x) && InRangeY(y) && m_nMove[y*m_nWidth + x] == UNUSED;
182 } //IsUnused
183 
189 
190 bool CBaseBoard::IsOnBoard(int pos, const MoveDelta& d){
191  if(!CellIndexInRange(pos))return false;
192 
193  const int x = pos%m_nWidth + d.first; //destination column
194  const int y = pos/m_nWidth + d.second; //destination row
195 
196  return InRangeX(x) && InRangeY(y);
197 } //IsOnBoard
198 
204 
206  assert(IsUndirected()); //safety
207 
208  const int x0 = index%m_nWidth; //cell column
209  const int y0 = index/m_nWidth; //cell row
210 
211  int count = 0; //return value
212 
213  for(MoveDelta delta: g_vecDeltas){
214  const int x = x0 + delta.first; //destination column of move delta
215  const int y = y0 + delta.second; //destination row of move delta
216  const int dest = y*m_nWidth + x; //destination index of move delta
217 
218  if(InRangeX(x) && InRangeY(y) && m_nMove[dest] == UNUSED)
219  count++;
220  } //for
221 
222  return count;
223 } //GetAvailableMoveCount
224 
231 
232 int CBaseBoard::operator[](int index){
233  assert(IsUndirected()); //safety
234  return CellIndexInRange(index)? m_nMove[index]: UNUSED;
235 } //operator[]
236 
239 
241  int prev = 0;
242  int cur = m_nMove[0];
243  UINT count = 1;
244 
245  //now we can begin the tour
246 
247  while(count < m_nSize && CellIndexInRange(cur) && cur != 0){
248  const int dest0 = m_nMove[cur];
249  const int newprev = cur;
250 
251  if(dest0 == prev){
252  if(IsUndirected())return false; //this should never happen
253  cur = m_nMove2[cur];
254  } //if
255 
256  else cur = dest0;
257 
258  prev = newprev;
259  count++;
260  } //while
261 
262  return count == m_nSize && cur == 0;
263 } //IsTour
264 
267 
269  int *count = new int[m_nSize];
270 
271  for(UINT i=0; i<m_nSize; i++)
272  count[i] = 0;
273 
274  //all cells must be used
275 
276  bool bAllCellsUsed = true;
277 
278  if(IsUndirected()){ //board is undirected
279  for(UINT i=0; i<m_nSize && bAllCellsUsed; i++){
280  if(CellIndexInRange(m_nMove[i])){
281  ++count[i];
282  ++count[m_nMove[i]];
283  } //if
284  else bAllCellsUsed = false;
285  } //for
286  } //if
287 
288  else{ //board is directed
289  for(UINT i=0; i<m_nSize && bAllCellsUsed; i++){
290  if(CellIndexInRange(m_nMove[i]))
291  ++count[m_nMove[i]];
292  else bAllCellsUsed = false;
293 
294  if(CellIndexInRange(m_nMove2[i]))
295  ++count[m_nMove2[i]];
296  else bAllCellsUsed = false;
297  } //for
298  } //else
299 
300  if(!bAllCellsUsed)return false;
301 
302  //the degree of the graph must 2
303 
304  bool bDegree2 = true;
305 
306  if(bAllCellsUsed)
307  for(UINT i=0; i<m_nSize; i++)
308  if(count[i] != 2)
309  bDegree2 = false;
310 
311  delete [] count;
312 
313  return bDegree2;
314 } //IsTourney
315 
318 
320  return !IsUndirected();
321 } //IsDirected
322 
326 
328  return m_nMove2 == nullptr;
329 } //IsUndirected
330 
334 
336  if(IsUndirected()){
337  m_nMove2 = new int[m_nSize];
338  for(UINT i=0; i<m_nSize; i++)
339  m_nMove2[i] = UNUSED;
340 
341  for(UINT i=0; i<m_nSize; i++)
342  if(CellIndexInRange(m_nMove[i]))
343  m_nMove2[m_nMove[i]] = i;
344  } //if
345 } //MakeDirected
346 
350 
352  if(IsDirected() && IsTourney()){
353  int* temp = new int[m_nSize];
354 
355  for(UINT i=0; i<m_nSize; i++)
356  temp[i] = UNUSED;
357 
358  for(UINT start=0; start<m_nSize; start++)
359  if(temp[start] == UNUSED){
360 
361  int prev = start;
362  int cur = m_nMove[start];
363 
364  while(CellIndexInRange(cur) && cur != start){
365  temp[prev] = cur;
366 
367  const int dest0 = (m_nMove[cur] == prev)? m_nMove2[cur]: m_nMove[cur];
368  prev = cur;
369  cur = dest0;
370  } //while
371 
372  if(CellIndexInRange(prev) && CellIndexInRange(cur)){
373  temp[prev] = cur;
374  } //if
375  } //if
376 
377  //clean up and exit
378 
379  delete [] m_nMove;
380  m_nMove = temp;
381 
382  delete [] m_nMove2;
383  m_nMove2 = nullptr;
384  } //if
385 } //MakeUndirected
386 
392 
393 int CBaseBoard::GetDest(int i, const MoveDelta& delta){
394  int x = i%m_nWidth + delta.first;
395  int y = i/m_nWidth + delta.second;
396 
397  if(InRangeX(x) && InRangeY(y)) //move stays on board
398  return y*m_nWidth + x;
399  else return UNUSED; //fail
400 } //GetDest
401 
407 
408 int CBaseBoard::GetMoveIndex(int src, int dest){
409  const int dx = dest%m_nWidth - src%m_nWidth;
410  const int dy = dest/m_nWidth - src/m_nWidth;
411 
412  switch(dx){
413  case -2:
414  if(dy == -1)return 3;
415  else if(dy == 1)return 4;
416  break;
417 
418  case -1:
419  if(dy == -2)return 2;
420  else if(dy == 2)return 5;
421  break;
422 
423  case 1:
424  if(dy == -2)return 1;
425  else if(dy == 2)return 6;
426  break;
427 
428  case 2:
429  if(dy == -1)return 0;
430  else if(dy == 1)return 7;
431  break;
432  } //switch
433 
434  return UNUSED; //bother, it's not a knight's move
435 } //GetMoveIndex
436 
442 
443 void CBaseBoard::CopyToSubBoard(CBaseBoard& b, int x0, int y0){
444  assert(b.IsUndirected()); //safety
445 
446  const int w = b.m_nWidth;
447  const int h = b.m_nHeight;
448 
449  for(int bsrcy=0; bsrcy<h; bsrcy++)
450  for(int bsrcx=0; bsrcx<w; bsrcx++){
451  const int bsrc = bsrcy*w + bsrcx;
452  const int bdest = b[bsrc];
453 
454  const int bdestx = bdest%w;
455  const int bdesty = bdest/w;
456 
457  const int srcx = bsrcx + x0;
458  const int srcy = bsrcy + y0;
459 
460  const int destx = bdestx + x0;
461  const int desty = bdesty + y0;
462 
463  const int src = srcy*m_nWidth + srcx;
464  const int dest = desty*m_nWidth + destx;
465 
466  if(IsDirected())
467  InsertDirectedMove(src, dest);
468  else InsertUndirectedMove(src, dest);
469  } //for
470 } //CopyToSubBoard
471 
473 // Move insertion and deletion functions.
474 
475 #pragma region Move insertion and deletion
476 
481 
482 bool CBaseBoard::InsertUndirectedMove(int src, int dest){
483  assert(IsUndirected()); //safety
484 
485  if(m_nMove[src] < 0)
486  m_nMove[src] = dest;
487 
488  else if(m_nMove[dest] < 0)
489  m_nMove[dest] = src;
490 
491  else return false;
492 
493  return true;
494 } //InsertMove
495 
500 
501 bool CBaseBoard::InsertDirectedMove(int src, int dest){
502  assert(IsDirected()); //safety
503 
504  if(m_nMove[src] < 0)
505  m_nMove[src] = dest;
506 
507  else if(m_nMove2[src] < 0)
508  m_nMove2[src] = dest;
509 
510  else return false;
511 
512  if(m_nMove[dest] < 0)
513  m_nMove[dest] = src;
514 
515  else if(m_nMove2[dest] < 0)
516  m_nMove2[dest] = src;
517 
518  else return false;
519 
520  return true;
521 } //InsertDirectedMove
522 
527 
528 bool CBaseBoard::DeleteMove(int src, int dest){
529  //delete move from primary move table
530 
531  if(m_nMove[src] == dest)
532  m_nMove[src] = UNUSED;
533 
534  if(m_nMove[dest] == src)
535  m_nMove[dest] = UNUSED;
536 
537  //delete move from secondary move table
538 
539  if(IsDirected()){
540  if(!IsMove(src, dest))
541  return false;
542 
543  if(m_nMove2[src] == dest)
544  m_nMove2[src] = UNUSED;
545 
546  if(m_nMove2[dest] == src)
547  m_nMove2[dest] = UNUSED;
548  } //if
549 
550  return true;
551 } //DeleteMove
552 
553 #pragma endregion Move insertion and deletion
554 
556 // Save functions.
557 
558 #pragma region Save functions
559 
570 
571 void CBaseBoard::Save(std::string& name){
572  assert(IsUndirected()); //safety
573 
574  char buffer[256];
575  sprintf_s(buffer, "%s.txt", name.c_str());
576 
577  FILE* output = nullptr;
578  fopen_s(&output, buffer, "wt");
579 
580  if(output != nullptr){
581  for(UINT i=0; i<m_nHeight; i++){
582  for(UINT j=0; j<m_nWidth; j++){
583  const int cell = i*m_nWidth + j;
584  fprintf_s(output, "%d", GetMoveIndex(cell, m_nMove[cell]));
585  } //for
586  fprintf_s(output, "\n");
587  } //for
588 
589  fclose(output);
590  } //if
591 } //Save
592 
598 
600  UINT numcycles = 0; //number of cycles seen in tourney
601 
602  for(UINT i=0; i<m_nSize; i++) //for each cell
603  id[i] = UNUSED; //set identifier to indicate "no tourney"
604 
605  for(UINT start=0; start<m_nSize; start++){ //for each start cell
606  if(id[start] == UNUSED){ //if not already in a tourney
607  id[start] = numcycles; //identify as in a new tourney
608 
609  int prev = start; //previous cell
610  int cur = m_nMove[start]; //current cell
611 
612  while(CellIndexInRange(cur) && cur != start){ //while not closed
613  id[cur] = numcycles; //identify each cell in the new cycle
614 
615  const int dest0 = m_nMove[cur]; //dest0 move
616 
617  if(dest0 == prev){ //dest0 move in m_nMoveTable moves us back
618  prev = cur;
619  cur = m_nMove2[cur]; //use m_nMoveTable2 instead
620  } //if
621 
622  else{ //safe to use m_nMoveTable
623  prev = cur;
624  cur = dest0;
625  } //else
626  } //while
627 
628  ++numcycles; //one more cycle seen in tourney
629  } //if
630  } //for
631 
632  return numcycles;
633 } //GetTourneyIds
634 
640 
641 void CBaseBoard::SaveToSVG(std::string& name){
642  assert(IsUndirected()); //safety
643 
644  int* id = new int[m_nSize]; //tourney identifiers
645  const int numcycles = GetTourneyIds(id); //get tourney id for each cell
646 
647  char buffer[256];
648  sprintf_s(buffer, "%s.svg", name.c_str());
649 
650  FILE* output = nullptr;
651  fopen_s(&output, buffer, "wt");
652 
653  if(output != nullptr){
654  const int w = m_nWidth; //shorthand
655  const int h = m_nHeight; //shorthand
656  const int n = m_nSize; //shorthand
657 
658  const float cellsize = 16; //cell size
659  const float spotsize = 2.8f; //spot size
660  const float strokewidth = 1.0f; //default line width
661  const float strokewidth2 = 2.0f; //thick line width
662 
663  const UINT sw = (UINT)std::ceil(w*cellsize); //screen width
664  const UINT sh = (UINT)std::ceil(h*cellsize); //screen height
665 
666  fprintf(output, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); //header
667 
668  //svg tag
669 
670  fprintf(output, "<svg width=\"%u\" height=\"%u\" ", sw + 8, sh + 8);
671  fprintf(output, "viewBox=\"-4 -4 %u %u\" ", sw + 8, sh + 8);
672  fprintf(output, "xmlns=\"http://www.w3.org/2000/svg\">");
673 
674  //style tag
675 
676  fprintf(output, "<style>");
677  fprintf(output, "circle{fill:black;r:%0.1f}", spotsize);
678  fprintf(output, "polyline{fill:none;stroke:black;stroke-width:%0.1f}",
679  strokewidth2);
680  fprintf(output, "line{stroke:black;stroke-width:%0.1f}", strokewidth2);
681  fprintf(output, "</style>");
682 
683  //bounding rectangle
684 
685  fprintf(output, "<rect width=\"%u\" height=\"%u\" ", sw, sh); //rectangle
686  fprintf(output, "style=\"fill:white;stroke:black;stroke-width:%s\"/>",
687  NumString(strokewidth).c_str());
688 
689  //cell boundary lines
690 
691  const std::string bds =
692  "style=\"stroke-width:" + NumString(strokewidth) + "\"";
693  const std::string wstr = NumString(w*cellsize);
694  const std::string hstr = NumString(h*cellsize);
695 
696  for(int i=1; i<h; i++){ //horizontal lines
697  const std::string s = NumString((float)i*cellsize);
698  fprintf(output, "<line x1=\"0\" y1=\"%s\" x2=\"%s\" y2=\"%s\" %s/>",
699  s.c_str(), wstr.c_str(), s.c_str(), bds.c_str());
700  } //for
701 
702  for(int i=1; i<w; i++){ //vertical lines
703  const std::string s = NumString((float)i*cellsize);
704  fprintf(output, "<line x1=\"%s\" y1=\"0\" x2=\"%s\" y2=\"%s\" %s/>",
705  s.c_str(), s.c_str(), hstr.c_str(), bds.c_str());
706  } //for
707 
708  //knight's moves (lines and circles)
709 
710  bool* used = new bool[n]; //whether cell has been used in a cycle
711 
712  for(int i=0; i<n; i++) //mark all cells unused
713  used[i] = false;
714 
715  //Iterate through each cell. If that cell is unused then iterate
716  //through the cells on the cycle that starts there.
717 
718  for(int start=0; start<n; start++) //for each start cell
719  if(!used[start]){ //if not used in a previous cycle
720  std::string polylinetag; //contents of polyline tag for current cycle
721 
722  //pseudorandom color for if there's more than one cycle
723 
724  UINT rgb[3] = {0, 0, 0}; //color for the current cycle
725  m_cRandom.randclr(rgb); //get random color
726  const std::string colorstr = "rgb(" + std::to_string(rgb[0]) + ","
727  + std::to_string(rgb[1]) + "," + std::to_string(rgb[2]) + ")";
728 
729  //if there's more than one cycle, append stroke color to polyline tag
730 
731  if(numcycles > 1)
732  polylinetag += "style=\"stroke:" + colorstr + "\" ";
733 
734  //iterate through cells on this cycle, printing a circle tag of
735  //the correct color at the cell center and appending the center points
736  //to string polylinetag to be printed later
737 
738  polylinetag += "points=\""; //start the points list
739 
740  int cur = start; //current cell
741 
742  do{ //process current cell
743  const float x = (cur%w + 0.5f)*cellsize; //cell x-coordinate
744  const float y = (cur/w + 0.5f)*cellsize; //cell y-coordinate
745 
746  //print tag for circle at center of cell
747 
748  std::string circletag; //contents of circle polylinetag
749 
750  if(numcycles > 1) //append fill color to the circle tag
751  circletag += "style=\"fill:" + colorstr + "\" ";
752 
753  circletag += "cx=\"" + NumString(x) + "\" cy=\"" + NumString(y) + "\"";
754  fprintf(output, "<circle %s/>", circletag.c_str());
755 
756  //append center point to point list for polyline tag and continue
757 
758  polylinetag += NumString(x) + " " + NumString(y) + " ";
759 
760  used[cur] = true; //mark cell used
761  cur = m_nMove[cur]; //advance to next cell
762  }while(cur != start); //exit when we get back to the start
763 
764  //close the cycle by adding the last edge to the polyline tag
765 
766  const float x = (start%w + 0.5f)*cellsize;
767  const float y = (start/w + 0.5f)*cellsize;
768  polylinetag += NumString(x) + " " + NumString(y) + " ";
769 
770  //print the polyline tag to the SVG file after the circle tags
771 
772  fprintf(output, "<polyline %s\"/>", polylinetag.c_str());
773  } //if
774 
775  fprintf(output, "</svg>\n"); //close the svg tag
776 
777  //clean up and exit
778 
779  delete [] used;
780  fclose(output);
781  } //if
782 
783  delete [] id;
784 } //SaveToSVG
785 
786 #pragma endregion Save functions
787 
789 // Reader functions.
790 
793 
795  return m_nWidth;
796 } //GetWidth
797 
800 
802  return m_nHeight;
803 } //GetHeight
804 
807 
809  return m_nSize;
810 } //GetSize
bool InsertDirectedMove(int src, int dest)
Insert a directed move.
Definition: BaseBoard.cpp:501
int GetHeight()
Get height.
Definition: BaseBoard.cpp:801
MoveDeltas g_vecDeltas
Move deltas for all possible knight's moves.
Definition: Helpers.cpp:68
int GetMoveIndex(int src, int dest)
Get move index.
Definition: BaseBoard.cpp:408
bool IsUnused(int index)
Test for unused cell.
Definition: BaseBoard.cpp:161
Base chessboard.
Definition: BaseBoard.h:69
Defines, enumerated types, and typedefs.
bool CellIndexInRange(int index)
Index in range test.
Definition: BaseBoard.cpp:102
bool DeleteMove(int src, int dest)
Delete a move.
Definition: BaseBoard.cpp:528
bool IsDirected()
Directed board test.
Definition: BaseBoard.cpp:319
UINT GetTourneyIds(int *&id)
Get tourney identifier for each cell.
Definition: BaseBoard.cpp:599
int GetDest(int i, const MoveDelta &delta)
Get destination of move.
Definition: BaseBoard.cpp:393
void MakeDirected()
Make into a directed board.
Definition: BaseBoard.cpp:335
#define fprintf_s
fprintf_s for *NIX.
Definition: Helpers.h:36
Useful includes.
bool IsUndirected()
Undirected board test.
Definition: BaseBoard.cpp:327
int GetSize()
Get size.
Definition: BaseBoard.cpp:808
#define sprintf_s
sprintf_s for *NIX.
Definition: Helpers.h:37
UINT m_nSize
Board size in cells.
Definition: BaseBoard.h:75
std::pair< int, int > MoveDelta
Move delta for a knight's move.
Definition: Helpers.h:42
bool IsKnightMove(int i, int j)
Knight's move test.
Definition: BaseBoard.cpp:138
Header for helper functions.
int * m_nMove2
Secondary move table.
Definition: BaseBoard.h:78
bool IsOnBoard(int pos, const MoveDelta &delta)
Move stays on board.
Definition: BaseBoard.cpp:190
std::string NumString(float x)
Make string from number.
Definition: Helpers.cpp:123
void randclr(UINT rgb[3])
Get a random color.
Definition: Random.cpp:97
unsigned int UINT
Abbreviation for unsigned integer.
Definition: Defines.h:84
Header for the base chessboard CBaseBoard.
#define UNUSED
Contents of unused square on the chessboard.
Definition: Defines.h:31
bool InRangeY(int y)
Y coordinate in range test.
Definition: BaseBoard.cpp:118
void Save(std::string &name)
Save board to a text file.
Definition: BaseBoard.cpp:571
bool IsTourney()
Tourney test.
Definition: BaseBoard.cpp:268
int GetAvailableMoveCount(int index)
Get number of moves from a cell.
Definition: BaseBoard.cpp:205
bool IsMove(int i, int j)
Move test.
Definition: BaseBoard.cpp:127
int * m_nMove
Primary move table.
Definition: BaseBoard.h:77
void fopen_s(FILE **stream, const char *name, const char *fmt)
fopen_s for *NIX.
Definition: Helpers.cpp:40
UINT m_nHeight
Board height in cells.
Definition: BaseBoard.h:74
CBaseBoard()
Constructor.
Definition: BaseBoard.cpp:36
void CopyToSubBoard(CBaseBoard &b, int x, int y)
Copy to sub-board.
Definition: BaseBoard.cpp:443
void srand()
Seed the random number generator.
Definition: Random.cpp:39
int operator[](int index)
Get a move from the board.
Definition: BaseBoard.cpp:232
bool IsTour()
Knight's tour test.
Definition: BaseBoard.cpp:240
std::vector< MoveDelta > MoveDeltas
Move deltas for knight's moves.
Definition: Helpers.h:43
~CBaseBoard()
Destructor.
Definition: BaseBoard.cpp:81
void MakeUndirected()
Make into an undirected board.
Definition: BaseBoard.cpp:351
void SaveToSVG(std::string &name)
Save to an SVG file.
Definition: BaseBoard.cpp:641
UINT m_nWidth
Board width in cells.
Definition: BaseBoard.h:73
CRandom m_cRandom
PRNG.
Definition: BaseBoard.h:71
int GetWidth()
Get width.
Definition: BaseBoard.cpp:794
bool InsertUndirectedMove(int src, int dest)
Insert an undirected move.
Definition: BaseBoard.cpp:482
UINT timeGetTime()
Something a little bit like timeGetTime for *NIX.
Definition: Helpers.cpp:52
void Clear()
Clear the board of moves.
Definition: BaseBoard.cpp:89
bool InRangeX(int x)
X coordinate in range test.
Definition: BaseBoard.cpp:110