9 #include "joseki/joseki.h"
10 #include "joseki/base.h"
13 /* Internal engine state. */
14 struct joseki_engine
{
19 struct joseki_dict
*jdict
;
21 struct board
*b
[16]; // boards with reversed color, mirrored and rotated
24 /* We will record the joseki positions into incrementally-built
25 * jdict->patterns[]. */
29 joseki_play(struct engine
*e
, struct board
*b
, struct move
*m
)
31 struct joseki_engine
*j
= e
->data
;
34 /* New game, reset state. */
35 j
->size
= board_size(b
);
37 assert(j
->size
== j
->jdict
->bsize
);
39 j
->jdict
= joseki_init(j
->size
);
41 for (int i
= 0; i
< 16; i
++) {
42 board_resize(j
->b
[i
], j
->size
- 2);
47 //printf("%s %d\n", coord2sstr(m->coord, b), coord_quadrant(m->coord, b));
49 assert(!is_resign(m
->coord
));
50 if (is_pass(m
->coord
))
52 /* Ignore moves in different quadrants. */
53 if (coord_quadrant(m
->coord
, b
) > 0)
56 if (coord_x(m
->coord
, b
) == board_size(b
) / 2 || coord_y(m
->coord
, b
) == board_size(b
) / 2) {
57 /* This is troublesome, since it cannot mirror properly:
58 * it won't be hashed in some quadrants. Better just discard
59 * the rest of the sequence for now. (TODO: Make quadrants
66 //printf("%"PRIhash" %"PRIhash"\n", j->b[0]->qhash[0], b->qhash[0]);
67 assert(j
->b
[0]->qhash
[0] == b
->qhash
[0]);
69 /* Record next move in all rotations and update the hash. */
70 for (int i
= 0; i
< 16; i
++) {
71 #define HASH_VMIRROR 1
72 #define HASH_HMIRROR 2
76 coord_t coord
= m
->coord
;
77 if (i
& HASH_VMIRROR
) {
78 coord
= coord_xy(b
, coord_x(coord
, b
), board_size(b
) - 1 - coord_y(coord
, b
));
81 if (i
& HASH_HMIRROR
) {
82 coord
= coord_xy(b
, board_size(b
) - 1 - coord_x(coord
, b
), coord_y(coord
, b
));
85 if (i
& HASH_XYFLIP
) {
86 coord
= coord_xy(b
, coord_y(coord
, b
), coord_x(coord
, b
));
89 else if (quadrant
== 2)
92 enum stone color
= m
->color
;
94 color
= stone_other(color
);
96 coord_t
**ccp
= &j
->jdict
->patterns
[j
->b
[i
]->qhash
[quadrant
] & joseki_hash_mask
].moves
[color
- 1];
100 for (coord_t
*cc
= *ccp
; !is_pass(*cc
); cc
++) {
103 //printf("%d,%d (%"PRIhash", %d) !+ %s\n", i, quadrant, j->b[i]->qhash[quadrant], count, coord2sstr(coord, b));
109 //printf("%d,%d (%"PRIhash", %d) =+ %s\n", i, quadrant, j->b[i]->qhash[quadrant], count, coord2sstr(coord, b));
110 *ccp
= realloc(*ccp
, (count
+ 1) * sizeof(coord_t
));
111 (*ccp
)[count
- 1] = coord
;
112 (*ccp
)[count
] = pass
;
115 struct move m2
= { .coord
= coord
, .color
= color
};
116 board_play(j
->b
[i
], &m2
);
124 joseki_genmove(struct engine
*e
, struct board
*b
, struct time_info
*ti
, enum stone color
, bool pass_all_alive
)
126 fprintf(stderr
, "genmove command not available in joseki scan!\n");
131 engine_joseki_done(struct engine
*e
)
133 struct joseki_engine
*j
= e
->data
;
134 struct board
*b
= board_init();
135 board_resize(b
, j
->size
- 2);
138 for (hash_t i
= 0; i
< 1 << joseki_hash_bits
; i
++) {
139 for (int s
= 0; s
< 2; s
++) {
140 static const char cs
[] = "bw";
141 if (!j
->jdict
->patterns
[i
].moves
[s
])
143 printf("%" PRIhash
" %c", i
, cs
[s
]);
144 coord_t
*cc
= j
->jdict
->patterns
[i
].moves
[s
];
146 while (!is_pass(*cc
)) {
147 printf(" %s", coord2sstr(*cc
, b
));
150 printf(" %d\n", count
);
156 joseki_done(j
->jdict
);
160 struct joseki_engine
*
161 joseki_state_init(char *arg
)
163 struct joseki_engine
*j
= calloc2(1, sizeof(struct joseki_engine
));
165 for (int i
= 0; i
< 16; i
++)
166 j
->b
[i
] = board_init();
171 char *optspec
, *next
= arg
;
174 next
+= strcspn(next
, ",");
175 if (*next
) { *next
++ = 0; } else { *next
= 0; }
177 char *optname
= optspec
;
178 char *optval
= strchr(optspec
, '=');
179 if (optval
) *optval
++ = 0;
181 if (!strcasecmp(optname
, "debug")) {
183 j
->debug_level
= atoi(optval
);
188 fprintf(stderr
, "joseki: Invalid engine argument %s or missing value\n", optname
);
198 engine_joseki_init(char *arg
, struct board
*b
)
200 struct joseki_engine
*j
= joseki_state_init(arg
);
201 struct engine
*e
= calloc2(1, sizeof(struct engine
));
202 e
->name
= "Joseki Engine";
203 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.";
204 e
->genmove
= joseki_genmove
;
205 e
->notify_play
= joseki_play
;
206 e
->done
= engine_joseki_done
;
208 // clear_board does not concern us, we like to work over many games
209 e
->keep_on_clear
= true;