/* Generic function that tries to store a cache entry. If the cache * is full, we delete the lowest scoring entry. * * Unused parameters have to be normalized to NO_MOVE by the calling * function. */ static void store_persistent_cache(struct persistent_cache *cache, enum routine_id routine, int apos, int bpos, int cpos, Hash_data *goal_hash, int result, int move, int move2, int certain, int node_limit, int cost, const char goal[BOARDMAX], int goal_color) { int r; struct persistent_cache_entry *entry; if (stackp > cache->max_stackp) return; /* If cache is still full, consider kicking out an old entry. */ if (cache->current_size == cache->max_size) { int worst_entry = -1; int worst_score = cost; int k; for (k = 0; k < cache->current_size; k++) { if (cache->table[k].score < worst_score) { worst_score = cache->table[k].score; worst_entry = k; } } if (worst_entry != -1) { /* Move the last entry in the cache here to make space. */ if (worst_entry < cache->current_size - 1) cache->table[worst_entry] = cache->table[cache->current_size - 1]; cache->current_size--; } else return; } entry = &(cache->table[cache->current_size]); entry->boardsize = board_size; entry->routine = routine; entry->apos = apos; entry->bpos = bpos; entry->cpos = cpos; if (goal_hash) entry->goal_hash = *goal_hash; entry->result = result; entry->result_certain = certain; entry->node_limit = node_limit; entry->remaining_depth = depth - stackp; entry->move = move; entry->move2 = move2; entry->score = cost; entry->cost = cost; entry->movenum = movenum; for (r = 0; r < MAX_CACHE_DEPTH; r++) { if (r < stackp) get_move_from_stack(r, &(entry->stack[r]), &(entry->move_color[r])); else { entry->stack[r] = 0; entry->move_color[r] = EMPTY; } } /* Remains to set the board. */ cache->compute_active_area(&(cache->table[cache->current_size]), goal, goal_color); cache->current_size++; if (debug & DEBUG_PERSISTENT_CACHE) { gprintf("%oEntered position in %s:\n", cache->name); print_persistent_cache_entry(entry); gprintf("%oCurrent size: %d\n", cache->current_size); } }
/* Store a new read result in the persistent cache. */ void store_persistent_reading_cache(int routine, int str, int result, int move, int nodes) { char active[BOARDMAX]; int k; int r; int score = nodes; struct reading_cache *entry; ASSERT1(result == 0 || (move == 0) || ON_BOARD(move), move); /* Never cache results at too great depth. */ if (stackp > MAX_READING_CACHE_DEPTH) return; /* If cache is still full, consider kicking out an old entry. */ if (persistent_reading_cache_size == MAX_READING_CACHE_SIZE) { int worst_entry = -1; int worst_score = score; for (k = 1; k < persistent_reading_cache_size; k++) { if (persistent_reading_cache[k].score < worst_score) { worst_score = persistent_reading_cache[k].score; worst_entry = k; } } if (worst_entry != -1) { /* Move the last entry in the cache here to make space. */ if (worst_entry < persistent_reading_cache_size - 1) persistent_reading_cache[worst_entry] = persistent_reading_cache[persistent_reading_cache_size - 1]; persistent_reading_cache_size--; } else return; } entry = &(persistent_reading_cache[persistent_reading_cache_size]); entry->boardsize = board_size; entry->movenum = movenum; entry->nodes = nodes; entry->score = score; entry->remaining_depth = depth - stackp; entry->routine = routine; entry->str = str; entry->result = result; entry->move = move; for (r = 0; r < MAX_READING_CACHE_DEPTH; r++) { if (r < stackp) get_move_from_stack(r, &(entry->stack[r]), &(entry->move_color[r])); else { entry->stack[r] = 0; entry->move_color[r] = EMPTY; } } /* Remains to set the board. We let the active area be the contested * string and reading shadow + adjacent empty and strings + * neighbors of active area so far + one more expansion from empty * to empty. */ for (k = BOARDMIN; k < BOARDMAX; k++) active[k] = shadow[k]; mark_string(str, active, 1); /* To be safe, also add the successful move. */ if (result != 0 && move != 0) active[move] = 1; /* Add adjacent strings and empty. */ for (k = BOARDMIN; k < BOARDMAX; k++) { if (!ON_BOARD(k)) continue; if (active[k] != 0) continue; if ((ON_BOARD(SOUTH(k)) && active[SOUTH(k)] == 1) || (ON_BOARD(WEST(k)) && active[WEST(k)] == 1) || (ON_BOARD(NORTH(k)) && active[NORTH(k)] == 1) || (ON_BOARD(EAST(k)) && active[EAST(k)] == 1)) { if (IS_STONE(board[k])) mark_string(k, active, 2); else active[k] = 2; } } /* Remove invincible strings. No point adding their liberties and * neighbors. */ for (k = BOARDMIN; k < BOARDMAX; k++) { if (!ON_BOARD(k)) continue; if (IS_STONE(board[k]) && worm[k].invincible) active[k] = 0; } /* Expand empty to empty. */ for (k = BOARDMIN; k < BOARDMAX; k++) { if (IS_STONE(board[k]) || active[k] != 0) continue; if ((board[SOUTH(k)] == EMPTY && active[SOUTH(k)] == 2) || (board[WEST(k)] == EMPTY && active[WEST(k)] == 2) || (board[NORTH(k)] == EMPTY && active[NORTH(k)] == 2) || (board[EAST(k)] == EMPTY && active[EAST(k)] == 2)) active[k] = 3; } /* Add neighbors of active area so far. */ for (k = BOARDMIN; k < BOARDMAX; k++) { if (!ON_BOARD(k)) continue; if (active[k] != 0) continue; if ((ON_BOARD(SOUTH(k)) && active[SOUTH(k)] > 0 && active[SOUTH(k)] < 4) || (ON_BOARD(WEST(k)) && active[WEST(k)] > 0 && active[WEST(k)] < 4) || (ON_BOARD(NORTH(k)) && active[NORTH(k)] > 0 && active[NORTH(k)] < 4) || (ON_BOARD(EAST(k)) && active[EAST(k)] > 0 && active[EAST(k)] < 4)) active[k] = 4; } /* Also add the previously played stones to the active area. */ for (r = 0; r < stackp; r++) active[entry->stack[r]] = 5; for (k = BOARDMIN; k < BOARDMAX; k++) { if (!ON_BOARD(k)) continue; entry->board[k] = active[k] != 0 ? board[k] : GRAY; } if (0) { gprintf("%o Stored result in cache (entry %d):\n", persistent_reading_cache_size); print_persistent_reading_cache_entry(persistent_reading_cache_size); gprintf("%o Reading shadow was:\n"); draw_reading_shadow(); } persistent_reading_cache_size++; }