shuyi_core/bots/determinize.rs
1//! What a bot that plans may look at: a copy of the game as its side
2//! knows it ([`Determinize`]), and how good a state is for a side
3//! ([`Evaluate`]).
4//!
5//! A bot that plans plays moves out on copies of the game. Cloning the
6//! state itself would show it the luck to come (the rolls waiting in the
7//! state's [`SimRng`](crate::SimRng)) and whatever the other sides hide.
8//! The bots that plan on copies take only games that implement
9//! [`Determinize`], so each game decides what its bots may see
10//! (ADR-0027).
11
12use super::Sides;
13
14/// A game that can make a copy of itself as one side knows it.
15pub trait Determinize: Sides + Clone {
16 /// A copy of the state as `side` knows it, with everything `side`
17 /// can't see redrawn from `seed`: the luck to come (a new
18 /// [`SimRng::new(seed)`](crate::SimRng::new)), and the other sides'
19 /// hidden things (a hand dealt again from what is left, a piece that
20 /// hasn't shown up yet removed).
21 ///
22 /// The copy must list the same [`legal_commands`](crate::TurnRules::legal_commands)
23 /// as `self`, in the same order, and accept each of them: the
24 /// [`Rollout`](crate::Rollout) and [`TurnPlan`](crate::TurnPlan) bots
25 /// check the list and panic when it differs.
26 ///
27 /// A game with no luck and nothing hidden returns `self.clone()` and
28 /// says so in a comment. A game whose difficulty lets a bot see more
29 /// says so here.
30 #[must_use]
31 fn determinize(&self, side: Self::Side, seed: u64) -> Self;
32}
33
34/// How good a state is for a side: higher is better, in whole points.
35pub trait Evaluate<R: Sides> {
36 /// How good `end` is for `side`, reached from `start` (the state the
37 /// decision began in). A score that only needs the end ignores
38 /// `start`; one that counts what was lost on the way compares the
39 /// two. A finished game scores its outcome.
40 fn score(&self, start: &R, end: &R, side: R::Side) -> i32;
41}
42
43impl<R: Sides, F: Fn(&R, &R, R::Side) -> i32> Evaluate<R> for F {
44 fn score(&self, start: &R, end: &R, side: R::Side) -> i32 {
45 self(start, end, side)
46 }
47}