Skip to main content

chess/id/
basis.rs

1use crate::{
2    board::*,
3    finite::Empty as _,
4    position::{EnPassant, EnPassantTable},
5    square::*,
6};
7
8use super::{Id, fold};
9
10#[cfg(feature = "const-fn-standard-id")]
11// This allow turns the error into a warning, which cannot currently be suppressed.
12#[allow(long_running_const_eval)]
13pub const STANDARD: Basis = Basis::generate_standard();
14#[cfg(not(feature = "const-fn-standard-id"))]
15include!("standard.rs");
16
17#[cfg(feature = "const-fn-polyglot-id")]
18pub const POLYGLOT: Basis = Basis::empty();
19#[cfg(not(feature = "const-fn-polyglot-id"))]
20include!("polyglot.rs");
21
22type BoardTable<T> = SquareTable<PlayerTable<RoleTable<T>>>;
23type CastleTable<T> = PlayerTable<FileTable<T>>;
24
25#[derive(Clone, Copy, Debug)]
26pub struct Basis {
27    pub board: BoardTable<Id>,
28    pub turn: PlayerTable<Id>,
29    pub castle: CastleTable<Id>,
30    pub en_passant: EnPassantTable<Id>,
31}
32
33impl Basis {
34    pub const fn empty() -> Self {
35        Self {
36            board: BoardTable::EMPTY,
37            turn: PlayerTable::EMPTY,
38            castle: CastleTable::EMPTY,
39            en_passant: EnPassantTable::EMPTY,
40        }
41    }
42
43    pub const fn generate_standard() -> Self {
44        Self {
45            board: board_table(),
46            turn: turn_table(),
47            castle: castle_table(),
48            en_passant: en_passant_table(),
49        }
50    }
51}
52
53const fn board_table() -> BoardTable<Id> {
54    let mut squares = SquareTable::empty();
55
56    finite_for!(square in Square {
57        let mut players = PlayerTable::empty();
58        finite_for!(player in Player {
59            let mut roles = RoleTable::empty();
60            finite_for!(role in Role {
61                let entry = entry_4("board", square.name(), player.name(), role.name());
62                roles.set(role, entry);
63            });
64            players.set(player, roles);
65        });
66        squares.set(square, players);
67    });
68    squares
69}
70
71const fn castle_table() -> CastleTable<Id> {
72    let mut players = PlayerTable::empty();
73    finite_for!(player in Player {
74        let mut files = FileTable::empty();
75        finite_for!(file in File {
76            let entry = entry_3("castle", player.name(), file.name());
77            files.set(file, entry);
78        });
79        players.set(player, files);
80    });
81    players
82}
83
84const fn turn_table() -> PlayerTable<Id> {
85    let mut players = PlayerTable::empty();
86    finite_for!(player in Player {
87        let entry = entry_2("turn", player.name());
88        players.set(player, entry);
89    });
90    players
91}
92
93const fn en_passant_table() -> EnPassantTable<Id> {
94    let mut squares = EnPassantTable::empty();
95    finite_for!(en_passant in EnPassant {
96        let entry = entry_2("en-passant", en_passant.name());
97        squares.set(en_passant, entry);
98    });
99    squares
100}
101
102const fn entry_2(a: &str, b: &str) -> Id {
103    Id(fold(
104        sha2_const::Sha256::new().update(a.as_bytes()).update(b":").update(b.as_bytes()).finalize(),
105    ))
106}
107
108const fn entry_3(a: &str, b: &str, c: &str) -> Id {
109    Id(fold(
110        sha2_const::Sha256::new()
111            .update(a.as_bytes())
112            .update(b":")
113            .update(b.as_bytes())
114            .update(b":")
115            .update(c.as_bytes())
116            .finalize(),
117    ))
118}
119
120const fn entry_4(a: &str, b: &str, c: &str, d: &str) -> Id {
121    Id(fold(
122        sha2_const::Sha256::new()
123            .update(a.as_bytes())
124            .update(b":")
125            .update(b.as_bytes())
126            .update(b":")
127            .update(c.as_bytes())
128            .update(b":")
129            .update(d.as_bytes())
130            .finalize(),
131    ))
132}