Example #1
0
/* 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++;
}