My Project
game.c
Go to the documentation of this file.
1
11#include "bit.h"
12#include "board.h"
13#include "const.h"
14#include "game.h"
15#include "search.h"
16#include "util.h"
17
18#include <ctype.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <time.h>
23
25enum {
30};
31
39{
40 return 8 * ((x - 11) / 10) + ((x - 11) % 10);
41}
42
49static int move_to_wthor(int x)
50{
51 return 10 * (x / 8) + (x % 8) + 11;
52}
53
62static int move_from_oko(int x)
63{
64 static const char oko_to_edax[]={
65 0,
66 A1,B1,C1,D1,E1,F1,G1,H1,
67 A2,B2,C2,D2,E2,F2,G2,H2,
68 A3,B3,C3,D3,E3,F3,G3,H3,
69 A4,B4,C4, F4,G4,H4,
70 A5,B5,C5, F5,G5,H5,
71 A6,B6,C6,D6,E6,F6,G6,H6,
72 A7,B7,C7,D7,E7,F7,G7,H7,
73 A8,B8,C8,D8,E8,F8,G8,H8
74 };
75 return oko_to_edax[x & 0x3f];
76}
77
83void game_init(Game *game)
84{
85 char name[2] = "?";
87 memset(game->move, NOMOVE, 60);
88 game->player = BLACK;
89 memcpy(game->name[0], name, 2);
90 memcpy(game->name[1], name, 2);
91 game->date.year = game->date.month = game->date.day = 0;;
92 game->date.hour = -1; game->date.minute = game->date.second = 0;;
93 game->hash = 0ULL;
94}
95
103void game_copy(Game *dest, const Game *src)
104{
105 *dest = *src;
106}
107
114bool game_equals(const Game *game_1, const Game *game_2)
115{
116 int i;
117 if (game_1->hash == game_2->hash
118 && game_1->date.year == game_2->date.year && game_1->date.month == game_2->date.month && game_1->date.day == game_2->date.day
119 && game_1->date.hour == game_2->date.hour && game_1->date.minute == game_2->date.minute && game_1->date.second == game_2->date.second
120 && strcmp(game_1->name[0], game_2->name[0]) == 0 && strcmp(game_1->name[1], game_2->name[1]) == 0) {
121 for (i = 0; i < 60; ++i) {
122 if (game_1->move[i] != game_2->move[i]) return false;
123 }
124 return true;
125 } else {
126 return false;
127 }
128}
129
136bool wthor_equals(const WthorGame *game_1, const WthorGame *game_2)
137{
138 int i;
139 if (game_1->black == game_2->black && game_1->white ==game_2->white && game_1->tournament == game_2->tournament) {
140 for (i = 0; i < 60; ++i) {
141 if (game_1->x[i] != game_2->x[i]) return false;
142 }
143 return true;
144 } else {
145 return false;
146 }
147}
148
153bool game_update_board(Board *board, int x)
154{
155 Move move[1];
156
157 if (x < A1 || x > H8 || board_is_occupied(board, x)) return false;
158 if (!can_move(board->player, board->opponent)) {
159 board_pass(board);
160 }
161 if (board_get_move(board, x, move) == 0) return false;
162 board_update(board, move);
163
164 return true;
165}
166
171static bool game_update_player(Board *board, int x)
172{
173 Move move[1];
174 bool swap = false;
175
176 if (A1 <= x && x <= H8 && !board_is_occupied(board, x)) {
177 if (!can_move(board->player, board->opponent)) {
178 board_pass(board);
179 swap = !swap;
180 }
181 if (board_get_move(board, x, move) == 0) swap = !swap;
182 }
183
184 return swap;
185}
186
195bool game_get_board(const Game *game, const int ply, Board *board)
196{
197 int i;
198
199 *board = *game->initial_board;
200 for (i = 0; i < ply; i++) {
201 if (!game_update_board(board, game->move[i])) return false;
202 }
203
204 return true;
205}
206
213bool game_check(Game *game)
214{
215 Board board[1];
216 int i;
217
218 *board = *game->initial_board;
219 for (i = 0; i < 60 && game->move[i] != NOMOVE; ++i) {
220 if (!game_update_board(board, game->move[i])) {
221 return false;
222 }
223 }
224 return true;
225}
226
233int game_score(const Game *game)
234{
235 int n_discs_p, n_discs_o, n_empties;
236 int i, player, score;
237 Board board[1];
238
239 *board = *game->initial_board;
240 player = game->player;
241 for (i = 0; i < 60 && game->move[i] != NOMOVE; ++i) {
242 player ^= game_update_player(board, game->move[i]);
243 if (!game_update_board(board, game->move[i])) {
244 return -SCORE_INF;
245 }
246 }
247
248 if (!board_is_game_over(board)) return -SCORE_INF;
249
250 n_discs_p = bit_count(board->player);
251 n_discs_o = bit_count(board->opponent);
252 n_empties = 64 - n_discs_p - n_discs_o;
253 score = n_discs_p - n_discs_o;
254
255 if (score < 0) score -= n_empties;
256 else if (score > 0) score += n_empties;
257
258 if (player == game->player) return score;
259 else return -score;
260}
261
267void text_to_game(const char *line, Game *game)
268{
269 int i;
270 Board board[1];
271 Move move[1];
272 char *s;
273
275 game_init(game);
276 *board = *game->initial_board;
277 for (i = 0; i < 60 && *line;) {
278 s = parse_move(line, board, move);
279 if (s == line && move->x == NOMOVE) return;
280 if (move->x != PASS) {
281 game->hash ^= hash_move[move->x][i];
282 game->move[i++] = move->x;
283 }
284 board_update(board, move);
285 line = s;
286 }
287}
288
294void game_to_text(const Game *game, char *line)
295{
296 int i;
297
298 for (i = 0; i < 60 && game->move[i] != NOMOVE; i++) {
299 line = move_to_string(game->move[i], BLACK, line) + 2;
300 }
301 *line = '\0';
302}
303
313void oko_to_game(const OkoGame *oko, Game *game)
314{
315 int i;
316 Board board[1];
317
318 game_init(game);
319 *board = *game->initial_board;
320 for (i = 0; i < 60; i++) {
321 game->move[i] = move_from_oko(oko->move[i]);
322 if (!game_update_board(board, game->move[i])) {
323 game->move[i] = NOMOVE;
324 break;
325 }
326 game->hash ^= hash_move[(int)game->move[i]][i];
327 }
328}
329
340void wthor_to_game(const WthorGame *thor, Game *game)
341{
342 int i;
343 Board board[1];
344
345 game_init(game);
346 *board = *game->initial_board;
347 for (i = 0; i < 60; i++) {
348 game->move[i] = move_from_wthor(thor->x[i]);
349 if (!game_update_board(board, game->move[i])) {
350 game->move[i] = NOMOVE;
351 break;
352 }
353 game->hash ^= hash_move[(int)game->move[i]][i];
354 }
355}
356
366void game_to_wthor(const Game *game, WthorGame *thor)
367{
368 int i;
369
370 for (i = 0; i < 60; i++) {
371 thor->x[i] = move_to_wthor(game->move[i]);
372 }
373 thor->black = 1368; // edax
374 thor->white = 1368; // edax
375 thor->tournament = 0;//g->tournament;
376 /* TODO: */
377 thor->score = 32 + game_score(game) / 2;
378 thor->theoric_score = thor->score; // may be wrong?
379}
380
388void game_append_line(Game *game, const Line *line, const int from)
389{
390 int i, j;
391 Board board[1];
392
393 if (game_get_board(game, from, board)) {
394 for (i = 0, j = from; i < line->n_moves && j < 60; ++i) {
395 if (line->move[i] != PASS) {
396 if (game_update_board(board, line->move[i])) {
397 game->hash ^= hash_move[(int)line->move[i]][j];
398 game->move[j++] = line->move[i];
399 } else {
400 break;
401 }
402 }
403 }
404 for (; j < 60; ++j) game->move[j] = NOMOVE;
405 }
406}
407
415void line_to_game(const Board *initial_board, const Line *line, Game *game)
416{
417 game_init(game);
418 *game->initial_board = *initial_board;
419 game->player = line->color;
420 game_append_line(game, line, 0);
421}
422
429void game_read(Game *game, FILE *f)
430{
431 if (fread(game, sizeof (Game), 1, f) == 0) game_init(game);
432}
433
440void game_write(const Game *game, FILE *f)
441{
442 fwrite(game, sizeof (Game), 1, f);
443}
444
451void game_import_text(Game *game, FILE *f)
452{
453 char *line = string_read_line(f);
454
455 if (line) text_to_game(line, game);
456 else game_init(game);
457
458 free(line);
459}
460
467void game_export_text(const Game *game, FILE *f)
468{
469 char s_game[128], s_board[80];
470 Board board[1];
471
472 board_init(board);
473 if (!board_equal(board, game->initial_board)) {
474 board_to_string(game->initial_board, game->player, s_board);
475 fprintf(f, "%s;", s_board);
476 }
477 game_to_text(game, s_game);
478 fprintf(f, "%s\n", s_game);
479}
480
487void game_import_wthor(Game *game, FILE *f)
488{
489 WthorGame thor;
490 if (fread(&thor, sizeof (WthorGame), 1, f) == 1) wthor_to_game(&thor, game);
491 else game_init(game);
492}
493
500void game_export_wthor(const Game *game, FILE *f)
501{
502 WthorGame thor;
503 game_to_wthor(game, &thor);
504 fwrite(&thor, sizeof (WthorGame), 1, f);
505}
506
513void game_import_oko(Game *game, FILE *f)
514{
515 OkoGame oko;
516 if (fread(&oko, sizeof (OkoGame), 1, f) == 1) oko_to_game(&oko, game);
517 else game_init(game);
518}
519
529static int game_parse_ggf(FILE *f, char *tag, char *value)
530{
531 int i, c='\0';
532
533 tag[0] = tag[1] = tag[2] = '\0';
534 value[0] = '\0';
535
536 for (i = 0; i < 3; i++) {
537 c=fgetc(f);
538 if (c==EOF) return PARSE_END_OF_FILE;
539 else if (c==' ' || c=='\n' || c=='\r' || c=='\t') {
540 i--;
541 continue;
542 }
543 else if (c == '[') break;
544 else if ('A' <= c && c <= 'Z') tag[i] = (char)c;
545 else if (i == 0 && (c == '(' || c == ';')) {
546 tag[0] = (char)c;
547 c = fgetc(f);
548 if ((tag[0] == '(' && c == ';') || (tag[0] == ';' && c == ')')) {
549 tag[1] = (char)c;
550 tag[2] = '\0';
551 return PARSE_OK;
552 } else return PARSE_INVALID_TAG;
553 } else return PARSE_INVALID_TAG;
554 }
555 if (c != '[') return PARSE_INVALID_TAG;
556 tag[i] = '\0';
557
558 for (i = 0; i < 1000; i++) {
559 c = fgetc(f);
560 if (c == EOF) return PARSE_END_OF_FILE;
561 if (c == ']') break;
562 value[i] = tolower(c);
563 }
564 value[i]='\0';
565
566 if (i == 1000) {
567 for (i = 0; ; i++) {
568 c = fgetc(f);
569 if (c == EOF) return PARSE_END_OF_FILE;
570 if (c == ']') break;
571 }
572 }
573 return PARSE_OK;
574}
575
582void game_import_ggf(Game* game, FILE* f)
583{
584 char tag[4], value[1000];
585 int i = 0;
586
587 game_init(game);
588 while (game_parse_ggf(f, tag, value) != PARSE_END_OF_FILE && strcmp(tag, "(;") != 0) ;
589 if (strcmp(tag, "(;") == 0) {
590 while (game_parse_ggf(f, tag, value) == PARSE_OK) {
591 if (strcmp(tag,";)")==0) {
592 if (!game_check(game)) {
593 warn("error while importing a GGF game\n");
594 }
595 return;
596 }
597 if (strcmp(tag,"GM") == 0 && strcmp(value, "othello") != 0) break;
598 if (strcmp(tag, "BO") == 0) {
599 if (value[0] != '8') break;
600 game->player = board_set(game->initial_board, value + 2);
601 } else if (strcmp(tag, "PB") == 0) {
602 memcpy(game->name[BLACK], value, 31);
603 game->name[BLACK][31] = '\0';
604 } else if (strcmp(tag, "DT") == 0) {
605 int v[6]; // hack for windows that does not support %hhd in sscanf
606 sscanf(value, "%d.%d.%d_%d:%d:%d", v, v + 1, v + 2, v + 3, v + 4, v + 5);
607 game->date.year = v[0]; game->date.month = v[1]; game->date.day = v[2];
608 game->date.hour = v[3]; game->date.minute = v[4]; game->date.second = v[5];
609 } else if (strcmp(tag, "PW") == 0) {
610 memcpy(game->name[WHITE], value, 31);
611 game->name[WHITE][31] = '\0';
612 } else if (i < 60 && (strcmp(tag, "B") == 0 || strcmp(tag, "W") == 0)) {
613 if (strncmp("pa", value, 2) == 0) continue;
614 game->move[i] = string_to_coordinate(value);
615 game->hash ^= hash_move[(int)game->move[i]][i];
616 i++;
617 }
618 }
619 while (game_parse_ggf(f, tag, value) != PARSE_END_OF_FILE && strcmp(tag,";)") != 0) ;
620 }
621 return;
622}
623
632static const char* parse_tag(const char *string, char *tag, char *value)
633{
634 const char *s;
635 int n;
636
637 s = parse_skip_spaces(string);
638 if ((s[0] == '(' && s[1] == ';') || (s[0] == ';' && s[1] == ')')) {
639 tag[0] = *s++;
640 tag[1] = *s++;
641 tag[2] = *value = '\0';
642 } else {
643 n = 3; while (*s && *s != '[' && n--) *tag++ = toupper(*s++);
644 *tag = '\0';
645 if (*s == '[') {
646 ++s;
647 n = 255; while (*s && *s != ']' && n--) *value++ = tolower(*s++);
648 if (*s == ']') ++s;
649 else s = string;
650 } else s = string;
651 *value = '\0';
652 }
653
654 return s;
655}
656
664char* parse_ggf(Game *game, const char *string)
665{
666 const char *s = string;
667 const char *next;
668 char tag[4], value[256];
669 int i = 0;
670
671 game_init(game);
672
673 while ((next = parse_tag(s, tag, value)) != s && strcmp(tag, "(;") != 0) s = next;
674
675 if (strcmp(tag, "(;") == 0) {
676 s = next;
677 while ((next = parse_tag(s, tag, value)) != s && strcmp(tag, ";)") != 0) {
678 s = next;
679
680 if (strcmp(tag, "GM") == 0 && strcmp(value, "othello") != 0) {
681 s = string;
682 break;
683 } else if (strcmp(tag, "BO") == 0) {
684 if (value[0] != '8') {
685 s = string;
686 break;
687 }
688 game->player = board_set(game->initial_board, value + 2);
689 } else if (strcmp(tag, "PB") == 0) {
690 memcpy(game->name[BLACK], value, 31);
691 game->name[BLACK][31] = '\0';
692 } else if (strcmp(tag, "PW") == 0) {
693 memcpy(game->name[WHITE], value, 31);
694 game->name[WHITE][31] = '\0';
695 } else if (i < 60 && (strcmp(tag, "B") == 0 || strcmp(tag, "W") == 0)) {
696 if (strncmp("pa", value, 2) == 0) continue;
697 game->move[i++] = string_to_coordinate(value);
698 }
699 }
700 }
701
702 if (!game_check(game)) s = string;
703
704 return (char*) s;
705}
706
713void game_export_ggf(const Game *game, FILE *f)
714{
715 Board board[1];
716 int player;
717 static const char board_color[] = "*O-?";
718 int i, x, square;
719// time_t t:
720// struct tm *date;
721 static const char move_color[] = "BW";
722 char move_string[3] = "xx";
723
724 fputs("(;GM[othello]PC[Edax]", f);
725// t = time(NULL);
726// date = localtime(&t);
727// fprintf(f, "DT[%d.%2d.%2d_%2d:%2d:%2d]", date->tm_year + 1900, date->tm_mon + 1, date->tm_mday, date->tm_hour, date->tm_min, date->tm_sec);
728 fprintf(f, "PB[%s]PW[%s]", game->name[BLACK], game->name[WHITE]);
729 fprintf(f, "RE[%+d.000]", game_score(game));
730 fputs("BO[8 ", f);
731 for (x = 0; x < 64; ++x) {
732 if (game->player == BLACK) square = 2 - ((game->initial_board->opponent >> x) & 1) - 2 * ((game->initial_board->player >> x) & 1);
733 else square = 2 - ((game->initial_board->player >> x) & 1) - 2 * ((game->initial_board->opponent >> x) & 1);
734 putc(board_color[square], f); if ((x & 7) == 7) putc(' ', f);
735 }
736 putc(board_color[(int) game->player], f); fputc(']', f);
737
738 *board = *game->initial_board;
739 player = game->player;
740 for (i = 0; i < 60 && game->move[i] != NOMOVE; ++i) {
741 if (!can_move(board->player, board->opponent)) {
742 fprintf(f, "%c[PA]", move_color[player]);
743 player = !player;
744 }
745 if (game_update_board(board, game->move[i])) {
746 fprintf(f, "%c[%s]", move_color[player], move_to_string(game->move[i], 0, move_string));
747 player = !player;
748 }
749 }
750 fputs(";)\n", f);
751}
752
762static int game_parse_sgf(FILE *f, char *tag, char *value)
763{
764 int i, c = '\0';
765
766 tag[0] = tag[1] = tag[2] = '\0';
767 value[0] = '\0';
768
769 for (i = 0; i < 3; i++) {
770 c = fgetc(f);
771 if (c == EOF) return 0;
772 else if (c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == ';') {
773 i--;
774 continue;
775 }
776 else if (c == '[') break;
777 else if ('A' <= c && c <= 'Z') tag[i] = (char)c;
778 else if (i == 0 && (c == '(' || c == ')')) {
779 tag[0] = (char)c;
780 tag[1] = '\0';
781 return 1;
782 }
783 else return 0;
784
785 }
786 if (c != '[') return 0;
787 tag[i] = '\0';
788
789 for (i = 0; i < 1000; i++) {
790 c = fgetc(f);
791 if (c == EOF) return 0;
792 if (c == ']') break;
793 if (c == '\\') {
794 c = fgetc(f);
795 if (c == EOF) return 0;
796 }
797 value[i] = (char)c;
798 }
799 if (i < 1000) {
800 if (c != ']') return 0;
801 value[i] = '\0';
802 } else {
803 for (i = 0; ; i++) {
804 c = fgetc(f);
805 if (c == EOF) return 0;
806 if (c == '\\') {
807 c = fgetc(f);
808 if (c == EOF) return 0;
809 }
810 if (c == ']') break;
811 }
812 }
813
814 return 1;
815}
816
823void game_import_sgf(Game *game, FILE *f)
824{
825 char tag[4], value[1000];
826 int i = 0, level = 1;
827
828 game_parse_sgf(f, tag, value);
829 game_init(game);
830 if (strcmp(tag, "(") == 0) {
831 while (game_parse_sgf(f, tag, value)) {
832 if (strcmp(tag,"(") == 0) level++;
833 if (strcmp(tag,")") == 0) {
834 level--;
835 if (!game_check(game)) {
836 warn("error while importing a SGF game\n");
837 }
838 return;
839 }
840 if (strcmp(tag, "GM") == 0 && strcmp(value, "2") != 0) break;
841 if (strcmp(tag, "SZ") == 0 && strcmp(value, "8") != 0) break;
842 if (strcmp(tag, "PB") == 0) {
843 memcpy(game->name[BLACK], value, 31);
844 game->name[BLACK][31] = '\0';
845 } else if (strcmp(tag, "PW") == 0) {
846 memcpy(game->name[WHITE], value, 31);
847 game->name[WHITE][31] = '\0';
848 } else if (i < 60 && (strcmp(tag,"B") == 0 || strcmp(tag, "W") == 0)) {
849 game->move[i] = string_to_coordinate(value);
850 game->hash ^= hash_move[(int)game->move[i]][i];
851 i++;
852
853 }
854 }
855 while (level > 0 && game_parse_sgf(f, tag, value)) {
856 if (strcmp(tag,"(") == 0) level++;
857 if (strcmp(tag,")") == 0) level--;
858 }
859 }
860 return;
861}
862
870void game_save_sgf(const Game *game, FILE *f, const bool multiline)
871{
872 Board board[1];
873 int player;
874 static const char color[2] = {'B', 'W'};
875 char s[8];
876 int i;
877 time_t t = time(NULL);
878 struct tm *date = localtime(&t);
879 unsigned long long black, white;
880 const int score = game_score(game);
881
882 // game info
883 fprintf(f, "(;FF[4]GM[2]AP[edax:%s]", VERSION_STRING);
884 if (multiline) fputc('\n',f);
885 fputs("PC[Edax]", f);
886 fprintf(f,"DT[%04d-%02d-%02d]", 1900 + date->tm_year, 1 + date->tm_mon, date->tm_mday);
887 if (multiline) fputc('\n',f);
888 fprintf(f, "PB[%s]PW[%s]", game->name[BLACK], game->name[WHITE]);
889 if (multiline) fputc('\n',f);
890
891 // initial board
892 if (game->player == BLACK) {
893 black = game->initial_board->player;
894 white = game->initial_board->opponent;
895 } else {
896 white = game->initial_board->player;
897 black = game->initial_board->opponent;
898 }
899 fputs("SZ[8]",f);
900 if (black) {
901 fputs("AB", f);
902 for (i = A1; i <= H8; i++){
903 if (black & x_to_bit(i)) fprintf(f, "[%s]", move_to_string(i, WHITE, s));
904 }
905 }
906 if (white) {
907 fputs("AW", f);
908 for (i = A1; i <= H8; i++){
909 if (white & x_to_bit(i)) fprintf(f, "[%s]", move_to_string(i, WHITE, s));
910 }
911 }
912 fprintf(f, "PL[%c]", color[(int) game->player]);
913 if (multiline) fputc('\n', f);
914
915 /* score */
916 if (score >= SCORE_MIN) {
917 if (score > 0) fprintf(f, "RE[%c%+d]", color[(int) game->player], score);
918 else if (score < 0) fprintf(f, "RE[%c%+d]", color[(int) !game->player], -score);
919 else fputs("RE[0]", f);
920 } else {
921 fputs("RE[Void]", f);
922 }
923 if (multiline) fputc('\n', f);
924
925 /* moves */
926 *board = *game->initial_board;
927 player = game->player;
928 for (i = 0; i < 60 && game->move[i] != NOMOVE; ++i) {
929 if (!can_move(board->player, board->opponent)) {
930 fprintf(f, "%c[PA];", color[player]);
931 player = !player;
932 if (multiline && player == game->player) fputc('\n', f);
933 }
934 if (game_update_board(board, game->move[i])) {
935 fprintf(f, "%c[%s];", color[player], move_to_string(game->move[i], WHITE, s));
936 player = !player;
937 if (multiline && player == game->player) fputc('\n', f);
938 }
939 }
940 /*end */
941 fputs(")\n", f);
942}
943
944void game_export_sgf(const Game *game, FILE *f)
945{
946 game_save_sgf(game, f, false);
947}
948
955void game_import_pgn(Game *game, FILE *f)
956{
957 int c, state, i, j, k, n;
958 char move[5] = "--\0\0";
959 int score[2] = {0, 0};
960 char info_tag[257] = "", info_value[257] = ""; // 256 is the maximal info size according to PGN standard
961 int value[3];
962 const int info_size = 256;
963
964 enum {
965 STATE_START,
966 STATE_BEGIN_INFO,
967 STATE_END_INFO,
968 STATE_BEGIN_VALUE,
969 STATE_END_VALUE,
970 STATE_BEGIN_MOVE_N,
971 STATE_END_MOVE_N,
972 STATE_BEGIN_MOVE,
973 STATE_END_MOVE,
974 STATE_BEGIN_SCORE,
975 STATE_END_SCORE,
976 STATE_END_GAME
977 };
978
979 game_init(game);
980 state = STATE_START;
981 i = j = k = 0;
982 while(state != STATE_END_GAME) {
983 c = getc(f);
984 putchar(c);
985 if (c == EOF) {
986 state = STATE_END_GAME;
987 } else if (c == '{') { // skip comments
988 do {
989 c = getc(f);
990 } while(c != EOF && c != '}');
991 } else if (c == '[') {
992 switch(state) {
993 case STATE_START:
994 case STATE_END_INFO:
995 state = STATE_BEGIN_INFO;
996 j = 0;
997 break;
998 case STATE_END_MOVE:
999 case STATE_END_SCORE:
1000 ungetc(c, f);
1001 state = STATE_END_GAME;
1002 break;
1003 default:
1004 warn("unexpected '['");
1005 }
1006 } else if (c == ']') {
1007 switch(state) {
1008 case STATE_END_VALUE:
1009 state = STATE_END_INFO;
1010 break;
1011 default:
1012 warn("unmatched ']'");
1013 break;
1014 }
1015 } else if (c == '"') {
1016 switch (state) {
1017 case STATE_BEGIN_INFO:
1018 state = STATE_BEGIN_VALUE;
1019 for (--j; j >= 0 && isspace(info_tag[j]); --j);
1020 info_tag[j + 1] = '\0';
1021 j = 0;
1022 string_to_lowercase(info_tag);
1023 break;
1024 case STATE_BEGIN_VALUE:
1025 state = STATE_END_VALUE;
1026 info_value[j] = '\0';
1027 j = 0;
1028 if (strcmp(info_tag, "black") == 0) {
1029 memcpy(game->name[BLACK], info_value, 31);
1030 game->name[BLACK][31] = '\0';
1031 } else if (strcmp(info_tag, "white") == 0) {
1032 memcpy(game->name[WHITE], info_value, 31);
1033 game->name[WHITE][31] = '\0';
1034 } else if (strcmp(info_tag, "date") == 0) {
1035 sscanf(info_value, "%d.%d.%d", value, value + 1, value + 2);
1036 game->date.year = value[0]; game->date.month = value[1]; game->date.day = value[2];
1037 } else if (strcmp(info_tag, "time") == 0) {
1038 sscanf(info_value, "%d:%d:%d", value, value + 1, value + 2);
1039 game->date.hour = value[0]; game->date.minute = value[1]; game->date.second = value[2];
1040 } else if (strcmp(info_tag, "FEN") == 0) {
1041 game->player = board_from_FEN(game->initial_board, info_value);
1042 }
1043 break;
1044 }
1045 } else if (isdigit(c)) {
1046 switch(state) {
1047 case STATE_BEGIN_SCORE:
1048 score[1] = score[1] * 10 + (c - '0');
1049 break;
1050 case STATE_END_INFO:
1051 case STATE_END_MOVE:
1052 state = STATE_BEGIN_MOVE_N;
1053 n = c - '0';
1054 break;
1055 case STATE_BEGIN_MOVE_N:
1056 n = 10 * n + (c - '0');
1057 break;
1058 case STATE_BEGIN_MOVE:
1059 state = STATE_END_MOVE;
1060 move[k++] = c;
1061 game->move[i] = string_to_coordinate(move);
1062 game->hash ^= hash_move[(int)game->move[i]][i];
1063 i++;
1064 break;
1065 case STATE_BEGIN_INFO:
1066 if (j >= info_size) warn("info tag too long, will be truncated.");
1067 else info_tag[j++] = c;
1068 break;
1069 case STATE_BEGIN_VALUE:
1070 if (j >= info_size) warn("info value too long, will be truncated.");
1071 else info_value[j++] = c;
1072 break;
1073 default:
1074 warn("unexpected digit %c", c);
1075 break;
1076 }
1077 } else if (c == '*') {
1078 switch(state) {
1079 case STATE_END_MOVE:
1080 state = STATE_BEGIN_SCORE;
1081 score[0] = score[1] = -SCORE_INF;
1082 warn("uncomplete game.");
1083 break;
1084 case STATE_BEGIN_VALUE:
1085 if (j >= info_size) warn("info value too long, will be truncated.");
1086 else info_value[j++] = c;
1087 break;
1088 default:
1089 warn("unexpected '*' %d", state);
1090 break;
1091 }
1092 } else if (c == '.') {
1093 switch(state) {
1094 case STATE_BEGIN_MOVE_N:
1095 state = STATE_END_MOVE_N;
1096 break;
1097 case STATE_END_MOVE_N:
1098 break;
1099 case STATE_BEGIN_INFO:
1100 if (j >= info_size) warn("info tag too long, will be truncated.");
1101 else info_tag[j++] = c;
1102 break;
1103 case STATE_BEGIN_VALUE:
1104 if (j >= info_size) warn("info value too long, will be truncated.");
1105 else info_value[j++] = c;
1106 break;
1107 default:
1108 warn("unexpected '.'");
1109 break;
1110 }
1111 } else if (c == '-') {
1112 switch(state) {
1113 case STATE_BEGIN_MOVE_N:
1114 state = STATE_BEGIN_SCORE;
1115 score[0] = n;
1116 break;
1117 case STATE_BEGIN_INFO:
1118 if (j >= info_size) warn("info tag too long, will be truncated.");
1119 else info_tag[j++] = c;
1120 break;
1121 case STATE_BEGIN_VALUE:
1122 if (j >= info_size) warn("info value too long, will be truncated.");
1123 else info_value[j++] = c;
1124 break;
1125 case STATE_END_MOVE_N:
1126 case STATE_END_MOVE:
1127 break;
1128 default:
1129 warn("unexpected '-'");
1130 break;
1131 }
1132 } else if (isalpha(c) || c == '@') {
1133 switch(state) {
1134 case STATE_END_MOVE_N:
1135 case STATE_END_MOVE:
1136 state = STATE_BEGIN_MOVE;
1137 k = 0;
1138 move[k++] = c;
1139 break;
1140 case STATE_BEGIN_MOVE:
1141 if (k < 4) move[k++] = c;
1142 else warn("unexpected %c", c);
1143 break;
1144 case STATE_BEGIN_INFO:
1145 if (j >= info_size) warn("info tag too long, will be truncated.");
1146 else info_tag[j++] = c;
1147 break;
1148 case STATE_BEGIN_VALUE:
1149 if (j >= info_size) warn("info value too long, will be truncated.");
1150 else info_value[j++] = c;
1151 break;
1152 default:
1153 warn("unexpected %c", c);
1154 break;
1155 }
1156 } else if (isspace(c)) {
1157 switch(state) {
1158 case STATE_BEGIN_SCORE:
1159 case STATE_END_SCORE:
1160 state = STATE_END_SCORE;
1161 break;
1162 case STATE_BEGIN_INFO:
1163 if (j >= info_size) warn("info tag too long, will be truncated.");
1164 else info_tag[j++] = c;
1165 break;
1166 case STATE_BEGIN_VALUE:
1167 if (j >= info_size) warn("info value too long, will be truncated.");
1168 else info_value[j++] = c;
1169 break;
1170 default:
1171 break;
1172 }
1173 } else {
1174 switch(state) {
1175 case STATE_BEGIN_INFO:
1176 if (j >= info_size) warn("info tag too long, will be truncated.");
1177 else info_tag[j++] = c;
1178 break;
1179 case STATE_BEGIN_VALUE:
1180 if (j >= info_size) warn("info value too long, will be truncated.");
1181 else info_value[j++] = c;
1182 break;
1183 default:
1184 warn("unexpected %c", c);
1185 break;
1186 }
1187 }
1188
1189 }
1190
1191 if (!game_check(game)) {
1192 warn("error while importing a PGN game\n");
1193 }
1194 return;
1195}
1196
1203void game_export_pgn(const Game *game, FILE *f)
1204{
1205 time_t t = time(NULL);
1206 struct tm *date = localtime(&t);
1207 int half_score = game_score(game) / 2;
1208 const char *result = half_score < -32 ? "*" : (half_score < 0 ? "0-1" : (half_score > 0 ? "1-0" : "1/2-1/2"));
1209 const char *winner = (half_score < 0 ? game->name[WHITE]: (half_score > 0 ? game->name[BLACK] : NULL));
1210 Board board[1];
1211 char s[80];
1212 int i, j, k;
1213 int player;
1214
1215 board_init(board);
1216
1217 fputs("[Event \"?\"]\n", f);
1218 fputs("[Site \"edax\"]\n", f);
1219 if (game->date.year == 0) fprintf(f, "[Date \"%d.??.??\"]\n", date->tm_year + 1900);
1220 else if (game->date.month == 0) fprintf(f, "[Date \"%d.??.??\"]\n", game->date.year);
1221 else if (game->date.day == 0) fprintf(f, "[Date \"%d.%d.??\"]\n", game->date.year, game->date.month);
1222 fprintf(f, "[Date \"%d.%d.%d\"]\n", game->date.year, game->date.month, game->date.day);
1223 if (game->date.hour >= 0) fprintf(f, "[Time \"%d.%d.%d\"]\n", game->date.hour, game->date.minute, game->date.second);
1224 fputs("[Round \"?\"]\n", f);
1225 fprintf(f, "[Black \"%s\"]\n", game->name[BLACK]);
1226 fprintf(f, "[White \"%s\"]\n", game->name[WHITE]);
1227 fprintf(f, "[Result \"%s\"]\n", result);
1228 if (!board_equal(game->initial_board, board)) {
1229 fprintf(f, "[FEN \"%s\"]\n", board_to_FEN(game->initial_board, game->player, s));
1230 *board = *game->initial_board;
1231 }
1232 fputc('\n', f);
1233
1234 player = game->player;
1235 for (i = j = k = 0; i < 60 && game->move[i] != NOMOVE; ++i, ++k) {
1236 if (!can_move(board->player, board->opponent)) {
1237 s[0] = 'p'; s[1] = 'a'; s[2] = 's'; s[3] = 's'; s[4] = '\0'; --i;
1238 board_pass(board);
1239 } else if (game_update_board(board, game->move[i])) {
1240 move_to_string(game->move[i], WHITE, s);
1241 }
1242 if ((j >= 78) || (player == game->player && j >= 74)) {
1243 fputc('\n', f);
1244 j = 0;
1245 } else {
1246 fputc(' ', f);
1247 ++j;
1248 }
1249 if (player == game->player) j += fprintf(f, "%d. ", (k >> 1) + 1);
1250 fputs(s, f); j += 2;
1251 player = !player;
1252 }
1253 if (winner) fprintf(f, "\n{%s wins %d-%d}", winner, 32 + half_score, 32 - half_score);
1254 else if (half_score == 0) fprintf(f, "\n{Draw 32-32}");
1255 fprintf(f, " %s\n\n\n", result);
1256}
1257
1264void game_export_eps(const Game *game, FILE *f)
1265{
1266 time_t t = time(NULL);
1267 struct tm *date = localtime(&t);
1268 Board board[1];
1269 int i, color, player;
1270 char s_player[2][8] = {"black", "white"};
1271 char s[8];
1272
1273 fputs("%!PS-Adobe-3.0 EPSF-3.0\n",f);
1274 fputs("%%Creator: Edax-3.0\n",f);
1275 fprintf(f, "%%%%CreationDate: %d/%d/%d %d:%d:%d\n", date->tm_year + 1900, date->tm_mon + 1, date->tm_mday, date->tm_hour, date->tm_min, date->tm_sec);
1276 fputs("%%BoundingBox: 0 0 200 200\n\n",f);
1277 fputs("%%BeginProlog\n\n",f);
1278 fputs("% othello coordinates\n",f);
1279 fputs("/A1 {40 160} def /A2 {40 140} def /A3 {40 120} def /A4 {40 100} def /A5 {40 80} def /A6 {40 60} def /A7 {40 40} def /A8 {40 20} def\n",f);
1280 fputs("/B1 {60 160} def /B2 {60 140} def /B3 {60 120} def /B4 {60 100} def /B5 {60 80} def /B6 {60 60} def /B7 {60 40} def /B8 {60 20} def\n",f);
1281 fputs("/C1 {80 160} def /C2 {80 140} def /C3 {80 120} def /C4 {80 100} def /C5 {80 80} def /C6 {80 60} def /C7 {80 40} def /C8 {80 20} def\n",f);
1282 fputs("/D1 {100 160} def /D2 {100 140} def /D3 {100 120} def /D4 {100 100} def /D5 {100 80} def /D6 {100 60} def /D7 {100 40} def /D8 {100 20} def\n",f);
1283 fputs("/E1 {120 160} def /E2 {120 140} def /E3 {120 120} def /E4 {120 100} def /E5 {120 80} def /E6 {120 60} def /E7 {120 40} def /E8 {120 20} def\n",f);
1284 fputs("/F1 {140 160} def /F2 {140 140} def /F3 {140 120} def /F4 {140 100} def /F5 {140 80} def /F6 {140 60} def /F7 {140 40} def /F8 {140 20} def\n",f);
1285 fputs("/G1 {160 160} def /G2 {160 140} def /G3 {160 120} def /G4 {160 100} def /G5 {160 80} def /G6 {160 60} def /G7 {160 40} def /G8 {160 20} def\n",f);
1286 fputs("/H1 {180 160} def /H2 {180 140} def /H3 {180 120} def /H4 {180 100} def /H5 {180 80} def /H6 {180 60} def /H7 {180 40} def /H8 {180 20} def\n\n",f);
1287 fputs("% draw a black disc\n",f);
1288 fputs("/disc_black{\n",f);
1289 fputs("\tnewpath\n",f);
1290 fputs("\t8.5 0 360 arc\n",f);
1291 fputs("\tfill\n",f);
1292 fputs("} def\n\n",f);
1293 fputs("% draw a white disc\n",f);
1294 fputs("/disc_white{\n",f);
1295 fputs("\tnewpath\n",f);
1296 fputs("\t0.5 setlinewidth\n",f);
1297 fputs("\t8.5 0 360 arc\n",f);
1298 fputs("\tstroke\n",f);
1299 fputs("} def\n\n",f);
1300 fputs("% draw a black move\n",f);
1301 fputs("/move_black{\n",f);
1302 fputs("\t/y exch def\n",f);
1303 fputs("\t/x exch def\n",f);
1304 fputs("\tnewpath\n",f);
1305 fputs("\tx y 8.5 0 360 arc\n",f);
1306 fputs("\tfill\n",f);
1307 fputs("\t1 setgray\n",f);
1308 fputs("\tx y moveto dup stringwidth pop 2 div neg -4.5 rmoveto\n",f);
1309 fputs("\tshow\n",f);
1310 fputs("\t0 setgray\n",f);
1311 fputs("} def\n\n",f);
1312 fputs("% draw a white move\n",f);
1313 fputs("/move_white{\n",f);
1314 fputs("\t/y exch def\n",f);
1315 fputs("\t/x exch def\n",f);
1316 fputs("\tnewpath\n",f);
1317 fputs("\t0.5 setlinewidth\n",f);
1318 fputs("\tx y 8.5 0 360 arc\n",f);
1319 fputs("\tstroke\n",f);
1320 fputs("\tx y moveto dup stringwidth pop 2 div neg -4.5 rmoveto\n",f);
1321 fputs("\tshow\n",f);
1322 fputs("} def\n\n",f);
1323 fputs("% draw the grid\n",f);
1324 fputs("/board_grid{\n",f);
1325 fputs("\tnewpath\n\n",f);
1326 fputs("\t%border\n",f);
1327 fputs("\t1.5 setlinewidth\n",f);
1328 fputs("\t 27 7 moveto\n",f);
1329 fputs("\t 166 0 rlineto\n",f);
1330 fputs("\t 0 166 rlineto\n",f);
1331 fputs("\t-166 0 rlineto\n",f);
1332 fputs("\tclosepath\n",f);
1333 fputs("\tstroke\n\n",f);
1334 fputs("\t%vertical lines\n",f);
1335 fputs("\t0.5 setlinewidth\n",f);
1336 fputs("\t30 10 moveto\n",f);
1337 fputs("\t0 1 8{\n",f);
1338 fputs("\t\t 0 160 rlineto\n",f);
1339 fputs("\t\t20 -160 rmoveto\n",f);
1340 fputs("\t}for\n\n",f);
1341 fputs("\t%horizontal lines\n",f);
1342 fputs("\t30 10 moveto\n",f);
1343 fputs("\t0 1 8{\n",f);
1344 fputs("\t\t 160 0 rlineto\n",f);
1345 fputs("\t\t-160 20 rmoveto\n",f);
1346 fputs("\t}for\n",f);
1347 fputs("\tstroke\n\n",f);
1348 fputs("\t%marks\n",f);
1349 fputs("\t 70 50 2 0 360 arc fill\n",f);
1350 fputs("\t150 50 2 0 360 arc fill\n",f);
1351 fputs("\t 70 130 2 0 360 arc fill\n",f);
1352 fputs("\t150 130 2 0 360 arc fill\n",f);
1353 fputs("}def\n\n",f);
1354 fputs("% draw coordinates\n",f);
1355 fputs("/board_coord{\n",f);
1356 fputs("\t/NewCenturySchoolbook-Roman findfont 15 scalefont setfont\n",f);
1357 fputs("\tnewpath\n",f);
1358 fputs("\t(a) 35 180 moveto show\n",f);
1359 fputs("\t(b) 55 180 moveto show\n",f);
1360 fputs("\t(c) 75 180 moveto show\n",f);
1361 fputs("\t(d) 95 180 moveto show\n",f);
1362 fputs("\t(e) 115 180 moveto show\n",f);
1363 fputs("\t(f) 135 180 moveto show\n",f);
1364 fputs("\t(g) 155 180 moveto show\n",f);
1365 fputs("\t(h) 175 180 moveto show\n",f);
1366 fputs("\t(1) 14 155 moveto show\n",f);
1367 fputs("\t(2) 14 135 moveto show\n",f);
1368 fputs("\t(3) 14 115 moveto show\n",f);
1369 fputs("\t(4) 14 95 moveto show\n",f);
1370 fputs("\t(5) 14 75 moveto show\n",f);
1371 fputs("\t(6) 14 55 moveto show\n",f);
1372 fputs("\t(7) 14 35 moveto show\n",f);
1373 fputs("\t(8) 14 15 moveto show\n",f);
1374 fputs("}def\n",f);
1375 fputs("%%EndProlog\n\n",f);
1376
1377 fputs("% do the drawing\n",f);
1378 fputs("gsave\n",f);
1379 fputs("\n\t% draw an empty board\n",f);
1380 fputs("\tboard_coord\n",f);
1381 fputs("\tboard_grid\n",f);
1382 fputs("\n\t% draw the discs\n",f);
1383
1384 *board = *game->initial_board;
1385 for (i = A1; i <= H8; i++) {
1386 color = board_get_square_color(board, i);
1387 if (color != EMPTY) {
1388 if (game->player == WHITE) color = !color;
1389 fprintf(f, "\t%s disc_%s\n", move_to_string(i, 0, s), s_player[color]);
1390 }
1391 }
1392
1393 fputs("\n\t% draw the moves\n",f);
1394 fputs("\t/Utopia-Bold findfont 12 scalefont setfont\n",f);
1395 player = game->player;
1396 for (i = 0; i < 60 && game->move[i] != NOMOVE; ++i) {
1397 if (!can_move(board->player, board->opponent)) {
1398 player = !player;
1399 }
1400 if (game_update_board(board, game->move[i])) {
1401 fprintf(f, "\t(%d) %s move_%s\n", i + 1, move_to_string(game->move[i], BLACK, s), s_player[player]);
1402 player = !player;
1403 }
1404 }
1405 fputc('\n',f);
1406 fputs("grestore\n",f);
1407}
1408
1409void game_export_svg(const Game *game, FILE *f)
1410{
1411 int i, color, player;
1412 char s_color[2][8] = {"black", "white"};
1413 Board board[1];
1414 const char *style = "font-size:22px;text-align:center;text-anchor:middle;font-family:Times New Roman;font-weight:bold";
1415
1416 // prolog
1417 fputs("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n", f);
1418 fputs("<svg\n", f);
1419 fputs("\txmlns=\"http://www.w3.org/2000/svg\"\n", f);
1420 fputs("\tversion=\"1.1\"\n", f);
1421 fputs("\twidth=\"440\"\n", f);
1422 fputs("\theight=\"440\">\n", f);
1423 fputs("\t<desc>Othello Game</desc>\n", f);
1424
1425 // board
1426 fputs("\t<rect\n", f);
1427 fputs("\t\twidth=\"332\" height=\"332\" ", f);
1428 fputs("x=\"54\" y=\"54\" ", f);
1429 fputs("stroke=\"black\" ", f);
1430 fputs("stroke-width=\"2\" ", f);
1431 fputs("fill=\"white\" />\n", f);
1432 fputs("\t<rect\n", f);
1433 fputs("\t\twidth=\"320\" height=\"320\" ", f);
1434 fputs("x=\"60\" y=\"60\" ", f);
1435 fputs("stroke=\"black\" ", f);
1436 fputs("fill=\"green\" />\n", f);
1437 for (i = 1; i < 8; ++i) {
1438 fputs("\t<line\n", f);
1439 fprintf(f, "\t\tx1=\"60\" y1=\"%d\" ", 60 + 40 * i);
1440 fprintf(f, "x2=\"380\" y2=\"%d\" ", 60 + 40 * i);
1441 fputs("stroke=\"black\" />\n", f);
1442 fputs("\t<line\n", f);
1443 fprintf(f, "\t\tx1=\"%d\" y1=\"60\" ", 60 + 40 * i);
1444 fprintf(f, "x2=\"%d\" y2=\"380\" ", 60 + 40 * i);
1445 fputs("stroke=\"black\" />\n", f);
1446 }
1447 fputs("\t<circle cx=\"140\" cy=\"140\" r=\"4\" fill=\"black\" />\n", f);
1448 fputs("\t<circle cx=\"300\" cy=\"140\" r=\"4\" fill=\"black\" />\n", f);
1449 fputs("\t<circle cx=\"140\" cy=\"300\" r=\"4\" fill=\"black\" />\n", f);
1450 fputs("\t<circle cx=\"300\" cy=\"300\" r=\"4\" fill=\"black\" />\n", f);
1451
1452 // coordinates
1453 for (i = 0; i < 8; ++i) {
1454 fprintf(f, "\t<text x=\"%d\" y=\"%d\" style = \"%s\" > %d </text>\n", 40, 85 + i * 40, style, i + 1);
1455 fprintf(f, "\t<text x=\"%d\" y=\"%d\" style = \"%s\" > %c </text>\n", 80 + i * 40, 50, style, i + 'a');
1456 }
1457
1458 // discs
1459 for (i = A1; i <= H8; i++) {
1460 color = board_get_square_color(game->initial_board, i);
1461 if (color != EMPTY) {
1462 if (game->player == WHITE) color = !color;
1463 fprintf(f, "\t<circle cx=\"%d\" cy=\"%d\" r=\"17\" fill=\"%s\" stroke=\"%s\" />\n",
1464 80 + 40 * (i % 8), 80 + 40 * (i / 8), s_color[color], s_color[!color]);
1465 }
1466 }
1467
1468 // moves
1469 *board = *game->initial_board;
1470 player = game->player;
1471 for (i = 0; i < 60 && game->move[i] != NOMOVE; ++i) {
1472 if (!can_move(board->player, board->opponent)) {
1473 player = !player;
1474 }
1475 if (game_update_board(board, game->move[i])) {
1476 fprintf(f, "\t<circle cx=\"%d\" cy=\"%d\" r=\"17\" fill=\"%s\" stroke=\"%s\" />\n",
1477 80 + 40 * (game->move[i] % 8), 80 + 40 * (game->move[i] / 8), s_color[player], s_color[!player]);
1478 player = !player;
1479 fprintf(f, "\t<text x=\"%d\" y=\"%d\" fill=\"%s\" style=\"%s\"> %d </text>\n",
1480 83 + 40 * (game->move[i] % 8), 87 + 40 * (game->move[i] / 8), s_color[player], style, i + 1);
1481 }
1482 }
1483 fputc('\n',f);
1484
1485 // end
1486 fputs("</svg>\n", f);
1487}
1488
1489
1497void game_rand(Game *game, int n_ply, Random *r)
1498{
1499 Move move[1];
1500 unsigned long long moves;
1501 int ply;
1502 Board board[1];
1503
1504 game_init(game);
1505 board_init(board);
1506 for (ply = 0; ply < n_ply; ply++) {
1507 moves = get_moves(board->player, board->opponent);
1508 if (!moves) {
1509 board_pass(board);
1510 moves = get_moves(board->player, board->opponent);
1511 if (!moves) {
1512 break;
1513 }
1514 }
1515 ;
1516 board_get_move(board, get_rand_bit(moves, r), move);
1517 game->move[ply] = move->x;
1518 board_update(board, move);
1519 }
1520}
1521
1532int game_analyze(Game *game, Search *search, const int n_empties, const bool apply_correction)
1533{
1534 Board board[1];
1535 struct {
1536 Move played;
1537 Move best;
1538 Line pv[1];
1539 int n_empties;
1540 } stack[99];
1541 int n_error = 0;
1542 int n_move;
1543 const int verbosity = search->options.verbosity;
1544 int player;
1545 int score;
1546 int i;
1547
1548 search->options.verbosity = 0;
1549 search_cleanup(search);
1550 *board = *game->initial_board;
1551 player = game->player;
1552 for (i = n_move = 0; i < 60 && game->move[i] != NOMOVE; ++i) {
1553 if (!can_move(board->player, board->opponent)) {
1554 stack[n_move].best = MOVE_INIT;
1555 line_init(stack[n_move].pv, player);
1556 stack[n_move++].played = MOVE_PASS;
1557 board_pass(board);
1558 player = !player;
1559 }
1560 if (!board_is_occupied(board, game->move[i]) && board_get_move(board, game->move[i], &stack[n_move].played)) {
1561 stack[n_move].best = MOVE_INIT;
1562 line_init(stack[n_move].pv, player);
1563 search_set_board(search, board, player);
1564 search_set_level(search, 60, search->n_empties);
1565 stack[n_move].n_empties = search->n_empties;
1566 if (search->movelist->n_moves > 1 && search->n_empties <= n_empties) {
1567 movelist_exclude(search->movelist, game->move[i]);
1568 search_run(search);
1569 stack[n_move].best = *(movelist_first(search->movelist));
1570 *stack[n_move].pv = *search->result->pv;
1571 }
1572 board_update(board, &stack[n_move].played);
1573 player = !player;
1574 ++n_move;
1575 } else {
1576 char s[4];
1577 warn("\nillegal move %s in game:\n", move_to_string(game->move[i], player, s));
1578 game_export_text(game, stderr);
1579 board_print(board, player, stderr);
1580 fprintf(stderr, "\n\n");
1581 return 1; // stop, illegal moves
1582 }
1583 }
1584
1585 search_set_board(search, board, player);
1586 if (search->n_empties <= n_empties) {
1587 search_set_level(search, 60, search->n_empties);
1588 search_run(search);
1589 score = search->result->score;
1590
1591 for (i = n_move - 1; stack[i].n_empties <= n_empties; --i) {
1592 stack[i].played.score = -score;
1593 score = MAX(stack[i].played.score, stack[i].best.score);
1594 }
1595
1596 //backpropagate the score
1597 while (stack[--n_move].n_empties <= n_empties) {
1598 if (stack[n_move].played.score < stack[n_move].best.score) {
1599 ++n_error;
1600 // correct the move?
1601 if (apply_correction && stack[n_move].best.x != NOMOVE) {
1602 for (i = 0; i < 60 && game->move[i] != 0; ++i) {
1603 if (game->move[i] == stack[n_move].played.x) {
1604 game_append_line(game, stack[n_move].pv, i);
1605 }
1606 }
1607 }
1608 }
1609 }
1610 }
1611
1612 search->options.verbosity = verbosity;
1613
1614 return n_error;
1615}
1616
1625int game_complete(Game *game, Search *search)
1626{
1627 Board board[1];
1628 const int verbosity = search->options.verbosity;
1629 int i, n;
1630 int player;
1631
1632 search->options.verbosity = 0;
1633 search_cleanup(search);
1634
1635 player = game->player;
1636 for (n = 0; n < 60; ++n) {
1637 *board = *game->initial_board;
1638 for (i = 0; i < 60 && game->move[i] != NOMOVE; ++i) {
1639 player ^= game_update_player(board, game->move[i]);
1640 if (!game_update_board(board, game->move[i])) {
1641 break;
1642 }
1643 }
1644
1645 if (!can_move(board->player, board->opponent)) {
1646 if (!can_move(board->opponent, board->player)) break;
1647 player ^= 1;
1648 board_pass(board);
1649 }
1650
1651 search_set_board(search, board, player);
1652 search_run(search);
1653 if (search->result->depth == search->n_empties && search->result->selectivity == NO_SELECTIVITY) {
1654 game_append_line(game, search->result->pv, i);
1655 } else {
1656 game->move[i] = search->result->move;
1657 }
1658 if (search->result->score != 0) {
1659 putchar('\n'); search->observer(search->result);
1660 }
1661 }
1662
1663 search->options.verbosity = verbosity;
1664
1665 return n;
1666}
1667
DLL_API int bit_count(unsigned long long b)
Count the number of bits set to one in an unsigned long long.
Definition bit.c:72
int get_rand_bit(unsigned long long b, Random *r)
Get a random set bit index.
Definition bit.c:415
#define x_to_bit(x)
Definition bit.h:43
bool board_is_game_over(const Board *board)
Check if the game is over.
Definition board.c:1203
void board_print(const Board *board, const int player, FILE *f)
Print out the board.
Definition board.c:1230
void board_update(Board *board, const Move *move)
Update a board.
Definition board.c:469
unsigned long long board_get_move(const Board *board, const int x, Move *move)
Compute a move.
Definition board.c:438
char * board_to_FEN(const Board *board, const int player, char *string)
print to FEN description.
Definition board.c:1312
int board_get_square_color(const Board *board, const int x)
Get square color.
Definition board.c:1168
void board_init(Board *board)
Set a board to the starting position.
Definition board.c:280
char * board_to_string(const Board *board, const int player, char *s)
convert the to a compact string.
Definition board.c:1272
bool board_equal(const Board *b1, const Board *b2)
Compare two board for equality.
Definition board.c:335
DLL_API unsigned long long get_moves(const unsigned long long P, const unsigned long long O)
Get legal moves.
Definition board.c:621
DLL_API bool can_move(const unsigned long long P, const unsigned long long O)
Check if a player can move.
Definition board.c:797
int board_set(Board *board, const char *string)
Set a board from a string description.
Definition board.c:154
void board_pass(Board *board)
Passing move.
Definition board.c:503
bool board_is_occupied(const Board *board, const int x)
Check if a square is occupied.
Definition board.c:1180
int board_from_FEN(Board *board, const char *string)
Set a board from a string description.
Definition board.c:212
#define SCORE_INF
Definition const.h:52
@ B3
Definition const.h:31
@ D7
Definition const.h:35
@ PASS
Definition const.h:37
@ B6
Definition const.h:34
@ F3
Definition const.h:31
@ NOMOVE
Definition const.h:37
@ E8
Definition const.h:36
@ E6
Definition const.h:34
@ C4
Definition const.h:32
@ A6
Definition const.h:34
@ F5
Definition const.h:33
@ C5
Definition const.h:33
@ D1
Definition const.h:29
@ H4
Definition const.h:32
@ G5
Definition const.h:33
@ B8
Definition const.h:36
@ E7
Definition const.h:35
@ E3
Definition const.h:31
@ A2
Definition const.h:30
@ A3
Definition const.h:31
@ C7
Definition const.h:35
@ H5
Definition const.h:33
@ B7
Definition const.h:35
@ F1
Definition const.h:29
@ C2
Definition const.h:30
@ C8
Definition const.h:36
@ G6
Definition const.h:34
@ B4
Definition const.h:32
@ F7
Definition const.h:35
@ A1
Definition const.h:29
@ A7
Definition const.h:35
@ H1
Definition const.h:29
@ D2
Definition const.h:30
@ F4
Definition const.h:32
@ G3
Definition const.h:31
@ B2
Definition const.h:30
@ G8
Definition const.h:36
@ F6
Definition const.h:34
@ F2
Definition const.h:30
@ H6
Definition const.h:34
@ A5
Definition const.h:33
@ G1
Definition const.h:29
@ E1
Definition const.h:29
@ H7
Definition const.h:35
@ H3
Definition const.h:31
@ D6
Definition const.h:34
@ H2
Definition const.h:30
@ F8
Definition const.h:36
@ E2
Definition const.h:30
@ B1
Definition const.h:29
@ A4
Definition const.h:32
@ C3
Definition const.h:31
@ H8
Definition const.h:36
@ D3
Definition const.h:31
@ C6
Definition const.h:34
@ G7
Definition const.h:35
@ C1
Definition const.h:29
@ D8
Definition const.h:36
@ G2
Definition const.h:30
@ G4
Definition const.h:32
@ B5
Definition const.h:33
@ A8
Definition const.h:36
#define VERSION_STRING
Definition const.h:88
@ WHITE
Definition const.h:43
@ EMPTY
Definition const.h:44
@ BLACK
Definition const.h:42
#define SCORE_MIN
Definition const.h:55
static int move_to_wthor(int x)
Coordinates conversion from edax to wthor.
Definition game.c:49
@ PARSE_INVALID_VALUE
Definition game.c:29
@ PARSE_END_OF_FILE
Definition game.c:27
@ PARSE_INVALID_TAG
Definition game.c:28
@ PARSE_OK
Definition game.c:26
void game_export_ggf(const Game *game, FILE *f)
Write a game to the Generic Game Format (ggf) file.
Definition game.c:713
void game_import_text(Game *game, FILE *f)
Read a game from a text file.
Definition game.c:451
void game_read(Game *game, FILE *f)
Read a game from a binary file.
Definition game.c:429
int game_analyze(Game *game, Search *search, const int n_empties, const bool apply_correction)
Analyze an endgame.
Definition game.c:1532
bool game_check(Game *game)
Check a game.
Definition game.c:213
static bool game_update_player(Board *board, int x)
update a player.
Definition game.c:171
int game_complete(Game *game, Search *search)
Terminate an unfinished game.
Definition game.c:1625
char * parse_ggf(Game *game, const char *string)
Parse a ggf game from a string.
Definition game.c:664
bool game_update_board(Board *board, int x)
update a board.
Definition game.c:153
void game_export_sgf(const Game *game, FILE *f)
Definition game.c:944
void wthor_to_game(const WthorGame *thor, Game *game)
convert a Wthor game to a Game.
Definition game.c:340
void game_import_ggf(Game *game, FILE *f)
Read a game from the Generic Game Format (ggf) file.
Definition game.c:582
void game_import_oko(Game *game, FILE *f)
Read a game from the "allinf.oko" file.
Definition game.c:513
static int game_parse_sgf(FILE *f, char *tag, char *value)
Parse a Smart Game Format (sgf) game.
Definition game.c:762
void game_save_sgf(const Game *game, FILE *f, const bool multiline)
Write a game to the Generic Game Format (ggf) file.
Definition game.c:870
bool game_equals(const Game *game_1, const Game *game_2)
Test if two games are equal.
Definition game.c:114
void game_import_wthor(Game *game, FILE *f)
Read a game from a Wthor file.
Definition game.c:487
void game_rand(Game *game, int n_ply, Random *r)
Fill a game with some random moves.
Definition game.c:1497
void game_export_text(const Game *game, FILE *f)
Write a game to a text file.
Definition game.c:467
void game_export_svg(const Game *game, FILE *f)
Definition game.c:1409
void game_copy(Game *dest, const Game *src)
Game copy.
Definition game.c:103
static int game_parse_ggf(FILE *f, char *tag, char *value)
Parse a ggf game.
Definition game.c:529
void game_init(Game *game)
Create an empty game.
Definition game.c:83
void game_import_pgn(Game *game, FILE *f)
Read a game from a pgn file.
Definition game.c:955
void game_to_text(const Game *game, char *line)
Convert game to a text (ascii).
Definition game.c:294
void line_to_game(const Board *initial_board, const Line *line, Game *game)
Build a game from an initial position and a move sequence.
Definition game.c:415
void text_to_game(const char *line, Game *game)
Convert a text (ascii) game to a Game.
Definition game.c:267
void game_append_line(Game *game, const Line *line, const int from)
Build a game from an initial position and a move sequence.
Definition game.c:388
void game_export_wthor(const Game *game, FILE *f)
Write a game to a Wthor file.
Definition game.c:500
void game_to_wthor(const Game *game, WthorGame *thor)
convert a Game to a Whor game.
Definition game.c:366
static const char * parse_tag(const char *string, char *tag, char *value)
Parse a Tag/value ggf pair from a string.
Definition game.c:632
static int move_from_oko(int x)
Coordinates conversion from oko.
Definition game.c:62
void game_import_sgf(Game *game, FILE *f)
Read a game from a sgf file.
Definition game.c:823
void game_export_eps(const Game *game, FILE *f)
Write a game to an eps file.
Definition game.c:1264
void game_write(const Game *game, FILE *f)
Write a game to a binary file.
Definition game.c:440
void game_export_pgn(const Game *game, FILE *f)
Write a game to a pgn file.
Definition game.c:1203
void oko_to_game(const OkoGame *oko, Game *game)
convert an allinf.oko game to a Game.
Definition game.c:313
bool game_get_board(const Game *game, const int ply, Board *board)
Get the board after 'ply' move.
Definition game.c:195
int game_score(const Game *game)
Compute the final score of the game, for the initial player.
Definition game.c:233
bool wthor_equals(const WthorGame *game_1, const WthorGame *game_2)
Test if two Wthor games are equal.
Definition game.c:136
int move_from_wthor(int x)
Coordinates conversion from wthor to edax.
Definition game.c:38
unsigned long long hash_move[64][60]
Definition hash-lock-free.c:44
const Move MOVE_PASS
Definition move.c:26
Move * movelist_first(MoveList *movelist)
Return the first move of the list.
Definition move.c:422
void line_init(Line *line, const int player)
Initialize a sequence of moves.
Definition move.c:549
Move * movelist_exclude(MoveList *movelist, const int move)
Exclude a move.
Definition move.c:516
const Move MOVE_INIT
Definition move.c:25
char * move_to_string(const int x, const int player, char *s)
Print out a move.
Definition move.c:76
void * search_run(void *v)
Search the bestmove of a given board.
Definition root.c:810
void search_set_level(Search *search, const int level, const int n_empties)
Set the search level.
Definition search.c:609
const int NO_SELECTIVITY
Definition search.c:94
void search_cleanup(Search *search)
Clean-up some search data.
Definition search.c:578
void search_set_board(Search *search, const Board *board, const int player)
Set the board to analyze.
Definition search.c:593
Definition board.h:26
unsigned long long player
Definition board.h:27
unsigned long long opponent
Definition board.h:27
Definition game.h:22
char move[60]
Definition game.h:33
signed char second
Definition game.h:30
signed char day
Definition game.h:27
struct Game::@14 date
signed char month
Definition game.h:26
char name[2][32]
Definition game.h:32
unsigned long long hash
Definition game.h:35
Board initial_board[1]
Definition game.h:23
signed char minute
Definition game.h:29
short year
Definition game.h:25
signed char hour
Definition game.h:28
char player
Definition game.h:34
Definition move.h:35
int n_moves
Definition move.h:37
char move[GAME_SIZE]
Definition move.h:36
int color
Definition move.h:38
int n_moves
Definition move.h:31
Definition move.h:20
int x
Definition move.h:22
Definition game.h:44
char move[61]
Definition game.h:48
Definition util.h:87
int move
Definition search.h:44
int score
Definition search.h:45
int selectivity
Definition search.h:43
Line pv[1]
Definition search.h:47
int depth
Definition search.h:42
Definition search.h:95
int n_empties
Definition search.h:99
void(* observer)(Result *)
Definition search.h:153
MoveList movelist[1]
Definition search.h:132
Result * result
Definition search.h:151
struct Search::@25 options
int verbosity
Definition search.h:142
Definition game.h:38
signed char theoric_score
Definition game.h:40
char x[60]
Definition game.h:41
short tournament
Definition game.h:39
signed char score
Definition game.h:40
short white
Definition game.h:39
short black
Definition game.h:39
char * parse_move(const char *string, const Board *board, Move *move)
Parse a move.
Definition util.c:627
int string_to_coordinate(const char *s)
Convert the two first chars of a string into a coordinate.
Definition util.c:384
void string_to_lowercase(char *s)
Change all char of a string to lowercase.
Definition util.c:355
char * string_read_line(FILE *f)
Read a line.
Definition util.c:265
char * parse_skip_spaces(const char *string)
Skip spaces.
Definition util.c:514
Miscellaneous utilities header.
#define warn(...)
Display a warning message as "WARNING : ... ".
Definition util.h:373
#define MAX(a, b)
Definition util.h:98