1#![allow(dead_code)]
2
3#[derive(Clone, Copy)]
4pub struct Square(pub u8);
5
6pub const A1: &Square = &Square(0);
7pub const B1: &Square = &Square(1);
8pub const C1: &Square = &Square(2);
9pub const D1: &Square = &Square(3);
10pub const E1: &Square = &Square(4);
11pub const F1: &Square = &Square(5);
12pub const G1: &Square = &Square(6);
13pub const H1: &Square = &Square(7);
14pub const A2: &Square = &Square(8);
15pub const B2: &Square = &Square(9);
16pub const C2: &Square = &Square(10);
17pub const D2: &Square = &Square(11);
18pub const E2: &Square = &Square(12);
19pub const F2: &Square = &Square(13);
20pub const G2: &Square = &Square(14);
21pub const H2: &Square = &Square(15);
22pub const A3: &Square = &Square(16);
23pub const B3: &Square = &Square(17);
24pub const C3: &Square = &Square(18);
25pub const D3: &Square = &Square(19);
26pub const E3: &Square = &Square(20);
27pub const F3: &Square = &Square(21);
28pub const G3: &Square = &Square(22);
29pub const H3: &Square = &Square(23);
30pub const A4: &Square = &Square(24);
31pub const B4: &Square = &Square(25);
32pub const C4: &Square = &Square(26);
33pub const D4: &Square = &Square(27);
34pub const E4: &Square = &Square(28);
35pub const F4: &Square = &Square(29);
36pub const G4: &Square = &Square(30);
37pub const H4: &Square = &Square(31);
38pub const A5: &Square = &Square(32);
39pub const B5: &Square = &Square(33);
40pub const C5: &Square = &Square(34);
41pub const D5: &Square = &Square(35);
42pub const E5: &Square = &Square(36);
43pub const F5: &Square = &Square(37);
44pub const G5: &Square = &Square(38);
45pub const H5: &Square = &Square(39);
46pub const A6: &Square = &Square(40);
47pub const B6: &Square = &Square(41);
48pub const C6: &Square = &Square(42);
49pub const D6: &Square = &Square(43);
50pub const E6: &Square = &Square(44);
51pub const F6: &Square = &Square(45);
52pub const G6: &Square = &Square(46);
53pub const H6: &Square = &Square(47);
54pub const A7: &Square = &Square(48);
55pub const B7: &Square = &Square(49);
56pub const C7: &Square = &Square(50);
57pub const D7: &Square = &Square(51);
58pub const E7: &Square = &Square(52);
59pub const F7: &Square = &Square(53);
60pub const G7: &Square = &Square(54);
61pub const H7: &Square = &Square(55);
62pub const A8: &Square = &Square(56);
63pub const B8: &Square = &Square(57);
64pub const C8: &Square = &Square(58);
65pub const D8: &Square = &Square(59);
66pub const E8: &Square = &Square(60);
67pub const F8: &Square = &Square(61);
68pub const G8: &Square = &Square(62);
69pub const H8: &Square = &Square(63);
70
71#[derive(Debug)]
72pub struct InputError;
73
74impl std::fmt::Display for InputError {
75 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
76 write!(f, "invalid square")
77 }
78}
79
80impl Square {
81 pub fn from_string(s: &str) -> Result<Self, InputError> {
82 if s.len() == 2 {
83 let (file, rank) = s.split_at(1);
84 let sq: u8 = match file {
85 "a" => 0,
86 "b" => 1,
87 "c" => 2,
88 "d" => 3,
89 "e" => 4,
90 "f" => 5,
91 "g" => 6,
92 "h" => 7,
93 _ => return Err(InputError),
94 } + match rank {
95 "1" => 0,
96 "2" => 8,
97 "3" => 16,
98 "4" => 24,
99 "5" => 32,
100 "6" => 40,
101 "7" => 48,
102 "8" => 56,
103 _ => return Err(InputError),
104 };
105 Ok(Self(sq))
106 } else {
107 Err(InputError)
108 }
109 }
110
111 pub fn from_bitboard(bitboard: u64) -> Self {
112 for i in 0..64u8 {
113 let sq = Square(i);
114 if sq.test(bitboard) {
115 return sq
116 }
117 }
118 panic!("bitboard empty {}", bitboard);
119 }
120
121 pub fn rank(&self) -> u8 {
122 return self.0 / 8
123 }
124
125 pub fn file(&self) -> u8 {
126 return self.0 % 8
127 }
128
129 pub fn north(&self, cnt: u8) -> Option<Self> {
130 if cnt > 7 {
131 return None
132 }
133 if self.rank() > (7 - cnt) {
134 None
135 } else {
136 Some(Self(self.0 + 8 * cnt))
137 }
138 }
139
140 pub fn east(&self, cnt: u8) -> Option<Self> {
141 if cnt > 7 {
142 return None
143 }
144 if self.file() > (7 - cnt) {
145 None
146 } else {
147 Some(Self(self.0 + cnt))
148 }
149 }
150
151 pub fn west(&self, cnt: u8) -> Option<Self> {
152 if cnt > 7 {
153 return None
154 }
155 if self.file() < cnt {
156 None
157 } else {
158 Some(Self(self.0 - cnt))
159 }
160 }
161
162 pub fn south(&self, cnt: u8) -> Option<Self> {
163 if cnt > 7 {
164 return None
165 }
166 if self.rank() < cnt {
167 None
168 } else {
169 Some(Self(self.0 - 8 * cnt))
170 }
171 }
172
173 pub fn north_east(&self, cnt: u8) -> Option<Self> {
174 self.north(cnt)?.east(cnt)
175 }
176
177 pub fn north_west(&self, cnt: u8) -> Option<Self> {
178 self.north(cnt)?.west(cnt)
179 }
180
181 pub fn south_east(&self, cnt: u8) -> Option<Self> {
182 self.south(cnt)?.east(cnt)
183 }
184
185 pub fn south_west(&self, cnt: u8) -> Option<Self> {
186 self.south(cnt)?.west(cnt)
187 }
188
189 pub fn test(&self, bitboard: u64) -> bool {
190 bitboard & self.tester() > 0
191 }
192
193 pub fn tester(&self) -> u64 {
194 1 << (63 - self.0)
195 }
196}
197
198impl std::fmt::Display for Square {
199 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
200 let file = match self.file() {
201 0 => "a",
202 1 => "b",
203 2 => "c",
204 3 => "d",
205 4 => "e",
206 5 => "f",
207 6 => "g",
208 _ => "h",
209 };
210 let rank = self.rank() + 1;
211 write!(f, "{}{}", file, rank)
212 }
213}
214
215impl PartialEq for Square {
216 fn eq(&self, other: &Self) -> bool {
217 self.0 == other.0
218 }
219}
220
221#[cfg(test)]
222mod tests {
223 use crate::square::*;
224
225 #[test]
226 fn it_parses_e4() {
227 let sq = Square::from_string("e4").unwrap();
228 assert_eq!(sq.0, E4.0);
229 }
230}