2
gen_pattern.cc Game Pattern Generator
3
Copyright (c) 2001, 2002, 2003, 2004, 2005 Kriang Lerdsuwanakij
4
email: lerdsuwa@users.sourceforge.net
6
This program is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2 of the License, or
9
(at your option) any later version.
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
16
You should have received a copy of the GNU General Public License
17
along with this program; if not, write to the Free Software
18
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30
#include <sys/types.h>
46
#define _(x) gettext(x)
49
// Grab version number in VERSION variable
50
// Use same version number as main GRhino program
53
#include "scripts/version"
56
const char *prog_name = "gen_pattern";
57
const char *prog_ver = VERSION;
59
struct pattern_state {
62
// Pattern information
63
// pat[PATTERN][MOVE_INDEX][PATTERN_INDEX]
65
// PATTERN = ROW1, ROW2, etc.
66
// MOVE_INDEX = 0, 1, ..., num_move_index-1
67
// PATTERN_INDEX = 0, 1, ... according to
68
// positions of black and white pieces
69
raw_pattern_info ***pat;
70
pattern_state(pattern_t p_, raw_pattern_info ***pat_)
74
/* Calculate score based on
75
b = number of black wins
76
w = number of white wins
77
Result truncated to fit signed char. */
79
signed char log_func(long b, long w)
81
if (b == w) // Special case to avoid round-off problem
84
long a; // Make sure we don't put too high score for case
85
// like win-loss = 1-0
89
a = 1; // Make formula work even when either b or w is zero
93
// Make sure we don't have rounding non-symmetry
95
x = static_cast<long>(10*log(static_cast<double>(b+a)/(w+a)));
97
x = -static_cast<long>(10*log(static_cast<double>(w+a)/(b+a)));
99
// Limit value to fit signed char
104
return static_cast<signed char>(x);
107
void init_file(pattern_t p)
109
// Special marker for all patterns
110
if (p == PATTERN_UNKNOWN) {
111
for (int p = 0; p != PATTERN_UNKNOWN; p++)
112
init_file(static_cast<pattern_t>(p));
116
int handle = creat(get_pattern_file(p), S_IRUSR | S_IWUSR);
119
gtout(bufstr, _("cannot create file %$\n"))
120
<< get_pattern_file(p);
121
throw std::runtime_error(bufstr.str());
124
// Loop for all move indexes
125
raw_pattern_info **pat = new raw_pattern_info *[num_move_index];
126
for (int pos = 0; pos < num_move_index; ++pos) {
127
pat[pos] = new raw_pattern_info[get_pattern_size(p)];
129
// Loop for all pattern indexes
130
for (int i = 0; i < get_pattern_size(p); ++i) {
131
pat[pos][i].black_win = 0;
132
pat[pos][i].white_win = 0;
136
// Loop for all move indexes
137
for (int pos = 0; pos < num_move_index; ++pos) {
139
// Write all pattern indexes
140
int size = sizeof(raw_pattern_info) * get_pattern_size(p);
141
if (write(handle, pat[pos], size) != size) {
145
gtout(bufstr, _("cannot write file %$\n"))
146
<< get_pattern_file(p);
147
throw std::runtime_error(bufstr.str());
151
for (int pos = 0; pos < num_move_index; ++pos) {
159
int num_update[PATTERN_UNKNOWN][num_move_index];
160
int update_list[PATTERN_UNKNOWN][num_move_index][60];
161
int update_move_index;
165
update_move_index = -1;
166
for (int p = 0; p != PATTERN_UNKNOWN; ++p)
167
for (int i = 0; i < num_move_index; ++i)
168
num_update[p][i] = 0;
171
bool find_update(pattern_t p, int move_index, int pos)
173
for (int i = 0; i < num_update[p][move_index]; ++i) {
174
if (pos == update_list[p][move_index][i]) // Already updated
180
void update_info_table(pattern_t p, raw_pattern_info ***pat, int diff,
181
int move_index, int pos1, int pos2, int pos3, int pos4)
183
if (find_update(p, move_index, pos1))
185
update_list[p][move_index][num_update[p][move_index]] = pos1;
186
num_update[p][move_index]++;
187
update_list[p][move_index][num_update[p][move_index]] = pos2;
188
num_update[p][move_index]++;
189
update_list[p][move_index][num_update[p][move_index]] = pos3;
190
num_update[p][move_index]++;
191
update_list[p][move_index][num_update[p][move_index]] = pos4;
192
num_update[p][move_index]++;
197
pat[p][move_index][pos1].black_win++;
199
pat[p][move_index][pos1].white_win++;
202
pat[p][move_index][pos1].black_win++;
203
pat[p][move_index][pos1].white_win++;
207
if (get_pattern_symmetry(p)) {
209
pat[p][move_index][pos2].black_win++;
211
pat[p][move_index][pos2].white_win++;
213
pat[p][move_index][pos2].black_win++;
214
pat[p][move_index][pos2].white_win++;
218
// Need to maintain fairness when
219
// comparing positions during searching
222
pat[p][move_index][pos3].black_win++;
224
pat[p][move_index][pos3].white_win++;
226
pat[p][move_index][pos3].black_win++;
227
pat[p][move_index][pos3].white_win++;
231
if (get_pattern_symmetry(p)) {
233
pat[p][move_index][pos4].black_win++;
235
pat[p][move_index][pos4].white_win++;
237
pat[p][move_index][pos4].black_win++;
238
pat[p][move_index][pos4].white_win++;
243
void update_info(pattern_t p, raw_pattern_info ***pat, byte_board_info *board,
246
// Special marker for all patterns
247
if (p == PATTERN_UNKNOWN) {
248
for (int pp = 0; pp != PATTERN_UNKNOWN; pp++)
249
update_info(static_cast<pattern_t>(pp), pat,
254
int move_index = to_move_index(board->get_num_move());
256
for (int i = 0; i < get_num_pattern(p); ++i) {
258
// Appeared pattern_index
260
for (int j = 0; j < get_pattern_piece(p); ++j) {
261
pos1 += pow_3[j] * to_pattern_index(board->board[
262
static_cast<int>(pattern_data[p].pattern[i][j])]);
265
// Mirrored pattern_index
267
for (int j = 0; j < get_pattern_piece(p); ++j) {
268
pos2 += pow_3[j] * to_pattern_index(board->board[
269
static_cast<int>(pattern_data[p].pattern[i][get_pattern_piece(p)-1-j])]);
272
// Color swapped pattern_index
274
for (int j = 0; j < get_pattern_piece(p); ++j) {
275
pos3 += pow_3[j] * to_pattern_index(-board->board[
276
static_cast<int>(pattern_data[p].pattern[i][j])]);
279
// Mirrored and color swapped pattern_index
281
for (int j = 0; j < get_pattern_piece(p); ++j) {
282
pos4 += pow_3[j] * to_pattern_index(-board->board[
283
static_cast<int>(pattern_data[p].pattern[i][get_pattern_piece(p)-1-j])]);
286
// Update some poorly represented patterns during
287
// early to midgame from late-mid game as well
289
&& (p == PATTERN_ROW1 || p == PATTERN_ROW2
290
|| p == PATTERN_EDGE_X || p == PATTERN_CORNER5X2
291
|| p == PATTERN_DIAG1 || p == PATTERN_DIAG2)) {
293
for (int move_index_ = 0; move_index_ < 8; move_index_++) {
294
update_info_table(p, pat, diff, move_index_, pos1, pos2, pos3, pos4);
298
update_info_table(p, pat, diff, move_index, pos1, pos2, pos3, pos4);
303
void process_game(pattern_state &t, game_log &game)
305
byte_board_info board(game.board);
309
// Now collect pattern info
311
// Loop for all game moves
312
for (int i = 0; i < game.num_move_queue; ++i) {
313
int player = game.move_queue_color[i];
314
int pos = game.move_queue[i];
316
// Dump core upon broken game record
317
if (!board.can_play(player, pos))
318
throw std::runtime_error(_("invalid game moves"));
319
board.place_piece(player, pos);
321
// Update game info using final scores
322
update_info(t.p, t.pat, &board,
323
game.black_score-game.white_score);
327
void load_file(const char *f, pattern_state &t)
330
raw_pattern_info ***pat = t.pat;
332
// Special marker for all patterns
333
if (p == PATTERN_UNKNOWN) {
334
for (int pp = 0; pp != PATTERN_UNKNOWN; pp++) {
335
pattern_state tt(static_cast<pattern_t>(pp), pat);
341
int handle = open(get_pattern_file(p), O_RDONLY);
344
gtout(bufstr, _("cannot open file %$\n"))
345
<< get_pattern_file(p);
346
throw std::runtime_error(bufstr.str());
349
int io_size = sizeof(raw_pattern_info) * get_pattern_size(p);
351
pat[p] = new raw_pattern_info *[num_move_index];
353
// Loop for all move indexes
354
for (int pos = 0; pos < num_move_index; ++pos) {
356
// Read all pattern indexes
357
pat[p][pos] = new raw_pattern_info[get_pattern_size(p)];
358
if (read(handle, pat[p][pos], io_size) != io_size) {
362
gtout(bufstr, _("cannot read file %$\n"))
363
<< get_pattern_file(p);
364
throw std::runtime_error(bufstr.str());
370
void store_file(const char *f, pattern_state &t)
373
raw_pattern_info ***pat = t.pat;
375
// Special marker for all patterns
376
if (p == PATTERN_UNKNOWN) {
377
for (int pp = 0; pp != PATTERN_UNKNOWN; pp++) {
378
pattern_state tt(static_cast<pattern_t>(pp), pat);
384
int io_size = sizeof(raw_pattern_info) * get_pattern_size(p);
386
int handle = creat(get_pattern_file(p), S_IRUSR | S_IWUSR);
389
gtout(bufstr, _("cannot create file %$\n"))
390
<< get_pattern_file(p);
391
throw std::runtime_error(bufstr.str());
394
// Loop for all move indexes
395
for (int pos = 0; pos < num_move_index; ++pos) {
397
// Write all pattern indexes
398
if (write(handle, pat[p][pos], io_size) != io_size) {
402
gtout(bufstr, _("cannot write file %$\n"))
403
<< get_pattern_file(p);
404
throw std::runtime_error(bufstr.str());
411
void generate_file(const char *f, pattern_state &t)
414
raw_pattern_info ***pat = t.pat;
416
// Special marker for all patterns
417
if (p == PATTERN_UNKNOWN) {
418
for (int pp = 0; pp != PATTERN_UNKNOWN; pp++) {
419
pattern_state tt(static_cast<pattern_t>(pp), pat);
420
generate_file(f, tt);
425
int handle = creat(get_pattern_data_file(p), S_IRUSR | S_IWUSR);
428
gtout(bufstr, _("cannot create file %$\n"))
429
<< get_pattern_data_file(p);
430
throw std::runtime_error(bufstr.str());
433
int size = get_pattern_size(p);
434
pattern_info **pat2 = new pattern_info *[num_move_index];
435
for (int pos = 0; pos < num_move_index; ++pos) {
436
pat2[pos] = new pattern_info[size];
437
for (int i = 0; i < size; ++i) {
438
pat2[pos][i] = log_func(
439
pat[p][pos][i].black_win,
440
pat[p][pos][i].white_win);
444
// Set default value according to
446
for (int pos = 1; pos < num_move_index-1; ++pos) {
447
for (int i = 0; i < size; ++i) {
448
if (pat[p][pos][i].black_win + pat[p][pos][i].white_win == 0) {
450
if (p == PATTERN_ROW1) {
451
pat2i += 64 * extract_color(i, 0);
452
pat2i += 64 * extract_color(i, 7);
454
else if (p == PATTERN_DIAG1) {
455
pat2i += 64 * extract_color(i, 0);
456
pat2i += 64 * extract_color(i, 7);
458
else if (p == PATTERN_EDGE_X) {
459
pat2i += 64 * extract_color(i, 1);
460
pat2i += 64 * extract_color(i, 8);
462
else if (p == PATTERN_CORNER5X2) {
463
pat2i += 64 * extract_color(i, 0);
468
else if (pat2i < -127)
471
pat2[pos][i] = pat2i;
477
for (int pos = 1; pos < num_move_index-1; ++pos) {
478
for (int i = 0; i < size; ++i) {
479
if (pat[p][pos][i].black_win + pat[p][pos][i].white_win == 0
480
&& pat2[pos][i] == 0) {
483
while (pos_a > 0 && pat2[pos_a][i] == 0 &&
484
pat[p][pos_a][i].black_win + pat[p][pos_a][i].white_win == 0)
486
while (pos_b < num_move_index-1 && pat2[pos_b][i] == 0 &&
487
pat[p][pos_b][i].black_win + pat[p][pos_b][i].white_win == 0)
490
// Should not suffer symmetry problem during
492
pat2[pos][i] = ((pos-pos_a)*pat2[pos_b][i]
493
+ (pos_b-pos)*pat2[pos_a][i])
500
int comp_size = size/3*2;
501
for (int pos = 0; pos < num_move_index; ++pos) {
503
// Verify table symmetry
504
for (int j = comp_size, k = size/3-1; j < size; ++j, --k) {
505
if (pat2[pos][j] != -pat2[pos][k]) {
506
/* std::cout << "p=" << p << " pos=" << pos << " j=" << j << " k=" << k
507
<< " : " << int(pat2[pos][j]) << ' ' << int(pat2[pos][k]);
511
std::cout << ' ' << pat[p][pos][j].black_win;
512
std::cout << ' ' << pat[p][pos][j].white_win;
513
std::cout << ' ' << pat[p][pos][k].black_win;
514
std::cout << ' ' << pat[p][pos][k].white_win;
516
throw std::runtime_error(_("pattern symmetry error"));
519
if (write(handle, pat2[pos], comp_size) != comp_size) {
523
gtout(bufstr, _("cannot write file %$\n"))
524
<< get_pattern_data_file(p);
525
throw std::runtime_error(bufstr.str());
529
for (int pos = 0; pos < num_move_index; ++pos) {
537
void process_pattern(pattern_t pattern, int argc, char *argv[])
539
bool init_pattern = false;
541
raw_pattern_info ***pat = 0;
543
for (int i = 2; i < argc; ++i) {
544
if (strcmp(argv[i], "init") == 0) {
545
// Create new file with empty
548
init_file(pattern); // Write empty pattern data
549
init_pattern = false; // Force reload
551
else if (strcmp(argv[i], "gen") == 0) {
552
// Generate data file suitable
555
// Pattern data not yet initialized
556
if (init_pattern == false) {
558
pat = new raw_pattern_info **[PATTERN_UNKNOWN];
559
for (int pp = 0; pp != PATTERN_UNKNOWN; pp++)
562
pattern_state t(pattern, pat);
563
if (init_pattern == false) {
564
load_file(argv[i], t); // Only load once
568
generate_file(argv[i], t);
571
// Command line argument is
574
// Pattern data not yet initialized
575
if (init_pattern == false) {
577
pat = new raw_pattern_info **[PATTERN_UNKNOWN];
578
for (int pp = 0; pp != PATTERN_UNKNOWN; pp++)
581
pattern_state t(pattern, pat);
582
if (init_pattern == false) {
583
load_file(argv[i], t); // Only load once
587
process_file<game_log>(argv[i], t);
588
store_file(argv[i], t); // Store after every processed
593
// Free allocated memory
595
for (int pp = 0; pp != PATTERN_UNKNOWN; pp++) {
596
// In case we are processing only one
599
for (int pos = 0; pos < num_move_index; ++pos) {
600
delete [] pat[pp][pos];
609
int main_real(int argc, char *argv[])
611
use_private_files(true);
613
gtout(std::cout, _("%$ %$ - Pattern generator\n")) << prog_name << prog_ver;
614
std::cout << _("(c) 2001, 2002, 2003, 2004, 2005 Kriang Lerdsuwanakij\n\n");
615
gtout(std::cout, _("Usage: %$ PATTERN init|gen|FILES\n\n")) << prog_name;
619
throw std::runtime_error(_("bad arguments"));
621
pattern_t pattern = PATTERN_UNKNOWN;
622
if (strcmp(argv[1], "row1") == 0) {
623
pattern = PATTERN_ROW1;
625
else if (strcmp(argv[1], "row2") == 0) {
626
pattern = PATTERN_ROW2;
628
else if (strcmp(argv[1], "row3") == 0) {
629
pattern = PATTERN_ROW3;
631
else if (strcmp(argv[1], "row4") == 0) {
632
pattern = PATTERN_ROW4;
634
else if (strcmp(argv[1], "diag1") == 0) {
635
pattern = PATTERN_DIAG1;
637
else if (strcmp(argv[1], "diag2") == 0) {
638
pattern = PATTERN_DIAG2;
640
else if (strcmp(argv[1], "diag3") == 0) {
641
pattern = PATTERN_DIAG3;
643
else if (strcmp(argv[1], "diag4") == 0) {
644
pattern = PATTERN_DIAG4;
646
else if (strcmp(argv[1], "diag5") == 0) {
647
pattern = PATTERN_DIAG5;
649
else if (strcmp(argv[1], "edge-x") == 0) {
650
pattern = PATTERN_EDGE_X;
652
else if (strcmp(argv[1], "corner5x2") == 0) {
653
pattern = PATTERN_CORNER5X2;
655
else if (strcmp(argv[1], "all") == 0) {
659
throw std::runtime_error(_("bad pattern name"));
662
process_pattern(pattern, argc, argv);
666
int main(int argc, char *argv[])
669
return main_real(argc, argv);
671
catch (std::exception &e) {
672
std::cout << std::flush;
673
gtout(std::cerr, _("%$: %$\n")) << prog_name << e.what();
675
catch (const char *s) {
676
std::cout << std::flush;
677
gtout(std::cerr, _("%$: exception %$\n")) << prog_name << s;
680
std::cout << std::flush;
681
gtout(std::cerr, _("%$: unknown exception\n")) << prog_name;