Knight's Tour Generator
Tourneys and the Fast Generation and Obfuscation of Closed Knight's Tours
Generator.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 "Generator.h"
27 #include "Random.h"
28 #include "Defines.h"
29 #include "Timer.h"
30 #include "Board.h"
31 #include "DivideAndConquer.h"
32 #include "ConcentricBraid.h"
33 #include "FourCover.h"
34 
36 
38 } //constructor
39 
43 
44 CGenerator::CGenerator(int w, int h):
45  m_nWidth(w), m_nHeight(h), m_nSize(w*h){
46 } //constructor
47 
50 
52 } //constructor
53 
55 // Code for Task::Generate
56 
57 #pragma region Task::Generate
58 
65 
66 void CGenerator::Generate(const CTourneyDesc& t, int nThreads){
67  const GeneratorType gentype = t.m_eGenerator;
68  const CycleType cycletype = t.m_eCycle;
69 
70  //deterministic generators
71 
72  if(gentype == GeneratorType::DivideAndConquer){
73  CBoard b(m_nWidth, m_nHeight); //board for the tour
74  CDivideAndConquer().Generate(b, cycletype); //generate it
75  if(t.m_bObfuscate)b.Obfuscate(); //obfuscate if necessary
76 
77  std::string s = MakeFileNameBase(t, b.GetWidth()); //file name
78 
79  b.Save(s); //save to text file
80  b.SaveToSVG(s); //save to SVG file
81  } //if
82 
83  else if(gentype == GeneratorType::ConcentricBraid){
84  CBoard b(m_nWidth, m_nHeight); //board for the tour
85  CConcentricBraid().Generate(b); //generate it
86  if(cycletype == CycleType::TourFromTourney)b.JoinUntilTour(); //make tour
87  if(t.m_bObfuscate)b.Obfuscate(); //obfuscate if necessary
88 
89  std::string s = MakeFileNameBase(t, b.GetWidth()); //save file name
90  b.Save(s); //save to text file
91  b.SaveToSVG(s); //save to SVG file
92  } //if
93 
94  else if(gentype == GeneratorType::FourCover){
95  CBoard b(m_nWidth, m_nHeight); //board for the tour
96  CFourCover().Generate(b); //generate it
97  if(cycletype == CycleType::TourFromTourney)b.JoinUntilTour(); //make tour
98  if(t.m_bObfuscate)b.Obfuscate(); //obfuscate if necessary
99 
100  std::string s = MakeFileNameBase(t, b.GetWidth()); //save file name
101  b.Save(s); //save to text file
102  b.SaveToSVG(s); //save to SVG file
103  } //if
104 
105  //probabilistic generators
106 
107  else{
108  for(int i=0; i<nThreads; i++) //queue up search requests
110 
111  for(int i=0; i<nThreads; i++) //launch the search threads
112  m_vecThreadList.push_back(std::thread((CSearchThread())));
113 
114  //start timing CPU and elapsed time
115 
116  CTimer Timer;
117  Timer.Start();
118  printf("Starting %d theads at: %s", nThreads, Timer.GetCurrentDateAndTime());
119 
120  //wait for all search threads to terminate
121 
122  std::for_each(m_vecThreadList.begin(), m_vecThreadList.end(),
123  std::mem_fn(&std::thread::join));
124 
125  Timer.Finish(); //stop the timer
126  m_vecThreadList.clear(); //clear the thread list for next use
127 
128  //process results of search
129 
130  CSearchResult result; //current search result
131 
132  const int nResults = (int)m_cSearchResult.size();
133 
134  if(nResults == 0)
135  printf("\n**** Error: Search failed, nothing to print.\n");
136 
137  if(m_cSearchResult.pop(result)){ //get current search result
138  CBoard& b = *(result.m_pBoard);
139  std::string s = MakeFileNameBase(result.m_cTourneyDesc, b.GetWidth());
140 
141  b.Save(s); //save tour to text file
142  b.SaveToSVG(s); //save to SVG file
143 
144  delete result.m_pBoard;
145  } //if
146  } //else
147 } //Generate
148 
149 #pragma endregion generation task
150 
152 // Code for Task::Measure
153 
154 #pragma region Task::Measure
155 
164 
165 void CGenerator::Measure(const CTourneyDesc& t, int nThreads, int n){
166  //queue up search requests
167 
168  for(int i=0; i<n; i++){
169  CSearchRequest request(t, m_nWidth, m_nHeight, ::rand());
170  request.m_bDiscard = true; //we're measuring stats, so throw them away
171  m_cSearchRequest.push(request); //submit request
172  } //for
173 
174  //start timing CPU and elapsed time
175 
176  CTimer Timer;
177  Timer.Start();
178 
179  printf("Starting %d theads at: %s", nThreads, Timer.GetCurrentDateAndTime());
180 
181  //launch the search threads
182 
183  for(int i=0; i<nThreads; i++)
184  m_vecThreadList.push_back(std::thread((CSearchThread())));
185 
186  //wait for all search threads to terminate
187 
188  std::for_each(m_vecThreadList.begin(), m_vecThreadList.end(),
189  std::mem_fn(&std::thread::join));
190 
191  Timer.Finish();
192  m_vecThreadList.clear(); //clear the thread list for next use
193 
194  //process the measurements that were made by the threads
195 
196  //you can't iterate through std::queue, so transfer results to an std::vector
197 
198  std::vector<CSearchResult> results; //result list
199 
200  CSearchResult r; //current search result
201 
202  while(m_cSearchResult.pop(r)) //get current search result
203  results.push_back(r);
204 
205  //now process the results
206 
207  double fSingleMove[8] = {0}; //single move count
208  double fRelativeMove[8] = {0}; //relative move count
209 
210  double fSingleMean[8] = {0}; //single move observed mean
211  double fRelativeMean[8] = {0}; //relative move observed mean
212 
213  double fSingleStdev[8] = {0}; //single move standard deviation
214  double fRelativeStdev[8] = {0}; //relative move standard deviation
215 
217 
218  for(CSearchResult r: results)
219  for(int i=0; i<8; i++){
220  fSingleMove[i] += (double)r.m_nSingleMove[i];
221  fRelativeMove[i] += (double)r.m_nRelativeMove[i];
222  } //for
223 
224  for(int i=0; i<8; i++){
225  fSingleMove[i] /= (double)m_nSize;
226  fRelativeMove[i] /= (double)m_nSize;
227  } //for
228 
229  //compute observed mean
230 
231  for(int i=0; i<8; i++){
232  fSingleMean[i] = fSingleMove[i]/(double)n;
233  fRelativeMean[i] = fRelativeMove[i]/(double)n;
234  } //for
235 
236  //compute observed standard deviation
237 
238  const double denom = (double)m_nSize; //denominator
239 
240  for(CSearchResult r: results){
241  for(int i=0; i<8; i++){
242  fSingleStdev[i] += sqr((double)r.m_nSingleMove[i]/denom - fSingleMean[i]);
243  fRelativeStdev[i] += sqr((double)r.m_nRelativeMove[i]/denom - fRelativeMean[i]);
244  } //for
245  } //for
246 
247  if(n > 1){
248  const double denom = (double)n - 1; //denominator for standard deviation
249 
250  for(int i=0; i<8; i++){
251  fSingleStdev[i] = sqrt(fSingleStdev[i]/denom);
252  fRelativeStdev[i] = sqrt(fRelativeStdev[i]/denom);
253  } //for
254  } //if
255 
256  //write mean and standard deviation to a file
257 
258  std::string strFileName = "Stats" + MakeFileNameBase(t, m_nWidth) //file name
259  + "-" + std::to_string(n) + ".txt";
260 
261  FILE* output = fopen(strFileName.c_str(), "wt"); //open file
262 
263  if(output != nullptr){ //success
264  fprintf(output, "Single\n");
265  fprintf(output, "Mean\t"); OutputStat(output, fSingleMean);
266  fprintf(output, "Stdev\t"); OutputStat(output, fSingleStdev);
267  fprintf(output, "\n");
268 
269  fprintf(output, "Relative\n");
270  fprintf(output, "Mean\t"); OutputStat(output, fRelativeMean);
271  fprintf(output, "Stdev\t"); OutputStat(output, fRelativeStdev);
272 
273  fclose(output); //close file
274  } //if
275 } //Measure
276 
281 
282 void CGenerator::OutputStat(FILE* output, double a[8]){
283  assert(output != 0); //safety
284  fprintf(output, "%0.4f", a[0]);
285  for(int i=1; i<8; i++)
286  fprintf(output, "\t%0.4f", a[i]);
287  fprintf(output, "\n");
288 } //OutputStat
289 
290 #pragma endregion Task::Measure
291 
293 // Code for Task::Time
294 
295 #pragma region Task::Time
296 
304 
305 void CGenerator::Time(const CTourneyDesc& t, int nThreads, int n){
306  //queue up search requests
307 
308  for(int i=0; i<n; i++){
309  CSearchRequest request(t, m_nWidth, m_nHeight, ::rand());
310  request.m_bDiscard = true;
311  m_cSearchRequest.push(request);
312  } //for
313 
314  //start timing CPU and elapsed time
315 
316  CTimer Timer;
317  Timer.Start();
318 
319  //launch the search threads
320 
321  for(int i=0; i<nThreads; i++)
322  m_vecThreadList.push_back(std::thread((CSearchThread())));
323 
324  //wait for all search threads to terminate
325 
326  std::for_each(m_vecThreadList.begin(), m_vecThreadList.end(),
327  std::mem_fn(&std::thread::join));
328 
329  m_vecThreadList.clear(); //clear the thread list for next use
330 
331  //append cpu and elapsed time to a file
332 
333  std::string strFileName = "Time" + MakeFileNameBase(t);
334  strFileName += "-" + std::to_string(n) + ".txt";
335 
336  FILE* output = fopen(strFileName.c_str(), "at");
337 
338  if(output != nullptr){
339  OutputTimes(output, Timer.GetCPUTime(), Timer.GetElapsedTime());
340  fclose(output);
341  } //if
342 } //Time
343 
350 
351 void CGenerator::OutputTimes(FILE* output, float fCpu, float fElapsed){
352  assert(output != 0); //safety
353 
354  if(output != nullptr)
355  fprintf(output, "%d\t%0.2f\t%0.2f\n", m_nWidth, fCpu, fElapsed);
356 } //OutputTimes
357 
358 #pragma endregion Task::Time
359 
void OutputTimes(FILE *output, float fCpu, float fElapsed)
Output times.
Definition: Generator.cpp:351
Header for the concentric braided tourney generator CConcentricBraid.
const char * GetCurrentDateAndTime()
Get current time and date.
Definition: Timer.cpp:61
void Generate(CBoard &b)
Generate a concentric braided tourney.
Four-cover tourney generator.
Definition: FourCover.h:38
Defines, enumerated types, and typedefs.
CGenerator()
Default constructor.
Definition: Generator.cpp:37
Header for the divide-and conquer generator CDivideAndConquer.
Search thread.
Definition: SearchThread.h:41
void Generate(CBoard &b, CycleType t, const CRect &rect)
Recursion.
void Time(const CTourneyDesc &t, int nThreads, int n)
Time.
Definition: Generator.cpp:305
void OutputStat(FILE *output, double a[8])
Output a statistic.
Definition: Generator.cpp:282
void Start()
Start timing.
Definition: Timer.cpp:32
Tourney descriptor.
Definition: Structs.h:40
void push(const data &element)
Insert at tail.
Timer for elapsed time and CPU time.
Definition: Timer.h:43
void Generate(const CTourneyDesc &t, int nThreads)
Generate.
Definition: Generator.cpp:66
Header for the tourney and knight's tour generator CGenerator.
Header for the four-cover tourney generator CFourCover.
Search result.
Definition: Structs.h:76
void Generate(CBoard &b)
Generate a four-cover tourney.
Definition: FourCover.cpp:45
void JoinUntilTour()
Join cycles to reduce tourney size.
Definition: Board.cpp:305
UINT64 m_nRelativeMove[8]
Double move count.
Definition: Structs.h:86
static CThreadSafeQueue< CSearchResult > m_cSearchResult
Search result queue.
#define sqr(x)
Squaring function.
Definition: Defines.h:33
Header for the timer CTimer.
size_t size()
Get queue size.
Search request.
Definition: Structs.h:55
float GetCPUTime()
Get CPU time in seconds.
Definition: Timer.cpp:76
void Finish()
Print CPU and elapsed time.
Definition: Timer.cpp:83
bool m_bDiscard
Discard result.
Definition: Structs.h:62
std::vector< std::thread > m_vecThreadList
Thread list for search.
Definition: Generator.h:49
GeneratorType
Generator type.
Definition: Defines.h:47
bool pop(data &element)
Delete from head and return.
Concentric braided tourney generator.
CBoard * m_pBoard
Pointer to chessboard.
Definition: Structs.h:77
Chessboard.
Definition: Board.h:42
GeneratorType m_eGenerator
Generator type.
Definition: Structs.h:41
void Save(std::string &name)
Save board to a text file.
Definition: BaseBoard.cpp:571
float GetElapsedTime()
Get elapsed time in seconds.
Definition: Timer.cpp:68
Header for the pseudo-random number generator CRandom.
int m_nWidth
Board width.
Definition: Generator.h:51
Header for the chessboard CBoard.
CycleType m_eCycle
Cycle type.
Definition: Structs.h:42
Knight's tour and tourney generator.
Definition: Generator.h:47
int m_nHeight
Board height.
Definition: Generator.h:52
Divide-and-conquer knight's tour and tourney generator.
UINT64 m_nSingleMove[8]
Single move count.
Definition: Structs.h:85
int m_nSize
Board size.
Definition: Generator.h:53
std::string MakeFileNameBase(const CTourneyDesc &t, int w)
Make file name base.
Definition: Helpers.cpp:88
void Obfuscate()
Obfuscate function.
Definition: Board.cpp:214
void Measure(const CTourneyDesc &t, int nThreads, int n)
Measure.
Definition: Generator.cpp:165
CTourneyDesc m_cTourneyDesc
Tourney descriptor.
Definition: Structs.h:79
void SaveToSVG(std::string &name)
Save to an SVG file.
Definition: BaseBoard.cpp:641
int GetWidth()
Get width.
Definition: BaseBoard.cpp:794
CycleType
Cycle type.
Definition: Defines.h:58
static CThreadSafeQueue< CSearchRequest > m_cSearchRequest
Search request queue.
bool m_bObfuscate
Whether to obfuscate.
Definition: Structs.h:43