9 #include "joseki/joseki.h"
10 #include "joseki/base.h"
13 /* Internal engine state. */
14 struct joseki_engine
{
19 struct board
*b
[16]; // boards with reversed color, mirrored and rotated
22 /* We will record the joseki positions into incrementally-built
23 * jdict->patterns[]. */
27 joseki_play(struct engine
*e
, struct board
*b
, struct move
*m
)
29 struct joseki_engine
*j
= e
->data
;
32 /* New game, reset state. */
33 j
->size
= board_size(b
);
34 assert(j
->size
== jdict
->bsize
);
36 for (int i
= 0; i
< 16; i
++) {
37 board_resize(j
->b
[i
], j
->size
- 2);
42 //printf("%s %d\n", coord2sstr(m->coord, b), coord_quadrant(m->coord, b));
44 assert(!is_resign(m
->coord
));
45 if (is_pass(m
->coord
))
47 /* Ignore moves in different quadrants. */
48 if (coord_quadrant(m
->coord
, b
) > 0)
51 if (coord_x(m
->coord
, b
) == board_size(b
) / 2 || coord_y(m
->coord
, b
) == board_size(b
) / 2) {
52 /* This is troublesome, since it cannot mirror properly:
53 * it won't be hashed in some quadrants. Better just discard
54 * the rest of the sequence for now. (TODO: Make quadrants
61 //printf("%"PRIhash" %"PRIhash"\n", j->b[0]->qhash[0], b->qhash[0]);
62 assert(j
->b
[0]->qhash
[0] == b
->qhash
[0]);
64 /* Record next move in all rotations and update the hash. */
65 for (int i
= 0; i
< 16; i
++) {
66 #define HASH_VMIRROR 1
67 #define HASH_HMIRROR 2
71 coord_t coord
= m
->coord
;
72 if (i
& HASH_VMIRROR
) {
73 coord
= coord_xy(b
, coord_x(coord
, b
), board_size(b
) - 1 - coord_y(coord
, b
));
76 if (i
& HASH_HMIRROR
) {
77 coord
= coord_xy(b
, board_size(b
) - 1 - coord_x(coord
, b
), coord_y(coord
, b
));
80 if (i
& HASH_XYFLIP
) {
81 coord
= coord_xy(b
, coord_y(coord
, b
), coord_x(coord
, b
));
84 else if (quadrant
== 2)
87 enum stone color
= m
->color
;
89 color
= stone_other(color
);
91 coord_t
**ccp
= &jdict
->patterns
[j
->b
[i
]->qhash
[quadrant
] & joseki_hash_mask
].moves
[color
- 1];
95 for (coord_t
*cc
= *ccp
; !is_pass(*cc
); cc
++) {
98 //printf("%d,%d (%"PRIhash", %d) !+ %s\n", i, quadrant, j->b[i]->qhash[quadrant], count, coord2sstr(coord, b));
104 //printf("%d,%d (%"PRIhash", %d) =+ %s\n", i, quadrant, j->b[i]->qhash[quadrant], count, coord2sstr(coord, b));
105 *ccp
= realloc(*ccp
, (count
+ 1) * sizeof(coord_t
));
106 (*ccp
)[count
- 1] = coord
;
107 (*ccp
)[count
] = pass
;
110 struct move m2
= { .coord
= coord
, .color
= color
};
111 board_play(j
->b
[i
], &m2
);
119 joseki_genmove(struct engine
*e
, struct board
*b
, struct time_info
*ti
, enum stone color
, bool pass_all_alive
)
121 fprintf(stderr
, "genmove command not available in joseki scan!\n");
126 engine_joseki_done(struct engine
*e
)
128 struct joseki_engine
*j
= e
->data
;
129 struct board
*b
= board_init();
130 board_resize(b
, j
->size
- 2);
133 for (hash_t i
= 0; i
< 1 << joseki_hash_bits
; i
++) {
134 for (int j
= 0; j
< 2; j
++) {
135 static const char cs
[] = "bw";
136 if (!jdict
->patterns
[i
].moves
[j
])
138 printf("%" PRIhash
" %c", i
, cs
[j
]);
139 coord_t
*cc
= jdict
->patterns
[i
].moves
[j
];
141 while (!is_pass(*cc
)) {
142 printf(" %s", coord2sstr(*cc
, b
));
145 printf(" %d\n", count
);
153 struct joseki_engine
*
154 joseki_state_init(char *arg
)
156 struct joseki_engine
*j
= calloc2(1, sizeof(struct joseki_engine
));
158 for (int i
= 0; i
< 16; i
++)
159 j
->b
[i
] = board_init();
164 char *optspec
, *next
= arg
;
167 next
+= strcspn(next
, ",");
168 if (*next
) { *next
++ = 0; } else { *next
= 0; }
170 char *optname
= optspec
;
171 char *optval
= strchr(optspec
, '=');
172 if (optval
) *optval
++ = 0;
174 if (!strcasecmp(optname
, "debug")) {
176 j
->debug_level
= atoi(optval
);
181 fprintf(stderr
, "joseki: Invalid engine argument %s or missing value\n", optname
);
189 jdict
= joseki_init(19 + 2); // XXX
195 engine_joseki_init(char *arg
, struct board
*b
)
197 struct joseki_engine
*j
= joseki_state_init(arg
);
198 struct engine
*e
= calloc2(1, sizeof(struct engine
));
199 e
->name
= "Joseki Engine";
200 e
->comment
= "You cannot play Pachi with this engine, it is intended for special development use - scanning of joseki sequences fed to it within the GTP stream.";
201 e
->genmove
= joseki_genmove
;
202 e
->notify_play
= joseki_play
;
203 e
->done
= engine_joseki_done
;
205 // clear_board does not concern us, we like to work over many games
206 e
->keep_on_clear
= true;