17 #include "tactics/util.h"
18 #include "uct/dynkomi.h"
19 #include "uct/internal.h"
20 #include "uct/search.h"
26 #define DESCENT_DLEN 512
30 uct_progress_text(struct uct
*u
, struct tree
*t
, enum stone color
, int playouts
)
36 struct tree_node
*best
= u
->policy
->choose(u
->policy
, t
->root
, t
->board
, color
, resign
);
38 fprintf(stderr
, "... No moves left\n");
41 fprintf(stderr
, "[%d] ", playouts
);
42 fprintf(stderr
, "best %f ", tree_node_get_value(t
, 1, best
->u
.value
));
45 if (t
->use_extra_komi
)
46 fprintf(stderr
, "xkomi %.1f ", t
->extra_komi
);
49 fprintf(stderr
, "| seq ");
50 for (int depth
= 0; depth
< 4; depth
++) {
51 if (best
&& best
->u
.playouts
>= 25) {
52 fprintf(stderr
, "%3s ", coord2sstr(node_coord(best
), t
->board
));
53 best
= u
->policy
->choose(u
->policy
, best
, t
->board
, color
, resign
);
60 fprintf(stderr
, "| can %c ", color
== S_BLACK
? 'b' : 'w');
62 struct tree_node
*can
[cans
];
63 memset(can
, 0, sizeof(can
));
64 best
= t
->root
->children
;
67 while ((!can
[c
] || best
->u
.playouts
> can
[c
]->u
.playouts
) && ++c
< cans
);
68 for (int d
= 0; d
< c
; d
++) can
[d
] = can
[d
+ 1];
69 if (c
> 0) can
[c
- 1] = best
;
74 fprintf(stderr
, "%3s(%.3f) ",
75 coord2sstr(node_coord(can
[cans
]), t
->board
),
76 tree_node_get_value(t
, 1, can
[cans
]->u
.value
));
82 fprintf(stderr
, "\n");
85 /* Live gfx: show best sequence in GoGui */
87 uct_progress_gogui_sequence(struct uct
*u
, struct tree
*t
, enum stone color
, int playouts
)
90 struct tree_node
*best
= u
->policy
->choose(u
->policy
, t
->root
, t
->board
, color
, resign
);
92 fprintf(stderr
, "... No moves left\n");
96 fprintf(stderr
, "gogui-gfx: VAR ");
98 for (int depth
= 0; depth
< 4; depth
++) {
99 if (best
&& best
->u
.playouts
>= 25) {
100 fprintf(stderr
, "%c %3s ",
101 col
[(depth
+ (color
== S_WHITE
)) % 2],
102 coord2sstr(node_coord(best
), t
->board
));
103 best
= u
->policy
->choose(u
->policy
, best
, t
->board
, color
, resign
);
106 fprintf(stderr
, "\n");
109 /* Display best moves graphically in GoGui.
110 * gfx commands printed on stderr are for live gfx,
111 * and the last run is kept in a buffer in case we need a gtp reply.
114 uct_progress_gogui_candidates(struct uct
*u
, struct tree
*t
, enum stone color
, int playouts
)
116 struct tree_node
*best
= t
->root
->children
;
117 int cans
= GOGUI_CANDIDATES
;
118 struct tree_node
*can
[cans
];
119 memset(can
, 0, sizeof(can
));
122 while ((!can
[c
] || best
->u
.playouts
> can
[c
]->u
.playouts
) && ++c
< cans
);
123 for (int d
= 0; d
< c
; d
++) can
[d
] = can
[d
+ 1];
124 if (c
> 0) can
[c
- 1] = best
;
125 best
= best
->sibling
;
128 fprintf(stderr
, "gogui-gfx:\n");
129 char *buf
= gogui_gfx_buf
;
132 sprintf(buf
, "VAR %s %s\n",
133 (color
== S_WHITE
? "w" : "b"),
134 coord2sstr(node_coord(can
[cans
]), t
->board
) );
135 fprintf(stderr
, "%s", buf
);
140 sprintf(buf
, "LABEL %s %i\n",
141 coord2sstr(node_coord(can
[cans
]), t
->board
),
142 GOGUI_CANDIDATES
- cans
);
143 fprintf(stderr
, "%s", buf
);
146 fprintf(stderr
, "\n");
149 /* Display best moves' winrates in GoGui.
150 * gfx commands printed on stderr are for live gfx,
151 * and the last run is kept in a buffer in case we need a gtp reply.
154 uct_progress_gogui_winrates(struct uct
*u
, struct tree
*t
, enum stone color
, int playouts
)
156 struct tree_node
*best
= t
->root
->children
;
157 int cans
= GOGUI_CANDIDATES
;
158 struct tree_node
*can
[cans
];
159 memset(can
, 0, sizeof(can
));
162 while ((!can
[c
] || best
->u
.playouts
> can
[c
]->u
.playouts
) && ++c
< cans
);
163 for (int d
= 0; d
< c
; d
++) can
[d
] = can
[d
+ 1];
164 if (c
> 0) can
[c
- 1] = best
;
165 best
= best
->sibling
;
168 fprintf(stderr
, "gogui-gfx:\n");
169 char *buf
= gogui_gfx_buf
;
172 sprintf(buf
, "VAR %s %s\n",
173 (color
== S_WHITE
? "w" : "b"),
174 coord2sstr(node_coord(can
[cans
]), t
->board
) );
175 fprintf(stderr
, "%s", buf
);
182 sprintf(buf
, "LABEL %s .%02u\n",
183 coord2sstr(node_coord(can
[cans
]), t
->board
),
184 (unsigned)(tree_node_get_value(t
, 1, can
[cans
]->u
.value
) * 1000));
185 fprintf(stderr
, "%s", buf
);
188 fprintf(stderr
, "\n");
192 uct_progress_json(struct uct
*u
, struct tree
*t
, enum stone color
, int playouts
, coord_t
*final
, bool big
)
194 /* Prefix indicating JSON line. */
195 fprintf(stderr
, "{\"%s\": {", final
? "move" : "frame");
198 fprintf(stderr
, "\"playouts\": %d", playouts
);
201 if (t
->use_extra_komi
)
202 fprintf(stderr
, ", \"extrakomi\": %.1f", t
->extra_komi
);
205 /* Final move choice */
206 fprintf(stderr
, ", \"choice\": \"%s\"",
207 coord2sstr(*final
, t
->board
));
209 struct tree_node
*best
= u
->policy
->choose(u
->policy
, t
->root
, t
->board
, color
, resign
);
212 fprintf(stderr
, ", \"best\": {\"%s\": %f}",
213 coord2sstr(best
->coord
, t
->board
),
214 tree_node_get_value(t
, 1, best
->u
.value
));
218 /* Best candidates */
220 struct tree_node
*can
[cans
];
221 memset(can
, 0, sizeof(can
));
222 struct tree_node
*best
= t
->root
->children
;
225 while ((!can
[c
] || best
->u
.playouts
> can
[c
]->u
.playouts
) && ++c
< cans
);
226 for (int d
= 0; d
< c
; d
++) can
[d
] = can
[d
+ 1];
227 if (c
> 0) can
[c
- 1] = best
;
228 best
= best
->sibling
;
230 fprintf(stderr
, ", \"can\": [");
231 while (--cans
>= 0) {
232 if (!can
[cans
]) break;
234 fprintf(stderr
, "%s[", cans
< 3 ? ", " : "");
236 for (int depth
= 0; depth
< 4; depth
++) {
237 if (!best
|| best
->u
.playouts
< 25) break;
238 fprintf(stderr
, "%s{\"%s\":%.3f}", depth
> 0 ? "," : "",
239 coord2sstr(best
->coord
, t
->board
),
240 tree_node_get_value(t
, 1, best
->u
.value
));
241 best
= u
->policy
->choose(u
->policy
, best
, t
->board
, color
, resign
);
243 fprintf(stderr
, "]");
245 fprintf(stderr
, "]");
249 if (t
->avg_score
.playouts
> 0)
250 fprintf(stderr
, ", \"avg\": {\"score\": %.3f}", t
->avg_score
.value
);
251 /* Per-intersection information. */
252 fprintf(stderr
, ", \"boards\": {");
253 /* Position coloring information. */
254 fprintf(stderr
, "\"colors\": [");
256 foreach_point(t
->board
) {
257 if (board_at(t
->board
, c
) == S_OFFBOARD
) continue;
258 fprintf(stderr
, "%s%d", f
++ > 0 ? "," : "", board_at(t
->board
, c
));
260 fprintf(stderr
, "]");
261 /* Ownership statistics. Value (0..1000) for each possible
262 * point describes likelihood of this point becoming black.
263 * Normally, white rate is 1000-value; exception are possible
264 * seki points, but these should be rare. */
265 fprintf(stderr
, ", \"territory\": [");
267 foreach_point(t
->board
) {
268 if (board_at(t
->board
, c
) == S_OFFBOARD
) continue;
269 int rate
= u
->ownermap
.map
[c
][S_BLACK
] * 1000 / u
->ownermap
.playouts
;
270 fprintf(stderr
, "%s%d", f
++ > 0 ? "," : "", rate
);
272 fprintf(stderr
, "]");
273 fprintf(stderr
, "}");
276 fprintf(stderr
, "}}\n");
280 uct_progress_status(struct uct
*u
, struct tree
*t
, enum stone color
, int playouts
, coord_t
*final
)
282 switch (u
->reporting
) {
284 uct_progress_text(u
, t
, color
, playouts
);
288 uct_progress_json(u
, t
, color
, playouts
, final
,
289 u
->reporting
== UR_JSON_BIG
);
296 switch(gogui_live_gfx
) {
298 uct_progress_gogui_candidates(u
, t
, color
, playouts
);
301 uct_progress_gogui_sequence(u
, t
, color
, playouts
);
304 uct_progress_gogui_winrates(u
, t
, color
, playouts
);
311 record_amaf_move(struct playout_amafmap
*amaf
, coord_t coord
, bool is_ko_capture
)
313 assert(amaf
->gamelen
< MAX_GAMELEN
);
314 amaf
->is_ko_capture
[amaf
->gamelen
] = is_ko_capture
;
315 amaf
->game
[amaf
->gamelen
++] = coord
;
319 struct uct_playout_callback
{
322 struct tree_node
*lnode
;
327 uct_playout_hook(struct playout_policy
*playout
, struct playout_setup
*setup
, struct board
*b
, enum stone color
, int mode
)
329 /* XXX: This is used in some non-master branches. */
334 uct_playout_prepolicy(struct playout_policy
*playout
, struct playout_setup
*setup
, struct board
*b
, enum stone color
)
336 return uct_playout_hook(playout
, setup
, b
, color
, 0);
340 uct_playout_postpolicy(struct playout_policy
*playout
, struct playout_setup
*setup
, struct board
*b
, enum stone color
)
342 return uct_playout_hook(playout
, setup
, b
, color
, 1);
347 uct_leaf_node(struct uct
*u
, struct board
*b
, enum stone player_color
,
348 struct playout_amafmap
*amaf
,
349 struct uct_descent
*descent
, int *dlen
,
350 struct tree_node
*significant
[2],
351 struct tree
*t
, struct tree_node
*n
, enum stone node_color
,
354 enum stone next_color
= stone_other(node_color
);
355 int parity
= (next_color
== player_color
? 1 : -1);
358 fprintf(stderr
, "%s*-- UCT playout #%d start [%s] %f\n",
359 spaces
, n
->u
.playouts
, coord2sstr(node_coord(n
), t
->board
),
360 tree_node_get_value(t
, -parity
, n
->u
.value
));
362 struct uct_playout_callback upc
= {
365 /* TODO: Don't necessarily restart the sequence walk when
366 * entering playout. */
370 struct playout_setup ps
= {
371 .gamelen
= u
->gamelen
,
372 .mercymin
= u
->mercymin
,
373 .prepolicy_hook
= uct_playout_prepolicy
,
374 .postpolicy_hook
= uct_playout_postpolicy
,
377 int result
= play_random_game(&ps
, b
, next_color
,
378 u
->playout_amaf
? amaf
: NULL
,
379 &u
->ownermap
, u
->playout
);
380 if (next_color
== S_WHITE
) {
381 /* We need the result from black's perspective. */
385 fprintf(stderr
, "%s -- [%d..%d] %s random playout result %d\n",
386 spaces
, player_color
, next_color
, coord2sstr(node_coord(n
), t
->board
), result
);
392 scale_value(struct uct
*u
, struct board
*b
, enum stone node_color
, struct tree_node
*significant
[2], int result
)
394 floating_t rval
= result
> 0 ? 1.0 : result
< 0 ? 0.0 : 0.5;
395 if (u
->val_scale
&& result
!= 0) {
397 if (u
->t
->avg_score
.playouts
< 50)
399 result
-= u
->t
->avg_score
.value
* 2;
402 double scale
= u
->val_scale
;
404 /* xvalue is 0 at 0.5, 1 at 0 or 1 */
405 /* No correction for parity necessary. */
406 double xvalue
= significant
[node_color
- 1] ? fabs(significant
[node_color
- 1]->u
.value
- 0.5) * 2 : 0;
407 scale
= u
->val_bytemp_min
+ (u
->val_scale
- u
->val_bytemp_min
) * xvalue
;
410 int vp
= u
->val_points
;
412 vp
= board_size(b
) - 1; vp
*= vp
; vp
*= 2;
415 floating_t sval
= (floating_t
) abs(result
) / vp
;
416 sval
= sval
> 1 ? 1 : sval
;
417 if (result
< 0) sval
= 1 - sval
;
419 rval
+= scale
* sval
;
421 rval
= (1 - scale
) * rval
+ scale
* sval
;
422 // fprintf(stderr, "score %d => sval %f, rval %f\n", result, sval, rval);
428 local_value(struct uct
*u
, struct board
*b
, coord_t coord
, enum stone color
)
430 /* Tactical evaluation of move @coord by color @color, given
431 * simulation end position @b. I.e., a move is tactically good
432 * if the resulting group stays on board until the game end. */
433 /* We can also take into account surrounding stones, e.g. to
434 * encourage taking off external liberties during a semeai. */
435 double val
= board_local_value(u
->local_tree_neival
, b
, coord
, color
);
436 return (color
== S_WHITE
) ? 1.f
- val
: val
;
440 record_local_sequence(struct uct
*u
, struct tree
*t
, struct board
*endb
,
441 struct uct_descent
*descent
, int dlen
, int di
,
442 enum stone seq_color
)
444 #define LTREE_DEBUG if (UDEBUGL(6))
446 /* Ignore pass sequences. */
447 if (is_pass(node_coord(descent
[di
].node
)))
450 LTREE_DEBUG
board_print(endb
, stderr
);
451 LTREE_DEBUG
fprintf(stderr
, "recording local %s sequence: ",
452 stone2str(seq_color
));
454 /* Sequences starting deeper are less relevant in general. */
455 int pval
= LTREE_PLAYOUTS_MULTIPLIER
;
456 if (u
->local_tree
&& u
->local_tree_depth_decay
> 0)
457 pval
= ((floating_t
) pval
) / pow(u
->local_tree_depth_decay
, di
- 1);
459 LTREE_DEBUG
fprintf(stderr
, "too deep @%d\n", di
);
463 /* Pick the right local tree root... */
464 struct tree_node
*lnode
= seq_color
== S_BLACK
? t
->ltree_black
: t
->ltree_white
;
467 /* ...determine the sequence value... */
469 if (u
->local_tree_eval
!= LTE_EACH
) {
470 sval
= local_value(u
, endb
, node_coord(descent
[di
].node
), seq_color
);
471 LTREE_DEBUG
fprintf(stderr
, "(goal %s[%s %1.3f][%d]) ",
472 coord2sstr(node_coord(descent
[di
].node
), t
->board
),
473 stone2str(seq_color
), sval
, descent
[di
].node
->d
);
475 if (u
->local_tree_eval
== LTE_TOTAL
) {
477 while (di
< dlen
&& (di
== di0
|| descent
[di
].node
->d
< u
->tenuki_d
)) {
478 enum stone color
= (di
- di0
) % 2 ? stone_other(seq_color
) : seq_color
;
479 double rval
= local_value(u
, endb
, node_coord(descent
[di
].node
), color
);
485 sval
/= (di
- di0
+ 1);
490 /* ...and record the sequence. */
492 while (di
< dlen
&& !is_pass(node_coord(descent
[di
].node
))
493 && (di
== di0
|| descent
[di
].node
->d
< u
->tenuki_d
)) {
494 enum stone color
= (di
- di0
) % 2 ? stone_other(seq_color
) : seq_color
;
496 if (u
->local_tree_eval
!= LTE_EACH
)
499 rval
= local_value(u
, endb
, node_coord(descent
[di
].node
), color
);
500 LTREE_DEBUG
fprintf(stderr
, "%s[%s %1.3f][%d] ",
501 coord2sstr(node_coord(descent
[di
].node
), t
->board
),
502 stone2str(color
), rval
, descent
[di
].node
->d
);
503 lnode
= tree_get_node(t
, lnode
, node_coord(descent
[di
++].node
), true);
505 stats_add_result(&lnode
->u
, rval
, pval
);
508 /* Add lnode for tenuki (pass) if we descended further. */
510 double rval
= u
->local_tree_eval
!= LTE_EACH
? sval
: 0.5;
511 LTREE_DEBUG
fprintf(stderr
, "pass ");
512 lnode
= tree_get_node(t
, lnode
, pass
, true);
514 stats_add_result(&lnode
->u
, rval
, pval
);
517 LTREE_DEBUG
fprintf(stderr
, "\n");
522 uct_playout(struct uct
*u
, struct board
*b
, enum stone player_color
, struct tree
*t
)
527 struct playout_amafmap amaf
;
528 amaf
.gamelen
= amaf
.game_baselen
= 0;
530 /* Walk the tree until we find a leaf, then expand it and do
531 * a random playout. */
532 struct tree_node
*n
= t
->root
;
533 enum stone node_color
= stone_other(player_color
);
534 assert(node_color
== t
->root_color
);
536 /* Make sure the root node is expanded. */
537 if (tree_leaf_node(n
) && !__sync_lock_test_and_set(&n
->is_expanded
, 1))
538 tree_expand_node(t
, n
, &b2
, player_color
, u
, 1);
540 /* Tree descent history. */
541 /* XXX: This is somewhat messy since @n and descent[dlen-1].node are
543 struct uct_descent descent
[DESCENT_DLEN
];
544 descent
[0].node
= n
; descent
[0].lnode
= NULL
;
546 /* Total value of the sequence. */
547 struct move_stats seq_value
= { .playouts
= 0 };
548 /* The last "significant" node along the descent (i.e. node
549 * with higher than configured number of playouts). For black
551 struct tree_node
*significant
[2] = { NULL
, NULL
};
552 if (n
->u
.playouts
>= u
->significant_threshold
)
553 significant
[node_color
- 1] = n
;
556 int pass_limit
= (board_size(&b2
) - 2) * (board_size(&b2
) - 2) / 2;
557 int passes
= is_pass(b
->last_move
.coord
) && b
->moves
> 0;
560 static char spaces
[] = "\0 ";
563 fprintf(stderr
, "--- (#%d) UCT walk with color %d\n", t
->root
->u
.playouts
, player_color
);
565 while (!tree_leaf_node(n
) && passes
< 2) {
566 spaces
[dlen
- 1] = ' '; spaces
[dlen
] = 0;
569 /*** Choose a node to descend to: */
571 /* Parity is chosen already according to the child color, since
572 * it is applied to children. */
573 node_color
= stone_other(node_color
);
574 int parity
= (node_color
== player_color
? 1 : -1);
576 assert(dlen
< DESCENT_DLEN
);
577 descent
[dlen
] = descent
[dlen
- 1];
578 if (u
->local_tree
&& (!descent
[dlen
].lnode
|| descent
[dlen
].node
->d
>= u
->tenuki_d
)) {
579 /* Start new local sequence. */
580 /* Remember that node_color already holds color of the
581 * to-be-found child. */
582 descent
[dlen
].lnode
= node_color
== S_BLACK
? t
->ltree_black
: t
->ltree_white
;
585 if (!u
->random_policy_chance
|| fast_random(u
->random_policy_chance
))
586 u
->policy
->descend(u
->policy
, t
, &descent
[dlen
], parity
, b2
.moves
> pass_limit
);
588 u
->random_policy
->descend(u
->random_policy
, t
, &descent
[dlen
], parity
, b2
.moves
> pass_limit
);
591 /*** Perform the descent: */
593 if (descent
[dlen
].node
->u
.playouts
>= u
->significant_threshold
) {
594 significant
[node_color
- 1] = descent
[dlen
].node
;
597 seq_value
.playouts
+= descent
[dlen
].value
.playouts
;
598 seq_value
.value
+= descent
[dlen
].value
.value
* descent
[dlen
].value
.playouts
;
599 n
= descent
[dlen
++].node
;
600 assert(n
== t
->root
|| n
->parent
);
602 fprintf(stderr
, "%s+-- UCT sent us to [%s:%d] %d,%f\n",
603 spaces
, coord2sstr(node_coord(n
), t
->board
),
604 node_coord(n
), n
->u
.playouts
,
605 tree_node_get_value(t
, parity
, n
->u
.value
));
608 __sync_fetch_and_add(&n
->descents
, u
->virtual_loss
);
610 struct move m
= { node_coord(n
), node_color
};
611 int res
= board_play(&b2
, &m
);
613 if (res
< 0 || (!is_pass(m
.coord
) && !group_at(&b2
, m
.coord
)) /* suicide */
614 || b2
.superko_violation
) {
616 for (struct tree_node
*ni
= n
; ni
; ni
= ni
->parent
)
617 fprintf(stderr
, "%s<%"PRIhash
"> ", coord2sstr(node_coord(ni
), t
->board
), ni
->hash
);
618 fprintf(stderr
, "marking invalid %s node %d,%d res %d group %d spk %d\n",
619 stone2str(node_color
), coord_x(node_coord(n
),b
), coord_y(node_coord(n
),b
),
620 res
, group_at(&b2
, m
.coord
), b2
.superko_violation
);
622 n
->hints
|= TREE_HINT_INVALID
;
627 assert(node_coord(n
) >= -1);
628 record_amaf_move(&amaf
, node_coord(n
), board_playing_ko_threat(&b2
));
630 if (is_pass(node_coord(n
)))
635 enum stone next_color
= stone_other(node_color
);
636 /* We need to make sure only one thread expands the node. If
637 * we are unlucky enough for two threads to meet in the same
638 * node, the latter one will simply do another simulation from
639 * the node itself, no big deal. t->nodes_size may exceed
640 * the maximum in multi-threaded case but not by much so it's ok.
641 * The size test must be before the test&set not after, to allow
642 * expansion of the node later if enough nodes have been freed. */
643 if (tree_leaf_node(n
)
644 && n
->u
.playouts
- u
->virtual_loss
>= u
->expand_p
&& t
->nodes_size
< u
->max_tree_size
645 && !__sync_lock_test_and_set(&n
->is_expanded
, 1))
646 tree_expand_node(t
, n
, &b2
, next_color
, u
, -parity
);
649 amaf
.game_baselen
= amaf
.gamelen
;
651 if (t
->use_extra_komi
&& u
->dynkomi
->persim
) {
652 b2
.komi
+= round(u
->dynkomi
->persim(u
->dynkomi
, &b2
, t
, n
));
656 * ALERT: The "result" number is extremely confusing. In some parts
657 * of the code, it is from white's perspective, but here positive
658 * number is black's win! Be VERY CAREFUL.
661 // assert(tree_leaf_node(n));
662 /* In case of parallel tree search, the assertion might
663 * not hold if two threads chew on the same node. */
664 result
= uct_leaf_node(u
, &b2
, player_color
, &amaf
, descent
, &dlen
, significant
, t
, n
, node_color
, spaces
);
666 if (u
->policy
->wants_amaf
&& u
->playout_amaf_cutoff
) {
667 unsigned int cutoff
= amaf
.game_baselen
;
668 cutoff
+= (amaf
.gamelen
- amaf
.game_baselen
) * u
->playout_amaf_cutoff
/ 100;
669 amaf
.gamelen
= cutoff
;
672 /* Record the result. */
674 assert(n
== t
->root
|| n
->parent
);
675 floating_t rval
= scale_value(u
, b
, node_color
, significant
, result
);
676 u
->policy
->update(u
->policy
, t
, n
, node_color
, player_color
, &amaf
, &b2
, rval
);
678 stats_add_result(&t
->avg_score
, result
/ 2, 1);
679 if (t
->use_extra_komi
) {
680 stats_add_result(&u
->dynkomi
->score
, result
/ 2, 1);
681 stats_add_result(&u
->dynkomi
->value
, rval
, 1);
684 if (u
->local_tree
&& n
->parent
&& !is_pass(node_coord(n
)) && dlen
> 0) {
685 /* Get the local sequences and record them in ltree. */
686 /* We will look for sequence starts in our descent
687 * history, then run record_local_sequence() for each
688 * found sequence start; record_local_sequence() may
689 * pick longer sequences from descent history then,
690 * which is expected as it will create new lnodes. */
691 enum stone seq_color
= player_color
;
692 /* First move always starts a sequence. */
693 record_local_sequence(u
, t
, &b2
, descent
, dlen
, 1, seq_color
);
694 seq_color
= stone_other(seq_color
);
695 for (int dseqi
= 2; dseqi
< dlen
; dseqi
++, seq_color
= stone_other(seq_color
)) {
696 if (u
->local_tree_allseq
) {
697 /* We are configured to record all subsequences. */
698 record_local_sequence(u
, t
, &b2
, descent
, dlen
, dseqi
, seq_color
);
701 if (descent
[dseqi
].node
->d
>= u
->tenuki_d
) {
702 /* Tenuki! Record the fresh sequence. */
703 record_local_sequence(u
, t
, &b2
, descent
, dlen
, dseqi
, seq_color
);
706 if (descent
[dseqi
].lnode
&& !descent
[dseqi
].lnode
) {
707 /* Record result for in-descent picked sequence. */
708 record_local_sequence(u
, t
, &b2
, descent
, dlen
, dseqi
, seq_color
);
715 /* We need to undo the virtual loss we added during descend. */
716 if (u
->virtual_loss
) {
717 for (; n
->parent
; n
= n
->parent
) {
718 __sync_fetch_and_sub(&n
->descents
, u
->virtual_loss
);
722 board_done_noalloc(&b2
);
727 uct_playouts(struct uct
*u
, struct board
*b
, enum stone color
, struct tree
*t
, struct time_info
*ti
)
730 if (ti
&& ti
->dim
== TD_GAMES
) {
731 for (i
= 0; t
->root
->u
.playouts
<= ti
->len
.games
&& !uct_halt
; i
++)
732 uct_playout(u
, b
, color
, t
);
734 for (i
= 0; !uct_halt
; i
++)
735 uct_playout(u
, b
, color
, t
);