void update_special_node(int move) { // store special node int x,y; double winrate = 0; double c = 0; for(y = state.boardsize; y >= 1; y--) { for(x = 1; x <= state.boardsize; x++) { struct Node * nodeThis = hash_get_node(hash_get(move, POS(x,y), goban.hash, NODETYPE_POS|NODETYPE_TARGET|NODETYPE_MOVE)); struct Node *nodeParent = hash_get_node(hash_get(0, POS(x,y), goban.hash, NODETYPE_POS|NODETYPE_TARGET)); if (nodeThis->visits) { double wr = ((double)nodeThis->wins / (double)nodeThis->visits); double wrPar = ((double)nodeParent->wins / (double)nodeParent->visits); /*double stb = stab(POS(x,y)); stb = pow(stb, 2); stb=1; c+=stb;*/ c += 1; wr = exaggerate_winrate(wr, EXAGGERATE_RATE) ; wrPar = 1;//exaggerate_winrate(wrPar, EXAGGERATE_RATE) ; winrate += wr / wrPar;//((wr - wrPar) + 1) / 2.0;// 0...1 - get_average_rating(move(x,y)); //out(fileGTP, "Winrate for move %p, at target %p = %f - %f\n", // move, POS(x,y), wr, wrPar); } } } winrate /= c; //out(fileGTP, "Winrate for move %p, %f\n", move, POS(x,y), winrate); hash_set_node_special(hash_get(move, 0, goban.hash, NODETYPE_POS|NODETYPE_MOVE|NODETYPE_SPECIAL), winrate); }
// gets the currently determined best-move from the hashtables int engine_getbestmove() { int bestmove = 0; double bestwinrate = 0; int x,y; for(y = state.boardsize; y >= 1; y--) { for (x = 1; x <= state.boardsize; x++) { struct Node *node = hash_get_node(hash_get( POS(x,y), 0, goban.hash, NODETYPE_POS|NODETYPE_MOVE|NODETYPE_SPECIAL)); double winrate = (double) node->wins / (double) node->visits; if (winrate > bestwinrate) { bestwinrate = winrate; bestmove = POS(x,y); } } } return bestmove; }
uint64_t test_perft_rec(state_t *state, int depth, int verbose) { /* Given a position, it will recursivly apply every possible * move for a given depth and count the leaf nodes. */ if (depth == 0) { return 1; } hash_node_t *hash_node = hash_get_node(state->zobrist); /* Check if hashing is enabled */ if (hash_node) { if (hash_node->hash == state->zobrist && hash_node->depth == depth) { ++_cache_hits; return hash_node->score; } else { ++_cache_misses; } } int moves[100]; int count = 0, count2 = 0; move_generate_moves(state, moves, &count); move_generate_tactical(state, moves + count, &count2); count += count2; /* Check for invalid position or board with no pieces :) */ if (count <= 0) { return 0; } uint64_t nodes = 0; int i; for (i = 0; i < count; ++i) { make_move(state, moves[i], depth); if (move_is_attacked(state, state->king_idx[Flip(state->turn)], state->turn)) { unmake_move(state, moves[i], depth); continue; } uint64_t res = test_perft_rec(state, depth - 1, 0); nodes += res; if (verbose && res > 0) { char move_str[16]; util_move_to_lan(moves[i], move_str); printf("%s: %lld\n", move_str, res); } unmake_move(state, moves[i], depth); } hash_add_node(state->zobrist, nodes, depth, 0, 0); return nodes; }
// recursive function to try a game int trygame(int depth, int doUpdate) { struct Node *parent = (struct Node*)0; uint64_t goban_hash = goban.hash; int myturn = goban.turn; int result; int pos; int win; int x,y; int haspoints; uint64_t hash; if (depth == MAXDEPTH) return goban_getOwner(target); // see if we can use nt3 hash = hash_get(0, target, goban.hash, NODETYPE_POS |USE_TARGET); parent = hash_get_node(hash); pos = get_best_move( parent, (NODETYPE_POS| USE_TARGET| NODETYPE_MOVE), NULL ); if (parent->visits >= MIN_SPECIAL_VISITS && parent->visits % UPDATE_SPECIAL_RATE == 0) { update_special_node(pos); } if (mode == 1) { int p; for(y = state.boardsize; y >= 1; y--) for(x = 1; x <= state.boardsize; x++) update_special_node(POS(x,y)); p = engine_getbestmove(); if (p) pos = p; } goban_move(pos); #if LOG_MOVES_RATE > 0 if (depth == 0 && tries % LOG_MOVES_RATE == 0) { out(fileGTP, "Target %p ", target); } if (depth < 10 && tries % LOG_MOVES_RATE == 0) out(fileGTP, "%d%p ", 0, pos); #endif result = trygame(depth+1, parent->visits > 0); #if LOG_MOVES_RATE > 0 if (depth == 0 && tries % LOG_MOVES_RATE == 0) out(fileGTP, " res=%d, %r\n", result, goban.score); #endif haspoints = 0; for(y = state.boardsize; y >= 1; y--) for(x = 1; x <= state.boardsize; x++) { int targ = POS(x,y); if (targ != target) continue; result = goban_getOwner(targ); if (!result) continue; haspoints = 1; } if (!haspoints) { //out(fileInfo, "Failure getOwner(target)=%d\n", goban_getOwner(POS(7,5))); //outboard(fileInfo); } if (haspoints && doUpdate) for(y = state.boardsize; y >= 1; y--) for(x=1; x <= state.boardsize; x++) { int targ = POS(x,y); if (targ != target) continue; result = goban_getOwner(targ); if (!result) continue; win = (result == myturn ? 1 : 0); // store nt 3 hash_set_node(hash_get(pos, targ, goban_hash, NODETYPE_POS|NODETYPE_TARGET|NODETYPE_MOVE), win); hash_set_node(hash_get(pos, targ, goban_hash, NODETYPE_POS|NODETYPE_TARGET), win); } // update target-agnostic nodes (generic uct) if (haspoints && doUpdate && goban.score) { win = (myturn * goban.score > 0 ? 1 : 0); hash_set_node(hash_get(pos, 0, goban_hash, NODETYPE_POS|NODETYPE_MOVE), win); hash_set_node(hash_get(pos, 0, goban_hash, NODETYPE_POS), win); } if (haspoints && depth == 0) { for(y = state.boardsize; y >= 1; y--) for(x=1; x <= state.boardsize; x++) { int targ = POS(x,y); result = goban_getOwner(targ); pos_stat[targ].total++; if (result == myturn) pos_stat[targ].won++; else if (result == -myturn) pos_stat[targ].lost++; } //outboard(fileGTP); //update_special_node(pos); return 1; } return 0; return result; }
// move_info should contain parentvisits; others are filled in void get_move_value(int move, struct MoveInfo *move_info, int nodetype) { uint64_t hash; struct Node * node; if (move_info->parent_visits == 0) { move_info->uct = 0; /* hash = hash_get(move, target, goban.hash, nodetype); node = hash_get_node(hash); assert(node->wins == 0); assert(node->visits == 0); */ return; } hash = hash_get(move, target, goban.hash, NODETYPE_POS|USE_TARGET|NODETYPE_MOVE); node = hash_get_node(hash); move_info->wins = node->wins; move_info->visits = node->visits; if (move_info->visits > 0) move_info->winrate = (double)move_info->wins / ((double)move_info->visits); else move_info->winrate = 0; //if (move_info->parent_visits > state.boardsize * state.boardsize * 10) if (0) { hash = hash_get(move, target, goban.hash, NODETYPE_POS|NODETYPE_MOVE|NODETYPE_SPECIAL); node = hash_get_node(hash); if (node->visits > 0) move_info->winrate = (double)node->wins / ((double)node->visits+1); } //assert(move_info->visits <= move_info->parent_visits); move_info->uct = getuct(move_info->winrate, move_info->visits, move_info->parent_visits, nodetype); if (0) { // get the winrate from the special node hash = hash_get(move, target, goban.hash, nodetype); node = hash_get_node(hash); if (node->visits == 0) { move_info->wins = 0; move_info->visits = 0; move_info->winrate = 0.0; } else { move_info->winrate = (double)node->wins / ((double)node->visits+1); hash = hash_get(move, target, goban.hash, NODETYPE_POS|NODETYPE_TARGET|NODETYPE_MOVE); node = hash_get_node(hash); move_info->wins = node->wins; move_info->visits = node->visits; } move_info->uct = getuct(move_info->winrate, move_info->visits, move_info->parent_visits, nodetype); } }