15 coord_transform(struct board
*b
, coord_t coord
, int i
)
17 #define HASH_VMIRROR 1
18 #define HASH_HMIRROR 2
20 if (i
& HASH_VMIRROR
) {
21 coord
= coord_xy(b
, coord_x(coord
, b
), board_size(b
) - 1 - coord_y(coord
, b
));
23 if (i
& HASH_HMIRROR
) {
24 coord
= coord_xy(b
, board_size(b
) - 1 - coord_x(coord
, b
), coord_y(coord
, b
));
26 if (i
& HASH_XYFLIP
) {
27 coord
= coord_xy(b
, coord_y(coord
, b
), coord_x(coord
, b
));
32 /* Check if we can make a move along the fbook right away.
33 * Otherwise return pass. */
35 fbook_check(struct board
*board
)
37 if (!board
->fbook
) return pass
;
39 hash_t hi
= board
->hash
;
41 while (!is_pass(board
->fbook
->moves
[hi
& fbook_hash_mask
])) {
42 if (board
->fbook
->hashes
[hi
& fbook_hash_mask
] == board
->hash
) {
43 cf
= board
->fbook
->moves
[hi
& fbook_hash_mask
];
50 fprintf(stderr
, "fbook match %"PRIhash
":%"PRIhash
"\n", board
->hash
, board
->hash
& fbook_hash_mask
);
52 /* No match, also prevent further fbook usage
53 * until the next clear_board. */
55 fprintf(stderr
, "fbook out %"PRIhash
":%"PRIhash
"\n", board
->hash
, board
->hash
& fbook_hash_mask
);
56 fbook_done(board
->fbook
);
62 static struct fbook
*fbcache
;
65 fbook_init(char *filename
, struct board
*b
)
67 if (fbcache
&& fbcache
->bsize
== board_size(b
)
68 && fbcache
->handicap
== b
->handicap
)
71 FILE *f
= fopen(filename
, "r");
77 struct fbook
*fbook
= calloc(1, sizeof(*fbook
));
78 fbook
->bsize
= board_size(b
);
79 fbook
->handicap
= b
->handicap
;
80 /* We do not set handicap=1 in case of too low komi on purpose;
81 * we want to go with the no-handicap fbook for now. */
82 for (int i
= 0; i
< 1<<fbook_hash_bits
; i
++)
83 fbook
->moves
[i
] = pass
;
86 fprintf(stderr
, "Loading opening fbook %s...\n", filename
);
88 /* Scratch board where we lay out the sequence;
89 * one for each transposition. */
91 for (int i
= 0; i
< 8; i
++) {
92 bs
[i
] = board_init(NULL
);
93 board_resize(bs
[i
], fbook
->bsize
- 2);
97 while (fgets(linebuf
, sizeof(linebuf
), f
)) {
99 linebuf
[strlen(linebuf
) - 1] = 0; // chop
101 /* Format of line is:
102 * BSIZE COORD COORD COORD... | COORD
103 * BSIZE/HANDI COORD COORD COORD... | COORD
104 * We descend up to |, then add the new node
105 * with value minimax(1000), forcing UCT to
106 * always pick that node immediately. */
107 int bsize
= strtol(line
, &line
, 10);
108 if (bsize
!= fbook
->bsize
- 2)
113 handi
= strtol(line
, &line
, 10);
115 if (handi
!= fbook
->handicap
)
117 while (isspace(*line
)) line
++;
119 for (int i
= 0; i
< 8; i
++) {
121 bs
[i
]->last_move
.color
= S_WHITE
;
124 while (*line
!= '|') {
125 coord_t
*c
= str2coord(line
, fbook
->bsize
);
127 for (int i
= 0; i
< 8; i
++) {
128 coord_t coord
= coord_transform(b
, *c
, i
);
129 struct move m
= { .coord
= coord
, .color
= stone_other(bs
[i
]->last_move
.color
) };
130 int ret
= board_play(bs
[i
], &m
);
135 while (!isspace(*line
)) line
++;
136 while (isspace(*line
)) line
++;
140 while (isspace(*line
)) line
++;
142 /* In case of multiple candidates, pick one with
143 * exponentially decreasing likelihood. */
144 while (strchr(line
, ' ') && fast_random(2)) {
145 line
= strchr(line
, ' ');
146 while (isspace(*line
)) line
++;
147 // fprintf(stderr, "<%s> skip to %s\n", linebuf, line);
150 coord_t
*c
= str2coord(line
, fbook
->bsize
);
151 for (int i
= 0; i
< 8; i
++) {
152 coord_t coord
= coord_transform(b
, *c
, i
);
154 char conflict
= is_pass(fbook
->moves
[bs
[i
]->hash
& fbook_hash_mask
]) ? '+' : 'C';
156 for (int j
= 0; j
< i
; j
++)
157 if (bs
[i
]->hash
== bs
[j
]->hash
)
159 if (conflict
== 'C') {
160 hash_t hi
= bs
[i
]->hash
;
161 while (!is_pass(fbook
->moves
[hi
& fbook_hash_mask
]) && fbook
->hashes
[hi
& fbook_hash_mask
] != bs
[i
]->hash
)
163 if (fbook
->hashes
[hi
& fbook_hash_mask
] == bs
[i
]->hash
)
166 fprintf(stderr
, "%c %"PRIhash
":%"PRIhash
" (<%d> %s)\n", conflict
,
167 bs
[i
]->hash
& fbook_hash_mask
, bs
[i
]->hash
, i
, linebuf
);
169 hash_t hi
= bs
[i
]->hash
;
170 while (!is_pass(fbook
->moves
[hi
& fbook_hash_mask
]) && fbook
->hashes
[hi
& fbook_hash_mask
] != bs
[i
]->hash
)
172 fbook
->moves
[hi
& fbook_hash_mask
] = coord
;
173 fbook
->hashes
[hi
& fbook_hash_mask
] = bs
[i
]->hash
;
179 for (int i
= 0; i
< 8; i
++) {
185 if (!fbook
->movecnt
) {
186 /* Empty book is not worth the hassle. */
191 struct fbook
*fbold
= fbcache
;
199 void fbook_done(struct fbook
*fbook
)
201 if (fbook
!= fbcache
)