1use std::fmt::{Debug, Display};
2use std::hash::Hash;
3
4use internal_iterator::InternalIterator;
5use rand::Rng;
6
7use crate::symmetry::Symmetry;
8
9#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
10pub enum Player {
11 A,
12 B,
13}
14
15#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
16pub enum Outcome {
17 WonBy(Player),
18 Draw,
19}
20
21pub trait Board: Debug + Display + Clone + Eq + Hash + Send + Sync where for<'a> Self: BoardAvailableMoves<'a, Self> {
23 type Move: Debug + Copy + Eq + Ord + Hash + Send + Sync;
24 type Symmetry: Symmetry;
25
26 fn can_lose_after_move() -> bool;
30
31 fn game_length_bounds() -> (u32, Option<u32>);
34
35 fn next_player(&self) -> Player;
38
39 fn is_available_move(&self, mv: Self::Move) -> bool;
41
42 fn random_available_move(&self, rng: &mut impl Rng) -> Self::Move {
45 let count = self.available_moves().count();
46 let index = rng.gen_range(0..count);
47 self.available_moves().nth(index).unwrap()
48 }
49
50 fn play(&mut self, mv: Self::Move);
53
54 fn clone_and_play(&self, mv: Self::Move) -> Self {
56 let mut next = self.clone();
57 next.play(mv);
58 next
59 }
60
61 fn outcome(&self) -> Option<Outcome>;
63
64 fn is_done(&self) -> bool {
66 self.outcome().is_some()
67 }
68
69 fn map(&self, sym: Self::Symmetry) -> Self;
71
72 fn map_move(sym: Self::Symmetry, mv: Self::Move) -> Self::Move;
74}
75
76pub trait BoardAvailableMoves<'a, B: Board> {
79 type MoveIterator: InternalIterator<Item=B::Move>;
80 type AllMoveIterator: InternalIterator<Item=B::Move>;
81
82 fn all_possible_moves() -> Self::AllMoveIterator;
86
87 fn available_moves(&'a self) -> Self::MoveIterator;
91}
92
93impl Player {
94 pub fn other(self) -> Player {
95 match self {
96 Player::A => Player::B,
97 Player::B => Player::A,
98 }
99 }
100
101 pub fn index(self) -> u8 {
102 match self {
103 Player::A => 0,
104 Player::B => 1,
105 }
106 }
107
108 pub fn sign(self, pov: Player) -> i8 {
109 if self == pov { 1 } else { -1 }
110 }
111}
112
113impl Outcome {
114 pub fn other(self) -> Outcome {
115 match self {
116 Outcome::WonBy(player) => Outcome::WonBy(player.other()),
117 Outcome::Draw => Outcome::Draw,
118 }
119 }
120
121 pub fn unwrap_player(self) -> Player {
122 match self {
123 Outcome::WonBy(player) => player,
124 Outcome::Draw => panic!("Expected a player, got {:?}", self),
125 }
126 }
127
128 pub fn sign(self, pov: Player) -> i8 {
129 match self {
130 Outcome::WonBy(player) => player.sign(pov),
131 Outcome::Draw => 0,
132 }
133 }
134
135 pub fn inf_sign(self, pov: Player) -> f32 {
136 match self {
137 Outcome::WonBy(player) => player.sign(pov) as f32 * f32::INFINITY,
138 Outcome::Draw => 0.0,
139 }
140 }
141}
142