static void dirtree_expand (GtkCTree * tree, GtkCTreeNode * node) { GtkAdjustment *h_adjustment; gfloat row_align; DirTreeNode *dt_node; dt_node = gtk_ctree_node_get_row_data (tree, node); if (dt_node->scanned == FALSE) { tree_expand_node (DIRTREE (tree), node, FALSE); dt_node->scanned = TRUE; } if (parent_class->tree_expand) (*parent_class->tree_expand) (tree, node); h_adjustment = gtk_clist_get_hadjustment (GTK_CLIST (tree)); if (h_adjustment && h_adjustment->upper != 0.0) { row_align = (float) (tree->tree_indent * GTK_CTREE_ROW (node)->level) / h_adjustment->upper; gtk_ctree_node_moveto (tree, node, tree->tree_column, 0, row_align); } }
void dirtree_refresh_tree (DirTree * dt, GtkCTreeNode * parent, gboolean selected) { lock = TRUE; if (selected) { gtk_ctree_select (GTK_CTREE (dt), parent); GTK_CLIST (dt)->focus_row = GTK_CLIST (dt)->rows - g_list_length ((GList *) parent); } tree_expand_node (dt, parent, TRUE); lock = FALSE; if (selected) { gtk_ctree_select (GTK_CTREE (dt), parent); GTK_CLIST (dt)->focus_row = GTK_CLIST (dt)->rows - g_list_length ((GList *) parent); } }
int uct_playout(struct uct *u, struct board *b, enum stone player_color, struct tree *t) { struct board b2; board_copy(&b2, b); struct playout_amafmap amaf; amaf.gamelen = amaf.game_baselen = 0; /* Walk the tree until we find a leaf, then expand it and do * a random playout. */ struct tree_node *n = t->root; enum stone node_color = stone_other(player_color); assert(node_color == t->root_color); /* Make sure the root node is expanded. */ if (tree_leaf_node(n) && !__sync_lock_test_and_set(&n->is_expanded, 1)) tree_expand_node(t, n, &b2, player_color, u, 1); /* Tree descent history. */ /* XXX: This is somewhat messy since @n and descent[dlen-1].node are * redundant. */ struct uct_descent descent[DESCENT_DLEN]; descent[0].node = n; descent[0].lnode = NULL; int dlen = 1; /* Total value of the sequence. */ struct move_stats seq_value = { .playouts = 0 }; /* The last "significant" node along the descent (i.e. node * with higher than configured number of playouts). For black * and white. */ struct tree_node *significant[2] = { NULL, NULL }; if (n->u.playouts >= u->significant_threshold) significant[node_color - 1] = n; int result; int pass_limit = (board_size(&b2) - 2) * (board_size(&b2) - 2) / 2; int passes = is_pass(b->last_move.coord) && b->moves > 0; /* debug */ static char spaces[] = "\0 "; /* /debug */ if (UDEBUGL(8)) fprintf(stderr, "--- UCT walk with color %d\n", player_color); while (!tree_leaf_node(n) && passes < 2) { spaces[dlen - 1] = ' '; spaces[dlen] = 0; /*** Choose a node to descend to: */ /* Parity is chosen already according to the child color, since * it is applied to children. */ node_color = stone_other(node_color); int parity = (node_color == player_color ? 1 : -1); assert(dlen < DESCENT_DLEN); descent[dlen] = descent[dlen - 1]; if (u->local_tree && (!descent[dlen].lnode || descent[dlen].node->d >= u->tenuki_d)) { /* Start new local sequence. */ /* Remember that node_color already holds color of the * to-be-found child. */ descent[dlen].lnode = node_color == S_BLACK ? t->ltree_black : t->ltree_white; } if (!u->random_policy_chance || fast_random(u->random_policy_chance)) u->policy->descend(u->policy, t, &descent[dlen], parity, b2.moves > pass_limit); else u->random_policy->descend(u->random_policy, t, &descent[dlen], parity, b2.moves > pass_limit); /*** Perform the descent: */ if (descent[dlen].node->u.playouts >= u->significant_threshold) { significant[node_color - 1] = descent[dlen].node; } seq_value.playouts += descent[dlen].value.playouts; seq_value.value += descent[dlen].value.value * descent[dlen].value.playouts; n = descent[dlen++].node; assert(n == t->root || n->parent); if (UDEBUGL(7)) fprintf(stderr, "%s+-- UCT sent us to [%s:%d] %d,%f\n", spaces, coord2sstr(node_coord(n), t->board), node_coord(n), n->u.playouts, tree_node_get_value(t, parity, n->u.value)); /* Add virtual loss if we need to; this is used to discourage * other threads from visiting this node in case of multiple * threads doing the tree search. */ if (u->virtual_loss) stats_add_result(&n->u, node_color == S_BLACK ? 0.0 : 1.0, u->virtual_loss); assert(node_coord(n) >= -1); record_amaf_move(&amaf, node_coord(n)); struct move m = { node_coord(n), node_color }; int res = board_play(&b2, &m); if (res < 0 || (!is_pass(m.coord) && !group_at(&b2, m.coord)) /* suicide */ || b2.superko_violation) { if (UDEBUGL(4)) { for (struct tree_node *ni = n; ni; ni = ni->parent) fprintf(stderr, "%s<%"PRIhash"> ", coord2sstr(node_coord(ni), t->board), ni->hash); fprintf(stderr, "marking invalid %s node %d,%d res %d group %d spk %d\n", stone2str(node_color), coord_x(node_coord(n),b), coord_y(node_coord(n),b), res, group_at(&b2, m.coord), b2.superko_violation); } n->hints |= TREE_HINT_INVALID; result = 0; goto end; } if (is_pass(node_coord(n))) passes++; else passes = 0; enum stone next_color = stone_other(node_color); /* We need to make sure only one thread expands the node. If * we are unlucky enough for two threads to meet in the same * node, the latter one will simply do another simulation from * the node itself, no big deal. t->nodes_size may exceed * the maximum in multi-threaded case but not by much so it's ok. * The size test must be before the test&set not after, to allow * expansion of the node later if enough nodes have been freed. */ if (tree_leaf_node(n) && n->u.playouts - u->virtual_loss >= u->expand_p && t->nodes_size < u->max_tree_size && !__sync_lock_test_and_set(&n->is_expanded, 1)) tree_expand_node(t, n, &b2, next_color, u, -parity); } amaf.game_baselen = amaf.gamelen; if (t->use_extra_komi && u->dynkomi->persim) { b2.komi += round(u->dynkomi->persim(u->dynkomi, &b2, t, n)); } if (passes >= 2) { /* XXX: No dead groups support. */ floating_t score = board_official_score(&b2, NULL); /* Result from black's perspective (no matter who * the player; black's perspective is always * what the tree stores. */ result = - (score * 2); if (UDEBUGL(5)) fprintf(stderr, "[%d..%d] %s p-p scoring playout result %d (W %f)\n", player_color, node_color, coord2sstr(node_coord(n), t->board), result, score); if (UDEBUGL(6)) board_print(&b2, stderr); board_ownermap_fill(&u->ownermap, &b2); } else { // assert(tree_leaf_node(n)); /* In case of parallel tree search, the assertion might * not hold if two threads chew on the same node. */ result = uct_leaf_node(u, &b2, player_color, &amaf, descent, &dlen, significant, t, n, node_color, spaces); } if (u->policy->wants_amaf && u->playout_amaf_cutoff) { unsigned int cutoff = amaf.game_baselen; cutoff += (amaf.gamelen - amaf.game_baselen) * u->playout_amaf_cutoff / 100; amaf.gamelen = cutoff; } /* Record the result. */ assert(n == t->root || n->parent); floating_t rval = scale_value(u, b, result); u->policy->update(u->policy, t, n, node_color, player_color, &amaf, &b2, rval); if (t->use_extra_komi) { stats_add_result(&u->dynkomi->score, result / 2, 1); stats_add_result(&u->dynkomi->value, rval, 1); } if (u->local_tree && n->parent && !is_pass(node_coord(n)) && dlen > 0) { /* Get the local sequences and record them in ltree. */ /* We will look for sequence starts in our descent * history, then run record_local_sequence() for each * found sequence start; record_local_sequence() may * pick longer sequences from descent history then, * which is expected as it will create new lnodes. */ enum stone seq_color = player_color; /* First move always starts a sequence. */ record_local_sequence(u, t, &b2, descent, dlen, 1, seq_color); seq_color = stone_other(seq_color); for (int dseqi = 2; dseqi < dlen; dseqi++, seq_color = stone_other(seq_color)) { if (u->local_tree_allseq) { /* We are configured to record all subsequences. */ record_local_sequence(u, t, &b2, descent, dlen, dseqi, seq_color); continue; } if (descent[dseqi].node->d >= u->tenuki_d) { /* Tenuki! Record the fresh sequence. */ record_local_sequence(u, t, &b2, descent, dlen, dseqi, seq_color); continue; } if (descent[dseqi].lnode && !descent[dseqi].lnode) { /* Record result for in-descent picked sequence. */ record_local_sequence(u, t, &b2, descent, dlen, dseqi, seq_color); continue; } } } end: /* We need to undo the virtual loss we added during descend. */ if (u->virtual_loss) { floating_t loss = node_color == S_BLACK ? 0.0 : 1.0; for (; n->parent; n = n->parent) { stats_rm_result(&n->u, loss, u->virtual_loss); loss = 1.0 - loss; } } board_done_noalloc(&b2); return result; } int uct_playouts(struct uct *u, struct board *b, enum stone color, struct tree *t, struct time_info *ti) { int i; if (ti && ti->dim == TD_GAMES) { for (i = 0; t->root->u.playouts <= ti->len.games && !uct_halt; i++) uct_playout(u, b, color, t); } else { for (i = 0; !uct_halt; i++) uct_playout(u, b, color, t); } return i; }
GtkWidget * dirtree_new (GtkWidget * win, const gchar * start_path, gboolean check_dir, gboolean check_hlinks, gboolean show_dotfile, gint line_style, gint expander_style) { GtkWidget *widget; DirTree *dt; DirTreeNode *dt_node; GtkCTreeNode *node = NULL; char *root = "/", *rp, *tmp; widget = gtk_type_new (dirtree_get_type ()); #ifndef USE_GTK2 gtk_ctree_construct (GTK_CTREE (widget), 1, 0, NULL); #endif dt = DIRTREE (widget); dt->collapse = FALSE; dt->check_dir = check_dir; dt->check_hlinks = check_hlinks; dt->show_dotfile = show_dotfile; dt->expander_style = expander_style; dt->line_style = line_style; dt->check_events = TRUE; lock = FALSE; gtk_clist_set_column_auto_resize (GTK_CLIST (dt), 0, TRUE); gtk_clist_set_selection_mode (GTK_CLIST (dt), GTK_SELECTION_BROWSE); gtk_clist_set_row_height (GTK_CLIST (dt), 18); gtk_ctree_set_expander_style (GTK_CTREE (dt), expander_style); gtk_ctree_set_line_style (GTK_CTREE (dt), line_style); folder_pixmap = gdk_pixmap_create_from_xpm_d (win->window, &folder_mask, NULL, folder_xpm); ofolder_pixmap = gdk_pixmap_create_from_xpm_d (win->window, &ofolder_mask, NULL, folder_open_xpm); lfolder_pixmap = gdk_pixmap_create_from_xpm_d (win->window, &lfolder_mask, NULL, folder_link_xpm); lofolder_pixmap = gdk_pixmap_create_from_xpm_d (win->window, &lofolder_mask, NULL, folder_link_open_xpm); lckfolder_pixmap = gdk_pixmap_create_from_xpm_d (win->window, &lckfolder_mask, NULL, folder_lock_xpm); gofolder_pixmap = gdk_pixmap_create_from_xpm_d (win->window, &gofolder_mask, NULL, folder_go_xpm); upfolder_pixmap = gdk_pixmap_create_from_xpm_d (win->window, &upfolder_mask, NULL, folder_up_xpm); node = gtk_ctree_insert_node (GTK_CTREE (dt), NULL, NULL, &root, CTREE_SPACING, folder_pixmap, folder_mask, ofolder_pixmap, ofolder_mask, FALSE, TRUE); dt_node = g_malloc0 (sizeof (DirTreeNode)); dt_node->path = g_strdup ("/"); dt_node->scanned = TRUE; gtk_ctree_node_set_row_data_full (GTK_CTREE (dt), node, dt_node, dirtree_destroy_tree); tree_expand_node (dt, node, FALSE); rp = g_strdup (start_path); tmp = strtok (rp, "/"); while (tmp) { node = dirtree_find_file (dt, node, tmp); if (!node) break; gtk_ctree_expand (GTK_CTREE (dt), node); gtk_ctree_select (GTK_CTREE (dt), node); GTK_CLIST (dt)->focus_row = GTK_CLIST (dt)->rows - g_list_length ((GList *) node); tmp = strtok (NULL, "/"); } g_free (rp); return widget; }