pachi_py/pachi/tactics/util.c (92 lines of code) (raw):
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#define DEBUG
#include "board.h"
#include "debug.h"
#include "tactics/util.h"
bool
board_stone_radar(struct board *b, coord_t coord, int distance)
{
int bounds[4] = {
coord_x(coord, b) - distance,
coord_y(coord, b) - distance,
coord_x(coord, b) + distance,
coord_y(coord, b) + distance
};
for (int i = 0; i < 4; i++)
if (bounds[i] < 1)
bounds[i] = 1;
else if (bounds[i] > board_size(b) - 2)
bounds[i] = board_size(b) - 2;
for (int x = bounds[0]; x <= bounds[2]; x++)
for (int y = bounds[1]; y <= bounds[3]; y++)
if (board_atxy(b, x, y) != S_NONE) {
/* fprintf(stderr, "radar %d,%d,%d: %d,%d (%d)\n",
coord_x(coord, b), coord_y(coord, b),
distance, x, y, board_atxy(b, x, y)); */
return true;
}
return false;
}
void
cfg_distances(struct board *b, coord_t start, int *distances, int maxdist)
{
/* Queue for d+1 spots; no two spots of the same group
* should appear in the queue. */
#define qinc(x) (x = ((x + 1) >= board_size2(b) ? ((x) + 1 - board_size2(b)) : (x) + 1))
coord_t queue[board_size2(b)]; int qstart = 0, qstop = 0;
foreach_point(b) {
distances[c] = board_at(b, c) == S_OFFBOARD ? maxdist + 1 : -1;
} foreach_point_end;
queue[qstop++] = start;
for (int d = 0; d <= maxdist; d++) {
/* Process queued moves, while setting the queue
* for new wave. */
int qa = qstart, qb = qstop;
qstart = qstop;
for (int q = qa; q < qb; qinc(q)) {
#define cfg_one(coord, grp) do {\
distances[coord] = d; \
foreach_neighbor (b, coord, { \
if (distances[c] < 0 && (!grp || group_at(b, coord) != grp)) { \
queue[qstop] = c; \
qinc(qstop); \
} \
}); \
} while (0)
coord_t cq = queue[q];
if (distances[cq] >= 0)
continue; /* We already looked here. */
if (board_at(b, cq) == S_NONE) {
cfg_one(cq, 0);
} else {
group_t g = group_at(b, cq);
foreach_in_group(b, g) {
cfg_one(c, g);
} foreach_in_group_end;
}
#undef cfg_one
}
}
foreach_point(b) {
if (distances[c] < 0)
distances[c] = maxdist + 1;
} foreach_point_end;
}
floating_t
board_effective_handicap(struct board *b, int first_move_value)
{
/* This can happen if the opponent passes during handicap
* placing phase. */
// assert(b->handicap != 1);
/* Always return 0 for even games, in particular if
* first_move_value is set on purpose to a value different
* from the correct theoretical value (2*komi). */
if (!b->handicap)
return b->komi == 0.5 ? 0.5 * first_move_value : 7.5 - b->komi;
return b->handicap * first_move_value + 0.5 - b->komi;
}
bool
pass_is_safe(struct board *b, enum stone color, struct move_queue *mq)
{
floating_t score = board_official_score(b, mq);
if (color == S_BLACK)
score = -score;
//fprintf(stderr, "%d score %f\n", color, score);
return (score >= 0);
}
/* On average 20% of points remain empty at the end of a game */
#define EXPECTED_FINAL_EMPTY_PERCENT 20
/* Returns estimated number of remaining moves for one player until end of game. */
int
board_estimated_moves_left(struct board *b)
{
int total_points = (board_size(b)-2)*(board_size(b)-2);
int moves_left = (b->flen - total_points*EXPECTED_FINAL_EMPTY_PERCENT/100)/2;
return moves_left > MIN_MOVES_LEFT ? moves_left : MIN_MOVES_LEFT;
}