1use core::ops;
2
3use crate::board::Bitboard;
4
5use super::Square;
6
7#[derive(Clone, Copy)]
8#[repr(i8)]
9pub enum Direction {
12 North = direction(0, 1),
13 East = direction(1, 0),
14 South = direction(0, -1),
15 West = direction(-1, 0),
16 NorthNorth = direction(0, 2),
17 SouthSouth = direction(0, -2),
18
19 NorthEast = direction(1, 1),
20 NorthWest = direction(-1, 1),
21 SouthEast = direction(1, -1),
22 SouthWest = direction(-1, -1),
23
24 KnightNorthEast = direction(1, 2),
25 KnightNorthWest = direction(-1, 2),
26 KnightEastNorth = direction(2, 1),
27 KnightEastSouth = direction(2, -1),
28 KnightSouthEast = direction(1, -2),
29 KnightSouthWest = direction(-1, -2),
30 KnightWestNorth = direction(-2, 1),
31 KnightWestSouth = direction(-2, -1),
32}
33
34const fn direction(file: i8, rank: i8) -> i8 {
35 rank * 8 + file
36}
37
38impl Direction {
39 #[inline]
40 pub const fn reverse(self) -> Direction {
41 use Direction::*;
42
43 match self {
44 North => South,
45 East => West,
46 South => North,
47 West => East,
48 NorthNorth => SouthSouth,
49 SouthSouth => NorthNorth,
50 NorthEast => SouthWest,
51 NorthWest => SouthEast,
52 SouthEast => NorthWest,
53 SouthWest => NorthEast,
54 KnightNorthEast => KnightSouthWest,
55 KnightNorthWest => KnightSouthEast,
56 KnightEastNorth => KnightWestSouth,
57 KnightEastSouth => KnightWestNorth,
58 KnightSouthEast => KnightNorthWest,
59 KnightSouthWest => KnightNorthEast,
60 KnightWestNorth => KnightEastSouth,
61 KnightWestSouth => KnightEastNorth,
62 }
63 }
64}
65
66impl Square {
68 pub const fn checked_add(self, direction: Direction) -> Option<Square> {
69 let square = self as i8;
70 let target = square + direction as i8;
71 let file_diff = (target & 0x7) - (square & 0x7);
74 if target >= 0 && target < 64 && file_diff >= -2 && file_diff <= 2 {
75 Some(Square::panicky_from_index(target as u8))
76 } else {
77 None
78 }
79 }
80
81 pub const fn full_ray(self, other: Square) -> Bitboard {
83 Bitboard::FULL_RAYS[self as usize][other as usize]
84 }
85
86 const fn index_range(self, other: Square) -> Bitboard {
101 Bitboard((!0 << self as u32) ^ (!0 << other as u32))
102 }
103
104 pub const fn index_after(self) -> Bitboard {
120 Bitboard(!0 << (self as u32 + 1))
121 }
122
123 pub const fn index_before(self) -> Bitboard {
126 Bitboard((1 << self as u32) - 1)
127 }
128
129 pub const fn east(self) -> Bitboard {
130 self.index_after().intersection(Bitboard::from_rank(self.rank()))
131 }
132
133 pub const fn west(self) -> Bitboard {
134 self.index_before().intersection(Bitboard::from_rank(self.rank()))
135 }
136
137 pub const fn between(self, other: Square) -> Bitboard {
138 self.full_ray(other).intersection(self.index_range(other)).without_first()
141 }
142
143 pub const fn aligned(self, b: Square, c: Square) -> bool {
144 self.full_ray(b).contains(c)
145 }
146}
147
148impl ops::Add<Direction> for Square {
149 type Output = Option<Square>;
150
151 fn add(self, direction: Direction) -> Option<Square> {
152 self.checked_add(direction)
153 }
154}
155
156impl ops::Add<&[Direction]> for Square {
157 type Output = Bitboard;
158
159 fn add(self, directions: &[Direction]) -> Bitboard {
160 self.checked_add_vector_const(directions)
161 }
162}