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
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
);
35 for (int i
= 0; i
< 16; i
++) {
36 board_resize(j
->b
[i
], j
->size
- 2);
41 //printf("%s %d\n", coord2sstr(m->coord, b), coord_quadrant(m->coord, b));
43 assert(!is_resign(m
->coord
));
44 if (is_pass(m
->coord
))
46 /* Ignore moves in different quadrants. */
47 if (coord_quadrant(m
->coord
, b
) > 0)
50 if (coord_x(m
->coord
, b
) == board_size(b
) / 2 || coord_y(m
->coord
, b
) == board_size(b
) / 2) {
51 /* This is troublesome, since it cannot mirror properly:
52 * it won't be hashed in some quadrants. Better just discard
53 * the rest of the sequence for now. (TODO: Make quadrants
60 //printf("%"PRIhash" %"PRIhash"\n", j->b[0]->qhash[0], b->qhash[0]);
61 assert(j
->b
[0]->qhash
[0] == b
->qhash
[0]);
63 /* Record next move in all rotations and update the hash. */
64 for (int i
= 0; i
< 16; i
++) {
65 #define HASH_VMIRROR 1
66 #define HASH_HMIRROR 2
70 coord_t coord
= m
->coord
;
71 if (i
& HASH_VMIRROR
) {
72 coord
= coord_xy(b
, coord_x(coord
, b
), board_size(b
) - 1 - coord_y(coord
, b
));
75 if (i
& HASH_HMIRROR
) {
76 coord
= coord_xy(b
, board_size(b
) - 1 - coord_x(coord
, b
), coord_y(coord
, b
));
79 if (i
& HASH_XYFLIP
) {
80 coord
= coord_xy(b
, coord_y(coord
, b
), coord_x(coord
, b
));
83 else if (quadrant
== 2)
86 enum stone color
= m
->color
;
88 color
= stone_other(color
);
90 coord_t
**ccp
= &joseki_pats
[j
->b
[i
]->qhash
[quadrant
] & joseki_hash_mask
].moves
[color
- 1];
94 for (coord_t
*cc
= *ccp
; !is_pass(*cc
); cc
++) {
97 //printf("%d,%d (%"PRIhash", %d) !+ %s\n", i, quadrant, j->b[i]->qhash[quadrant], count, coord2sstr(coord, b));
103 //printf("%d,%d (%"PRIhash", %d) =+ %s\n", i, quadrant, j->b[i]->qhash[quadrant], count, coord2sstr(coord, b));
104 *ccp
= realloc(*ccp
, (count
+ 1) * sizeof(coord_t
));
105 (*ccp
)[count
- 1] = coord
;
106 (*ccp
)[count
] = pass
;
109 struct move m2
= { .coord
= coord
, .color
= color
};
110 board_play(j
->b
[i
], &m2
);
118 joseki_genmove(struct engine
*e
, struct board
*b
, struct time_info
*ti
, enum stone color
, bool pass_all_alive
)
120 fprintf(stderr
, "genmove command not available in joseki scan!\n");
125 joseki_done(struct engine
*e
)
127 struct joseki_engine
*j
= e
->data
;
128 struct board
*b
= board_init();
129 board_resize(b
, j
->size
- 2);
132 for (hash_t i
= 0; i
< 1 << joseki_hash_bits
; i
++) {
133 for (int j
= 0; j
< 2; j
++) {
134 static const char cs
[] = "bw";
135 if (!joseki_pats
[i
].moves
[j
])
137 printf("%" PRIhash
" %c", i
, cs
[j
]);
138 coord_t
*cc
= joseki_pats
[i
].moves
[j
];
140 while (!is_pass(*cc
)) {
141 printf(" %s", coord2sstr(*cc
, b
));
144 printf(" %d\n", count
);
152 struct joseki_engine
*
153 joseki_state_init(char *arg
)
155 struct joseki_engine
*j
= calloc2(1, sizeof(struct joseki_engine
));
157 for (int i
= 0; i
< 16; i
++)
158 j
->b
[i
] = board_init();
163 char *optspec
, *next
= arg
;
166 next
+= strcspn(next
, ",");
167 if (*next
) { *next
++ = 0; } else { *next
= 0; }
169 char *optname
= optspec
;
170 char *optval
= strchr(optspec
, '=');
171 if (optval
) *optval
++ = 0;
173 if (!strcasecmp(optname
, "debug")) {
175 j
->debug_level
= atoi(optval
);
180 fprintf(stderr
, "joseki: Invalid engine argument %s or missing value\n", optname
);
190 engine_joseki_init(char *arg
, struct board
*b
)
192 struct joseki_engine
*j
= joseki_state_init(arg
);
193 struct engine
*e
= calloc2(1, sizeof(struct engine
));
194 e
->name
= "Joseki Engine";
195 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.";
196 e
->genmove
= joseki_genmove
;
197 e
->notify_play
= joseki_play
;
198 e
->done
= joseki_done
;
200 // clear_board does not concern us, we like to work over many games
201 e
->keep_on_clear
= true;