Update codebase to remove clang warnings (and a couple of legit errors
[typhoon.git] / src / genetic / main.cpp
1 /*\r
2  *      INCLUDES\r
3  */\r
4 \r
5 #include <stdio.h>\r
6 #include <string.h>\r
7 #include <unistd.h>\r
8 #include <stdlib.h>\r
9 #include <signal.h>\r
10 #include <time.h>\r
11 #include <sys/time.h>\r
12 #include <sys/types.h>\r
13 #include <math.h>\r
14 #include <sys/wait.h>\r
15 \r
16 \r
17 /*\r
18  *      GLOBALS\r
19  */\r
20 \r
21 int start_time;\r
22 bool pipe_logging = false;\r
23 int only_opening = -1;\r
24 FILE *pgn_log = NULL;\r
25 FILE *match_log = NULL;\r
26 \r
27 \r
28 \r
29 \r
30 /*\r
31  *      Misc\r
32  */\r
33 \r
34 void strip_newline(char *s)\r
35 {\r
36         int i;\r
37         \r
38         for (i = 0;; ++i)\r
39                 {\r
40                 if (!s[i] || s[i] == '\r' || s[i] == '\n')\r
41                         {\r
42                         s[i] = 0;\r
43                         return;\r
44                         }\r
45                 }\r
46 }\r
47 \r
48 void copy_result(char *to, char *from)\r
49 {\r
50         int i;\r
51         \r
52         for (i = 0; i < strlen(from); ++i)\r
53                 if (from[i] == '0' || from[i] == '1')\r
54                         break;\r
55         strcpy(to, &from[i]);\r
56         for (i = 0; i < strlen(to); ++i)\r
57                 if (to[i] == '}')\r
58                         break;\r
59         to[i + 1] = 0;\r
60 }\r
61 \r
62 \r
63 \r
64 \r
65 /*\r
66  *      MyLock\r
67  */\r
68 \r
69 #include <pthread.h>\r
70 #include <semaphore.h>\r
71 \r
72 class MyLock\r
73 {\r
74 public:\r
75         MyLock();\r
76         void get();\r
77         void release();\r
78 \r
79 private:\r
80         pthread_mutex_t the_lock;\r
81 };\r
82 \r
83 MyLock::MyLock()\r
84 {\r
85         pthread_mutex_init(&the_lock, NULL);\r
86 }\r
87 \r
88 void MyLock::get()\r
89 {\r
90         for (;;)\r
91                 {\r
92                 if (pthread_mutex_lock(&the_lock) == 0)  // EBUSY??\r
93                         break;\r
94                 usleep(1);\r
95                 }\r
96 }\r
97 \r
98 void MyLock::release()\r
99 {\r
100         pthread_mutex_unlock(&the_lock);\r
101 }\r
102 \r
103 MyLock glock;\r
104 \r
105 \r
106 \r
107 \r
108 /*\r
109  *      Settings\r
110  */\r
111 \r
112 class Settings\r
113 {\r
114 public:\r
115         Settings() { count = 0; };\r
116         bool read(char *filename);\r
117         char * get(char *name);\r
118 \r
119 private:\r
120         char map[20][2][1000];\r
121         int count;\r
122 };\r
123 \r
124 Settings settings;\r
125 \r
126 bool Settings::read(char *filename)\r
127 {\r
128         FILE *f;\r
129         char line[1000];\r
130         char var[1000];\r
131 \r
132         printf("Reading settings file: %s\n", filename);\r
133         count = 0;\r
134         f = fopen(filename, "r");\r
135         if (!f)\r
136                 {\r
137                 printf("Couldn't open file.\n");\r
138                 return false;\r
139                 }\r
140         for (;;)\r
141                 {\r
142                 line[0] = 0;\r
143                 fgets(line, 1000, f);\r
144                 if (!line[0])\r
145                         break;\r
146                 strip_newline(line);\r
147                 sscanf(line, "%s", var);\r
148                 strcpy(map[count][0], var);\r
149                 strcpy(map[count][1], line + strlen(var) + 1);\r
150                 count++;\r
151                 }\r
152         fclose(f);\r
153         return true;\r
154 }\r
155 \r
156 char * Settings::get(char *name)\r
157 {\r
158         int i;\r
159         \r
160         for (i = 0; i < count; ++i)\r
161                 if (!strcmp(map[i][0], name))\r
162                         return map[i][1];\r
163         printf("Setting not found: %s\n", name);\r
164         exit(1);\r
165 }\r
166 \r
167 \r
168 \r
169 \r
170 /*\r
171  *      ChildProc\r
172  */\r
173 \r
174 class ChildProc\r
175 {\r
176 public:\r
177         ChildProc();\r
178         virtual ~ChildProc();\r
179         \r
180         virtual void start(char *cmd_line);\r
181         virtual void stop();\r
182         void send(char *line);\r
183         void receive(char *line, int size);\r
184         bool poll();\r
185         void flush();\r
186         char * get_cmd() { return cmd; }\r
187         \r
188 private:\r
189         void init();\r
190 \r
191         char cmd[100];\r
192         bool running;\r
193 \r
194         int pid;\r
195         int to_prog[2];\r
196         int from_prog[2];\r
197         FILE *to;\r
198         FILE *from;\r
199 };\r
200 \r
201 ChildProc::ChildProc()\r
202 {\r
203         init();\r
204 }\r
205 \r
206 ChildProc::~ChildProc()\r
207 {\r
208         stop();\r
209 }\r
210 \r
211 void ChildProc::init()\r
212 {\r
213         strcpy(cmd, "");\r
214         pid = 0;\r
215         to = NULL;\r
216         from = NULL;\r
217         running = false;\r
218 }\r
219 \r
220 void ChildProc::start(char *cmd_line)\r
221 {\r
222         char *argv[100];\r
223         char arg_buff[100][100];\r
224         int args = 0, i = 0, j = 0;\r
225 \r
226         argv[0] = arg_buff[0];\r
227         for (;;)\r
228                 {\r
229                 argv[args][i] = cmd_line[j];\r
230                 if (!argv[args][i] || argv[args][i] == ' ')\r
231                         {\r
232                         argv[args][i] = 0;\r
233                         args++;\r
234                         argv[args] = arg_buff[args];\r
235                         i = -1;  // will get incremented to 0\r
236                         }\r
237                 if (!cmd_line[j])\r
238                         break;\r
239                 i++;\r
240                 j++;\r
241                 }\r
242         argv[args] = NULL;\r
243         \r
244         stop();\r
245         glock.get();\r
246         pipe(to_prog);\r
247         pipe(from_prog);\r
248         if ((pid = fork()) == 0)  // what to do with glock here?\r
249                 {\r
250                 dup2(to_prog[0], 0);\r
251                 dup2(from_prog[1], 1);\r
252                 close(to_prog[0]);\r
253                 close(to_prog[1]);\r
254                 close(from_prog[0]);\r
255                 close(from_prog[1]);\r
256                 dup2(1, fileno(stderr));  // force stderr to the pipe\r
257                 execvp(argv[0], argv);\r
258                 perror(argv[0]);\r
259                 exit(1);\r
260                 }\r
261         if (pid == -1)\r
262                 {\r
263                 printf("fork() failed, command line: %s\n", cmd_line);\r
264                 exit(1);\r
265                 }\r
266         close(to_prog[0]);\r
267         close(from_prog[1]);\r
268         from = fdopen(from_prog[0], "r");\r
269         to = fdopen(to_prog[1], "w");\r
270         setbuf(from, NULL);\r
271         setbuf(to, NULL);\r
272         glock.release();\r
273 \r
274         running = true;\r
275         strcpy(cmd, argv[0]);   \r
276 }\r
277 \r
278 void ChildProc::stop()\r
279 {\r
280         int x;\r
281         \r
282         if (!running)\r
283                 return;\r
284         glock.get();\r
285         fclose(to);\r
286         fclose(from);\r
287         close(to_prog[1]);\r
288         close(from_prog[0]);\r
289         glock.release();\r
290         kill(pid, SIGTERM);\r
291         waitpid(pid, &x, 0);\r
292         init();\r
293 }\r
294 \r
295 void ChildProc::send(char *line)\r
296 {\r
297         char temp[1000];\r
298         int i;\r
299         \r
300         if (!running)\r
301                 return;\r
302         strcpy(temp, line);\r
303         strip_newline(temp);\r
304         glock.get();\r
305         fprintf(to, "%s\n", temp);\r
306         glock.release();\r
307         if (pipe_logging)\r
308                 printf("%s send: %s\n", cmd, temp);\r
309 }\r
310 \r
311 void ChildProc::receive(char *line, int size)\r
312 {\r
313         int i;\r
314         \r
315         line[0] = 0;\r
316         if (!running)\r
317                 return;\r
318         if (!poll())\r
319                 return;\r
320         glock.get();\r
321         fgets(line, size, from);\r
322         glock.release();\r
323         strip_newline(line);\r
324         if (pipe_logging)\r
325                 printf("%s recv: %s\n", cmd, line);\r
326 }\r
327 \r
328 bool ChildProc::poll()\r
329 {\r
330         fd_set myset;\r
331         timeval mytime;\r
332         int r;\r
333         \r
334         FD_ZERO(&myset);\r
335         FD_SET(from_prog[0], &myset);\r
336         mytime.tv_sec = 0;\r
337         mytime.tv_usec = 0;\r
338         glock.get();\r
339         r = select(from_prog[0] + 1, &myset, NULL, NULL, &mytime);\r
340         glock.release();\r
341         return (r > 0) ? true : false;\r
342 }\r
343 \r
344 void ChildProc::flush()\r
345 {\r
346         char line[1000];\r
347         \r
348         while (poll())\r
349                 {\r
350                 receive(line, 1000);\r
351                 if (!line[0])\r
352                         break;\r
353                 }\r
354 }\r
355 \r
356 \r
357 \r
358 \r
359 /*\r
360  *      ChessEngine\r
361  */\r
362 \r
363 class ChessEngine : private ChildProc\r
364 {\r
365 public:\r
366         void start(char *cmd_line, char *init_str_arg);\r
367         void stop();\r
368         void new_game();\r
369         void send_move(char *move);\r
370         void get_move(char *move);\r
371         bool is_game_over() { return game_over; }\r
372         char * get_result() { return result; }\r
373         \r
374 private:\r
375         bool game_over;\r
376         char result[100];\r
377         char init_str[1000];\r
378 };\r
379 \r
380 void ChessEngine::start(char *cmd_line, char *init_str_arg)\r
381 {\r
382         ChildProc::start(cmd_line);\r
383         send("xboard\n");\r
384         strcpy(init_str, init_str_arg);\r
385 }\r
386 \r
387 void ChessEngine::stop()\r
388 {\r
389         send("quit\n");\r
390         ChildProc::stop();\r
391 }\r
392 \r
393 void ChessEngine::new_game()\r
394 {\r
395         char temp[1000];\r
396         \r
397         // stop the engine and flush leftover output\r
398         // only necessary when reusing the engine\r
399         /*send("?\n");\r
400         usleep(100000);\r
401         flush();*/\r
402 \r
403         send("new\n");\r
404         send("easy\n");\r
405         sprintf(temp, "%s\n", init_str);\r
406         send(temp);\r
407         send("force\n");\r
408 \r
409         game_over = false;\r
410 }\r
411 \r
412 void ChessEngine::send_move(char *move)\r
413 {\r
414         char s[100];\r
415         \r
416         if (game_over)\r
417                 return;\r
418         sprintf(s, "%s\n", move);\r
419         send(s);\r
420 }\r
421 \r
422 void ChessEngine::get_move(char *move)\r
423 {\r
424         char line[1000];\r
425         char tok[1000];\r
426         \r
427         move[0] = 0;\r
428         while (poll())  // does the engine think the game is over?\r
429                 {\r
430                 receive(line, 1000);\r
431                 if (strchr(line, '{'))\r
432                         {\r
433                         game_over = true;\r
434                         copy_result(result, line);\r
435                         }\r
436                 }\r
437         if (game_over)\r
438                 return;\r
439         send("go\n");\r
440         for (;;)\r
441                 {\r
442                 receive(line, 1000);\r
443                 if (!line[0])\r
444                         {\r
445                         usleep(1000);\r
446                         continue;\r
447                         }               \r
448                 if (strchr(line, '{'))\r
449                         {\r
450                         game_over = true;\r
451                         copy_result(result, line);\r
452                         break;\r
453                         }\r
454                 sscanf(line, "%s", tok);\r
455                 if (!strcmp(tok, "move"))\r
456                         {\r
457                         sscanf(line, "move %s", move);\r
458                         break;\r
459                         }\r
460                 }\r
461         if (!game_over)\r
462                 send("force\n");\r
463 }\r
464 \r
465 \r
466 \r
467 \r
468 /*\r
469  *      WorkItems\r
470  */\r
471 \r
472 const int max_work_items = 5000;\r
473 const int max_game_ply = 400;\r
474 \r
475 struct WorkItem\r
476 {\r
477         volatile int status;\r
478         bool printed;\r
479         \r
480         int white_engine;\r
481         int opening_id;\r
482         char opening[200];\r
483         char move[max_game_ply + 2][10];\r
484         int moves;\r
485         char result[100];\r
486 };\r
487 \r
488 WorkItem *work_item[max_work_items];\r
489 int work_items;\r
490 \r
491 bool make_work_items(char *filename)\r
492 {\r
493         FILE *f;\r
494         char line[1000];\r
495         int openings = 0;\r
496         WorkItem *w;\r
497 \r
498         printf("Creating work items from file: %s\n", filename);\r
499         work_items = 0;\r
500         f = fopen(filename, "r");\r
501         if (!f)\r
502                 {\r
503                 printf("Couldn't open file.\n");\r
504                 return false;\r
505                 }\r
506         for (;;)\r
507                 {\r
508                 line[0] = 0;\r
509                 fgets(line, 1000, f);\r
510                 if (!line[0])\r
511                         break;\r
512                 strip_newline(line);\r
513                 openings++;\r
514                 \r
515                 if (only_opening != -1 && openings != only_opening)\r
516                         continue;\r
517                 \r
518                 w = new WorkItem;\r
519                 w->status = 0;\r
520                 w->opening_id = openings;\r
521                 strcpy(w->opening, line);\r
522                 w->white_engine = 1;\r
523                 work_item[work_items++] = w;\r
524 \r
525                 w = new WorkItem;\r
526                 w->status = 0;\r
527                 w->opening_id = openings;\r
528                 strcpy(w->opening, line);\r
529                 w->white_engine = 2;\r
530                 work_item[work_items++] = w;\r
531                 }\r
532         fclose(f);\r
533         printf("%d work items created.\n", work_items);\r
534         return true;\r
535 }\r
536 \r
537 void print_game(WorkItem *w)\r
538 {\r
539         char white_name[100];\r
540         char black_name[100];\r
541         char line[1000];\r
542         char short_result[100];\r
543         char *temp;\r
544         int m, i, line_break;\r
545         \r
546         if (w->white_engine == 1)\r
547                 {\r
548                 strcpy(white_name, settings.get("engine1"));\r
549                 strcpy(black_name, settings.get("engine2"));\r
550                 }\r
551         else\r
552                 {\r
553                 strcpy(white_name, settings.get("engine2"));\r
554                 strcpy(black_name, settings.get("engine1"));\r
555                 }\r
556         sprintf(line, "Opening: %d, %s vs. %s, result: %s\n",\r
557                         w->opening_id,\r
558                         white_name,\r
559                         black_name,\r
560                         w->result);\r
561         printf(line);\r
562         fprintf(match_log, line);\r
563         fflush(match_log);\r
564         \r
565         strcpy(short_result, w->result);\r
566         temp = strchr(short_result, ' ');\r
567         if (temp)\r
568                 *temp = 0;\r
569         fprintf(pgn_log, "[Round \"%d.%d\"]\n", w->opening_id, w->white_engine);\r
570         fprintf(pgn_log, "[White \"%s\"]\n", white_name);\r
571         fprintf(pgn_log, "[Black \"%s\"]\n", black_name);\r
572         fprintf(pgn_log, "[Result \"%s\"]\n", short_result);\r
573         fprintf(pgn_log, "\n");\r
574         m = 0;\r
575         line_break = 0;\r
576         for (i = 1;; ++i)\r
577                 {\r
578                 if (m == w->moves)\r
579                         {\r
580                         fprintf(pgn_log, "%s\n", w->result);\r
581                         break;\r
582                         }\r
583                 fprintf(pgn_log, "%d. %s ", i, w->move[m++]);\r
584                 if (m < w->moves)\r
585                         fprintf(pgn_log, "%s ", w->move[m++]);\r
586                 if (m > line_break + 8)\r
587                         {\r
588                         fprintf(pgn_log, "\n");\r
589                         line_break = m;\r
590                         }\r
591                 }\r
592         fprintf(pgn_log, "\n");\r
593         fflush(pgn_log);\r
594         \r
595         w->printed = true;\r
596 }\r
597 \r
598 void print_stats(int items)\r
599 {\r
600         int i;\r
601         int win = 0, lose = 0, draw = 0;\r
602         int games = 0;\r
603         double percent;\r
604         double elo;\r
605         char elo_sign = '+';\r
606         int elapsed_time;\r
607         int min, sec;\r
608         double spg = 10.0;\r
609         double percent_done;\r
610         double eta;\r
611         int eta_min, eta_sec;\r
612         \r
613         for (i = 0; i < items; ++i)\r
614                 {\r
615                 if (work_item[i]->status != 2)  // shouldn't happen\r
616                         break;\r
617                 if (strstr(work_item[i]->result, "1-0"))\r
618                         {\r
619                         if (work_item[i]->white_engine == 1)\r
620                                 win++;\r
621                         else\r
622                                 lose++;\r
623                         }\r
624                 if (strstr(work_item[i]->result, "0-1"))\r
625                         {\r
626                         if (work_item[i]->white_engine == 1)\r
627                                 lose++;\r
628                         else\r
629                                 win++;\r
630                         }\r
631                 if (strstr(work_item[i]->result, "1/2-1/2"))\r
632                         draw++;\r
633                 }\r
634         games = win + lose + draw;\r
635         \r
636         percent = (double)win + (0.5 * (double)draw);\r
637         percent /= (double)games;\r
638         if (percent > 0.99999)\r
639                 elo = 400.0;\r
640         else if (percent < 0.00001)\r
641                 elo = -400.0;\r
642         else\r
643                 elo = -400.0 * log(1.0 / percent - 1.0) / log(10.0);\r
644         if (elo < 0.0)\r
645                 {\r
646                 elo_sign = '-';\r
647                 elo = -elo;\r
648                 }\r
649         elapsed_time = time(NULL) - start_time;\r
650         sec = elapsed_time;\r
651         min = sec / 60;\r
652         sec -= min * 60;\r
653         if (elapsed_time)\r
654                 spg = (double)(time(NULL) - start_time) / (double)games;\r
655         percent_done = (double)games / (double)work_items;\r
656         eta = (double)work_items - (double)games;\r
657         eta *= spg;\r
658         eta_sec = (int)eta;\r
659         eta_min = eta_sec / 60;\r
660         eta_sec -= eta_min * 60;\r
661         \r
662         printf("%s vs. %s: +%d -%d =%d, %.2f%c, ELO: %c%d\n",\r
663                         settings.get("engine1"),\r
664                         settings.get("engine2"),\r
665                         win, lose, draw,\r
666                         (float)(percent * 100.0), '%',\r
667                         elo_sign, (int)elo);\r
668         printf("%d games in %d:%02d, %.2f seconds/game, %.1f%c done, ETA: %d:%02d\n",\r
669                         games, min, sec, (float)spg,\r
670                         (float)(percent_done * 100.0), '%',\r
671                         eta_min, eta_sec);\r
672         printf("\n");\r
673 }\r
674 \r
675 \r
676 \r
677 /*\r
678  *      WorkerThread\r
679  */\r
680 \r
681 class WorkerThread\r
682 {\r
683 public:\r
684         void do_work(int id_arg);\r
685         void do_item(WorkItem *w);\r
686
687 private:\r
688         void do_opening(WorkItem *w);\r
689         void add_move(WorkItem *w, char *move);\r
690 \r
691         int id;\r
692         ChessEngine engine1, engine2;\r
693 };\r
694 \r
695 void WorkerThread::do_work(int id_arg)\r
696 {\r
697         int i;\r
698         \r
699         id = id_arg;\r
700         for (;;)\r
701                 {\r
702                 glock.get();\r
703                 for (i = 0; i < work_items; ++i)\r
704                         if (work_item[i]->status == 0)\r
705                                 break;\r
706                 if (i != work_items)\r
707                         work_item[i]->status = 1;\r
708                 glock.release();\r
709 \r
710                 if (i == work_items)\r
711                         break;\r
712                 do_item(work_item[i]);\r
713                 }\r
714 }\r
715 \r
716 void WorkerThread::do_item(WorkItem *w)\r
717 {\r
718         char move[100];\r
719         ChessEngine *etm;  // engine to move\r
720         ChessEngine *etw;  // engine to wait\r
721         ChessEngine *temp;\r
722 \r
723         w->printed = false;\r
724         w->moves = 0;\r
725         \r
726         engine1.start(settings.get("cmd1"), settings.get("init1"));\r
727         engine2.start(settings.get("cmd2"), settings.get("init2"));\r
728         engine1.new_game();\r
729         engine2.new_game();\r
730         do_opening(w);\r
731         \r
732         etm = &engine1;\r
733         etw = &engine2;\r
734         if ((w->moves & 1) == 1 && w->white_engine == 1)\r
735                 {\r
736                 etm = &engine2;\r
737                 etw = &engine1;\r
738                 }\r
739         if ((w->moves & 1) == 0 && w->white_engine == 2)\r
740                 {\r
741                 etm = &engine2;\r
742                 etw = &engine1;\r
743                 }\r
744         for (;;)\r
745                 {\r
746                 etm->get_move(move);\r
747                 if (etm->is_game_over())\r
748                         {\r
749                         strcpy(w->result, etm->get_result());\r
750                         break;\r
751                         }\r
752                 etw->send_move(move);\r
753                 add_move(w, move);\r
754                 if (w->moves >= max_game_ply)\r
755                         {\r
756                         strcpy(w->result, "1/2-1/2 {Game too long}");\r
757                         break;\r
758                         }\r
759                 temp = etm;\r
760                 etm = etw;\r
761                 etw = temp;\r
762                 }\r
763         \r
764         engine1.stop();\r
765         engine2.stop();\r
766         w->status = 2;\r
767 }\r
768 \r
769 void WorkerThread::do_opening(WorkItem *w)\r
770 {\r
771         char move[100];\r
772         int i = 0, j = 0;\r
773         \r
774         for (;;)\r
775                 {\r
776                 move[i] = w->opening[j];\r
777                 if (!move[i] || move[i] == ' ')\r
778                         {\r
779                         move[i] = 0;\r
780                         engine1.send_move(move);\r
781                         engine2.send_move(move);\r
782                         add_move(w, move);\r
783                         i = -1;\r
784                         }\r
785                 if (!w->opening[j])\r
786                         break;\r
787                 i++;\r
788                 j++;\r
789                 }\r
790 }\r
791 \r
792 void WorkerThread::add_move(WorkItem *w, char *move)\r
793 {\r
794         strcpy(w->move[w->moves++], move);\r
795 }\r
796 \r
797 \r
798 \r
799 \r
800 /*\r
801  *      threads\r
802  */\r
803 \r
804 WorkerThread *worker[100];\r
805 pthread_t *mythread[100];\r
806 volatile int thread_count = 0;\r
807 \r
808 void * thread_proc(void *arg)\r
809 {\r
810         int id;\r
811         \r
812         glock.get();\r
813         id = thread_count++;\r
814         glock.release();\r
815         worker[id] = new WorkerThread;\r
816         worker[id]->do_work(id);\r
817         delete worker[id];\r
818         pthread_exit(&mythread[id]);\r
819         delete mythread[id];  // ?\r
820 }\r
821 \r
822 void start_threads(int count)\r
823 {\r
824         int i;\r
825         int x = 0;\r
826 \r
827         printf("Starting threads...\n");\r
828         for (i = 0; i < count; ++i)\r
829                 {\r
830                 mythread[i] = new pthread_t;\r
831                 pthread_create(mythread[i], NULL, thread_proc, (void *)&x);\r
832                 }\r
833         printf("Started %d threads.\n", i);\r
834 }\r
835 \r
836 \r
837 \r
838 \r
839 /*\r
840  *      main\r
841  */\r
842 \r
843 main(int argc, char *argv[])\r
844 {\r
845         int i;\r
846         char settings_filename[100];\r
847         int threads = 1;\r
848         \r
849         start_time = time(NULL);\r
850         strcpy(settings_filename, "settings.txt");\r
851 \r
852         for (i = 1;;)\r
853                 {\r
854                 if (i >= argc)\r
855                         break;\r
856                 if (!strcmp(argv[i], "-l"))\r
857                         {\r
858                         pipe_logging = true;\r
859                         }\r
860                 else if (!strcmp(argv[i], "-o"))\r
861                         {\r
862                         only_opening = atoi(argv[++i]);\r
863                         }\r
864                 else if (!strcmp(argv[i], "-t"))\r
865                         {\r
866                         threads = atoi(argv[++i]);\r
867                         }\r
868                 else if (argv[i][0] == '-')\r
869                         {\r
870                         printf("Usage: shiai [options] [settings file]\n");\r
871                         printf("\n");\r
872                         printf(" -h   : Display this screen\n");\r
873                         printf(" -l   : Display I/O with engines (\"log\")\n");\r
874                         printf(" -o # : Run opening number #\n");\r
875                         printf(" -t # : Run with # threads\n");\r
876                         printf("\n");\r
877                         exit(0);\r
878                         }\r
879                 else\r
880                         {\r
881                         strcpy(settings_filename, argv[i]);\r
882                         }\r
883                 i++;\r
884                 }\r
885         \r
886         if (!settings.read(settings_filename))\r
887                 exit(1);\r
888         if (!make_work_items(settings.get("openings")))\r
889                 exit(1);\r
890         \r
891         pgn_log = fopen(settings.get("pgnlog"), "w");\r
892         if (!pgn_log)\r
893                 {\r
894                 printf("Couldn't open %s for writing.\n", settings.get("pgnlog"));\r
895                 exit(1);\r
896                 }\r
897         match_log = fopen(settings.get("matchlog"), "w");\r
898         if (!match_log)\r
899                 {\r
900                 printf("Couldn't open %s for writing.\n", settings.get("matchlog"));\r
901                 exit(1);\r
902                 }\r
903         \r
904         if (threads <= 0 || threads > 16)\r
905                 threads = 1;\r
906         start_threads(threads);\r
907         for (i = 0; i < work_items; ++i)\r
908                 {\r
909                 while (work_item[i]->status != 2)\r
910                         sleep(1);\r
911                 print_game(work_item[i]);\r
912                 print_stats(i + 1);\r
913                 }\r
914         \r
915         fclose(pgn_log);\r
916         fclose(match_log);\r
917         return 0;\r
918 }\r