Пример #1
0
static floating_t
adaptive_permove(struct uct_dynkomi *d, struct board *b, struct tree *tree)
{
	struct dynkomi_adaptive *a = d->data;
	enum stone color = stone_other(tree->root_color);

	/* We do not use extra komi at the game end - we are not
	 * to fool ourselves at this point. */
	if (a->no_komi_at_game_end && board_estimated_moves_left(b) <= MIN_MOVES_LEFT) {
		tree->use_extra_komi = false;
		return 0;
	}

	if (DEBUGL(4))
		fprintf(stderr, "m %d/%d ekomi %f permove %f/%d\n",
			b->moves, a->lead_moves, tree->extra_komi,
			d->score.value, d->score.playouts);

	if (b->moves <= a->lead_moves)
		return bounded_komi(a, b, color,
		                    board_effective_handicap(b, 7 /* XXX */),
		                    a->max_losing_komi);

	floating_t komi = a->indicator(d, b, tree, color);
	if (DEBUGL(4))
		fprintf(stderr, "dynkomi: %f -> %f\n", tree->extra_komi, komi);
	return bounded_komi(a, b, color, komi, a->max_losing_komi);
}
Пример #2
0
static floating_t
board_game_portion(struct dynkomi_adaptive *a, struct board *b)
{
	if (!a->adapt_aport) {
		int total_moves = b->moves + 2 * board_estimated_moves_left(b);
		return (floating_t) b->moves / total_moves;
	} else {
		int brsize = board_size(b) - 2;
		return 1.0 - (floating_t) b->flen / (brsize * brsize);
	}
}
Пример #3
0
/* Set worst.time to all available remaining time (main time plus usable
 * byoyomi), to be spread over returned number of moves (expected game
 * length minus moves to be played in final byoyomi - if we would not be
 * able to spend more time on them in main time anyway). */
static int
time_stop_set_remaining(struct time_info *ti, struct board *b, double net_lag, struct time_stop *stop)
{
	int moves_left = board_estimated_moves_left(b);
	stop->worst.time = ti->len.t.main_time;

	if (!ti->len.t.byoyomi_time)
		return moves_left;

	/* Time for one move in byoyomi. */
	assert(ti->len.t.byoyomi_stones > 0);
	double move_time = ti->len.t.byoyomi_time / ti->len.t.byoyomi_stones;

	/* (i) Plan to extend our thinking time to make use of byoyom. */

	/* For Japanese byoyomi with N>1 periods, we use N-1 periods
	 * as main time, keeping the last one as insurance against
	 * unexpected net lag. */
	if (ti->len.t.byoyomi_periods > 2) {
		stop->worst.time += (ti->len.t.byoyomi_periods - 2) * move_time;
		// Will add 1 more byoyomi_time just below
	}

	/* In case of Canadian byoyomi, include time that can be spent
	 * on its first move. */
	stop->worst.time += move_time;

	/* (ii) Do not play faster in main time than we would in byoyomi. */

	/* Maximize the number of moves played uniformly in main time,
	 * while not playing faster in main time than in byoyomi.
	 * At this point, the main time remaining is stop->worst.time and
	 * already includes the first (canadian) or N-1 byoyomi periods. */
	double real_move_time = move_time - net_lag;
	if (real_move_time > 0) {
		int main_moves = stop->worst.time / real_move_time;
		if (moves_left > main_moves) {
			/* We plan to do too many moves in main time,
			 * do the rest in byoyomi. */
			moves_left = main_moves;
		}
		if (moves_left <= 0) // possible if too much lag
			moves_left = 1;
	}

	return moves_left;
}
Пример #4
0
/* Adjust the recommended per-move time based on the current game phase.
 * We expect stop->worst to be total time available, stop->desired the current
 * per-move time allocation, and set stop->desired to adjusted per-move time. */
static void
time_stop_phase_adjust(struct board *b, int fuseki_end, int yose_start, struct time_stop *stop)
{
	int bsize = (board_size(b)-2)*(board_size(b)-2);
	fuseki_end = fuseki_end * bsize / 100; // move nb at fuseki end
	yose_start = yose_start * bsize / 100; // move nb at yose start
	assert(fuseki_end < yose_start);

	/* No adjustments in yose. */
	if (b->moves >= yose_start)
		return;
	int moves_to_yose = (yose_start - b->moves) / 2;
	// ^- /2 because we only consider the moves we have to play ourselves
	int left_at_yose_start = board_estimated_moves_left(b) - moves_to_yose;
	if (left_at_yose_start < MIN_MOVES_LEFT)
		left_at_yose_start = MIN_MOVES_LEFT;

	/* This particular value of middlegame_time will continuously converge
	 * to effective "yose_time" value as we approach yose_start. */
	double middlegame_time = stop->worst.time / left_at_yose_start;
	if (middlegame_time < stop->desired.time)
		return;

	if (b->moves < fuseki_end) {
		assert(fuseki_end > 0);
		/* At the game start, use stop->desired.time (rather
		 * conservative estimate), then gradually prolong it. */
		double beta = b->moves / fuseki_end;
		stop->desired.time = middlegame_time * beta + stop->desired.time * (1 - beta);

	} else { assert(b->moves < yose_start);
		/* Middlegame, start with relatively large value, then
		 * converge to the uniform-timeslice yose value. */
		stop->desired.time = middlegame_time;
	}
}
Пример #5
0
/* Pre-process time_info for search control and sets the desired stopping conditions. */
void
time_stop_conditions(struct time_info *ti, struct board *b, int fuseki_end, int yose_start,
		     floating_t max_maintime_ratio, struct time_stop *stop)
{
	/* We must have _some_ limits by now, be it random default values! */
	assert(ti->period != TT_NULL);

	/* Special-case limit by number of simulations. */
	if (ti->dim == TD_GAMES) {
		if (ti->period == TT_TOTAL) {
			ti->period = TT_MOVE;
			ti->len.games /= board_estimated_moves_left(b);
		}

		stop->desired.playouts = ti->len.games;
		/* We force worst == desired, so note that we will NOT loop
		 * until best == winner. */
		stop->worst.playouts = ti->len.games;
		return;
	}

	assert(ti->dim == TD_WALLTIME);


	/* Minimum net lag (seconds) to be reserved in the time for move. */
	double net_lag = MAX_NET_LAG;
	net_lag += time_now() - ti->len.t.timer_start;
	// TODO: keep statistics to get good estimate of lag not just current move


	if (ti->period == TT_TOTAL && time_in_byoyomi(ti)) {
		/* Technically, we are still in main time, but we can
		 * effectively switch to byoyomi scheduling since we
		 * have less time available than one byoyomi move takes. */
		ti->period = TT_MOVE;
	}


	if (ti->period == TT_MOVE) {
		/* We are in byoyomi, or almost! */

		/* The period can still include some tiny remnant of main
		 * time if we are just switching to byoyomi. */
		double period_len = ti->len.t.byoyomi_time + ti->len.t.main_time;

		stop->worst.time = period_len;
		assert(ti->len.t.byoyomi_stones > 0);
		stop->desired.time = period_len / ti->len.t.byoyomi_stones;

		/* Use a larger safety margin if we risk losing on time on
		 * this move; it makes no sense to have 30s byoyomi and wait
		 * until 28s to play our move). */
		if (stop->desired.time >= period_len - net_lag) {
			double safe_margin = RESERVED_BYOYOMI_PERCENT * stop->desired.time / 100;
			if (safe_margin > net_lag)
				net_lag = safe_margin;
		}

		/* Make recommended_old == average(recommended_new, max) */
		double worst_time = stop->desired.time * MAX_BYOYOMI_TIME_RATIO;
		if (worst_time < stop->worst.time)
			stop->worst.time = worst_time;
		stop->desired.time *= (2 - MAX_BYOYOMI_TIME_RATIO);

	} else { assert(ti->period == TT_TOTAL);
		/* We are in main time. */

		assert(ti->len.t.main_time > 0);
		/* Set worst.time to all available remaining time, to be spread
		 * over returned number of moves. */
		int moves_left = time_stop_set_remaining(ti, b, net_lag, stop);

		/* Allocate even slice of the remaining time for next move. */
		stop->desired.time = stop->worst.time / moves_left;
		assert(stop->desired.time > 0 && stop->worst.time > 0);
		assert(stop->desired.time <= stop->worst.time + 0.001);

		/* Furthermore, tweak the slice based on the game phase. */
		time_stop_phase_adjust(b, fuseki_end, yose_start, stop);

		/* Put final upper bound on maximal time spent on the move.
		 * Keep enough time for sudden death (or near SD) games. */
		double worst_time = stop->desired.time;
		if (ti->len.t.byoyomi_time_max > ti->len.t.byoyomi_stones_max) {
			worst_time *= max_maintime_ratio;
		} else {
			worst_time *= MAX_SUDDEN_DEATH_RATIO;
		}
		if (worst_time < stop->worst.time)
			stop->worst.time = worst_time;
		if (stop->desired.time > stop->worst.time)
			stop->desired.time = stop->worst.time;
	}

	if (DEBUGL(1))
		fprintf(stderr, "desired %0.2f, worst %0.2f, clock [%d] %0.2f + %0.2f/%d*%d, lag %0.2f\n",
			stop->desired.time, stop->worst.time,
			ti->dim, ti->len.t.main_time,
			ti->len.t.byoyomi_time, ti->len.t.byoyomi_stones,
			ti->len.t.byoyomi_periods, net_lag);

	/* Account for lag. */
	lag_adjust(&stop->desired.time, net_lag);
	lag_adjust(&stop->worst.time, net_lag);
}