tangled
alpha
login
or
join now
nove.dev
/
outsider
0
fork
atom
cleanroom implementation of a chess engine. doesn't work :)
0
fork
atom
overview
issues
pulls
pipelines
add pawn moves :3
nove.dev
7 months ago
ff00f498
c3c200df
+186
-85
1 changed file
expand all
collapse all
unified
split
src
lib.rs
+186
-85
src/lib.rs
reviewed
···
52
52
fn value(&self) -> u32 {
53
53
self.backing.count_ones()
54
54
}
55
55
+
fn or(self, other: Self) -> Self {
56
56
+
Self {
57
57
+
backing: self.backing | other.backing,
58
58
+
}
59
59
+
}
55
60
}
56
61
57
62
struct Move {
···
63
68
64
69
pub struct Board {
65
70
white_to_move: bool,
71
71
+
66
72
white_pawns: BitBoard,
67
73
white_knights: BitBoard,
68
74
white_bishops: BitBoard,
69
75
white_rooks: BitBoard,
70
76
white_queens: BitBoard,
71
77
white_king: BitBoard,
78
78
+
72
79
black_pawns: BitBoard,
73
80
black_knights: BitBoard,
74
81
black_bishops: BitBoard,
···
145
152
+ self.black_queens.value() * 9;
146
153
white_value as i32 - black_value as i32
147
154
}
155
155
+
fn white_pieces(&self) -> BitBoard {
156
156
+
self.white_pawns
157
157
+
.or(self.white_knights)
158
158
+
.or(self.white_bishops)
159
159
+
.or(self.white_rooks)
160
160
+
.or(self.white_queens)
161
161
+
.or(self.white_king)
162
162
+
}
163
163
+
164
164
+
fn black_pieces(&self) -> BitBoard {
165
165
+
self.black_pawns
166
166
+
.or(self.black_knights)
167
167
+
.or(self.black_bishops)
168
168
+
.or(self.black_rooks)
169
169
+
.or(self.black_queens)
170
170
+
.or(self.black_king)
171
171
+
} /*
148
172
pub fn make_move(&mut self, algebra: &str) {
149
149
-
let (mover, non_mover) = self.movers_or_not();
150
150
-
if algebra == "O-O" || algebra == "0-0" {
151
151
-
mover
152
152
-
.iter_mut()
153
153
-
.find(|lp| lp.piece == Piece::King)
154
154
-
.unwrap()
155
155
-
.file = 6; //castles kingside
156
156
-
mover
157
157
-
.iter_mut()
158
158
-
.find(|lp| lp.piece == Piece::Rook && lp.file == 7)
159
159
-
.unwrap()
160
160
-
.file = 5;
161
161
-
} else if algebra == "O-O-O" || algebra == "0-0-0" {
162
162
-
mover
163
163
-
.iter_mut()
164
164
-
.find(|lp| lp.piece == Piece::King)
165
165
-
.unwrap()
166
166
-
.file = 2; //castles queenside
167
167
-
mover
168
168
-
.iter_mut()
169
169
-
.find(|lp| lp.piece == Piece::Rook && lp.file == 0)
170
170
-
.unwrap()
171
171
-
.file = 3;
173
173
+
let (mover, non_mover) = self.movers_or_not();
174
174
+
if algebra == "O-O" || algebra == "0-0" {
175
175
+
mover
176
176
+
.iter_mut()
177
177
+
.find(|lp| lp.piece == Piece::King)
178
178
+
.unwrap()
179
179
+
.file = 6; //castles kingside
180
180
+
mover
181
181
+
.iter_mut()
182
182
+
.find(|lp| lp.piece == Piece::Rook && lp.file == 7)
183
183
+
.unwrap()
184
184
+
.file = 5;
185
185
+
} else if algebra == "O-O-O" || algebra == "0-0-0" {
186
186
+
mover
187
187
+
.iter_mut()
188
188
+
.find(|lp| lp.piece == Piece::King)
189
189
+
.unwrap()
190
190
+
.file = 2; //castles queenside
191
191
+
mover
192
192
+
.iter_mut()
193
193
+
.find(|lp| lp.piece == Piece::Rook && lp.file == 0)
194
194
+
.unwrap()
195
195
+
.file = 3;
196
196
+
} else {
197
197
+
let mut move_segments = vec![];
198
198
+
let mut iter = algebra.chars();
199
199
+
while let Some(ch) = iter.next() {
200
200
+
if let Some(piece) = Piece::from_char(ch) {
201
201
+
move_segments.push(MoveSegment::Piece(piece));
202
202
+
} else if let Some(rank) = ch.to_digit(10) {
203
203
+
move_segments.push(MoveSegment::File(rank as usize));
204
204
+
} else if ch >= 'a' && ch <= 'h' {
205
205
+
move_segments.push(MoveSegment::File(ch as usize - 'a' as usize));
206
206
+
} else if ch == 'x' {
207
207
+
move_segments.push(MoveSegment::Captures)
208
208
+
} else if ch == '='
209
209
+
&& let Some(next) = iter.next() // if given bad notation this breaks, but the notation was unparseable anyway
210
210
+
&& let Some(piece) = Piece::from_char(next)
211
211
+
{
212
212
+
move_segments.push(MoveSegment::Promotion(piece));
213
213
+
}
214
214
+
}
215
215
+
if move_segments.len() == 2
216
216
+
&& let MoveSegment::File(file) = move_segments[0]
217
217
+
&& let MoveSegment::Rank(rank) = move_segments[1]
218
218
+
{
219
219
+
self.move_unambiguous(Piece::Pawn, None, None, rank, file);
220
220
+
}
221
221
+
}
222
222
+
}
223
223
+
fn move_unambiguous(
224
224
+
&mut self,
225
225
+
piece: Piece,
226
226
+
source_rank: Option<usize>,
227
227
+
source_file: Option<usize>,
228
228
+
dest_rank: usize,
229
229
+
dest_file: usize,
230
230
+
) {
231
231
+
let piece_to_move = (if self.white_to_move {
232
232
+
&mut self.white
233
233
+
} else {
234
234
+
&mut self.black
235
235
+
})
236
236
+
.iter_mut()
237
237
+
.filter(|lp| lp.piece == piece)
238
238
+
.filter(|lp| {
239
239
+
source_rank.is_none_or(|rank| rank == lp.rank)
240
240
+
&& source_file.is_none_or(|file| file == lp.file)
241
241
+
})
242
242
+
.find(|lp| {
243
243
+
self.valid_moves(lp.clone())
244
244
+
.contains(&(dest_file, dest_rank))
245
245
+
})
246
246
+
.unwrap();
247
247
+
248
248
+
self.capture_if_possible(dest_file, dest_rank);
249
249
+
piece_to_move.rank = dest_rank;
250
250
+
piece_to_move.file = dest_file;
251
251
+
}*/
252
252
+
fn pawn_moves(&self, file: u8, rank: u8) -> Vec<(u8, u8)> {
253
253
+
let white = self.white_pieces();
254
254
+
let black = self.black_pieces();
255
255
+
let white_moving = self.white_pawns.get_square(file, rank);
256
256
+
let either = white.or(black);
257
257
+
let mut moves = vec![];
258
258
+
if white_moving {
259
259
+
let (open_squares, _) = self.open_squares(file, rank, Direction::North);
260
260
+
if (open_squares) > 0 {
261
261
+
moves.push((file, rank + 1));
262
262
+
}
263
263
+
if rank == 1 && open_squares > 1 {
264
264
+
moves.push((file, rank + 2));
265
265
+
}
266
266
+
if let (0, true) = self.open_squares(file, rank, Direction::Northeast) {
267
267
+
moves.push((file + 1, rank + 1))
268
268
+
}
269
269
+
if let (0, true) = self.open_squares(file, rank, Direction::Northwest) {
270
270
+
moves.push((file - 1, rank + 1))
271
271
+
}
172
272
} else {
173
173
-
let mut move_segments = vec![];
174
174
-
let mut iter = algebra.chars();
175
175
-
while let Some(ch) = iter.next() {
176
176
-
if let Some(piece) = Piece::from_char(ch) {
177
177
-
move_segments.push(MoveSegment::Piece(piece));
178
178
-
} else if let Some(rank) = ch.to_digit(10) {
179
179
-
move_segments.push(MoveSegment::File(rank as usize));
180
180
-
} else if ch >= 'a' && ch <= 'h' {
181
181
-
move_segments.push(MoveSegment::File(ch as usize - 'a' as usize));
182
182
-
} else if ch == 'x' {
183
183
-
move_segments.push(MoveSegment::Captures)
184
184
-
} else if ch == '='
185
185
-
&& let Some(next) = iter.next() // if given bad notation this breaks, but the notation was unparseable anyway
186
186
-
&& let Some(piece) = Piece::from_char(next)
187
187
-
{
188
188
-
move_segments.push(MoveSegment::Promotion(piece));
273
273
+
let (open_squares, _) = self.open_squares(file, rank, Direction::South);
274
274
+
if open_squares > 0 {
275
275
+
moves.push((file, rank - 1))
276
276
+
}
277
277
+
if rank == 6 && open_squares > 1 {
278
278
+
moves.push((file, rank - 2))
279
279
+
}
280
280
+
281
281
+
if let (0, true) = self.open_squares(file, rank, Direction::Southeast) {
282
282
+
moves.push((file + 1, rank - 1))
283
283
+
}
284
284
+
if let (0, true) = self.open_squares(file, rank, Direction::Southwest) {
285
285
+
moves.push((file - 1, rank - 1))
286
286
+
}
287
287
+
}
288
288
+
moves
289
289
+
}
290
290
+
/// returns number of squares and whether that's a capture
291
291
+
fn open_squares(&self, mut file: u8, mut rank: u8, direction: Direction) -> (u8, bool) {
292
292
+
let white = self.white_pieces();
293
293
+
let black = self.black_pieces();
294
294
+
let white_playing = white.get_square(file, rank);
295
295
+
let mut count = 0;
296
296
+
loop {
297
297
+
match direction {
298
298
+
Direction::North => {
299
299
+
if rank == 7 {
300
300
+
return (count, false);
301
301
+
} else {
302
302
+
rank += 1
303
303
+
}
189
304
}
305
305
+
Direction::Northeast => {
306
306
+
if rank == 7 || file == 7 {
307
307
+
return (count, false);
308
308
+
} else {
309
309
+
rank += 1;
310
310
+
file += 1;
311
311
+
}
312
312
+
}
313
313
+
Direction::East => todo!(),
314
314
+
Direction::Southeast => todo!(),
315
315
+
Direction::South => todo!(),
316
316
+
Direction::Southwest => todo!(),
317
317
+
Direction::West => todo!(),
318
318
+
Direction::Northwest => todo!(),
190
319
}
191
191
-
if move_segments.len() == 2
192
192
-
&& let MoveSegment::File(file) = move_segments[0]
193
193
-
&& let MoveSegment::Rank(rank) = move_segments[1]
194
194
-
{
195
195
-
self.move_unambiguous(Piece::Pawn, None, None, rank, file);
320
320
+
if white.get_square(file, rank) {
321
321
+
return (count, !white_playing);
322
322
+
} else if black.get_square(file, rank) {
323
323
+
return (count, white_playing);
324
324
+
} else {
325
325
+
count += 1;
196
326
}
197
327
}
198
328
}
199
199
-
fn move_unambiguous(
200
200
-
&mut self,
201
201
-
piece: Piece,
202
202
-
source_rank: Option<usize>,
203
203
-
source_file: Option<usize>,
204
204
-
dest_rank: usize,
205
205
-
dest_file: usize,
206
206
-
) {
207
207
-
let piece_to_move = (if self.white_to_move {
208
208
-
&mut self.white
209
209
-
} else {
210
210
-
&mut self.black
211
211
-
})
212
212
-
.iter_mut()
213
213
-
.filter(|lp| lp.piece == piece)
214
214
-
.filter(|lp| {
215
215
-
source_rank.is_none_or(|rank| rank == lp.rank)
216
216
-
&& source_file.is_none_or(|file| file == lp.file)
217
217
-
})
218
218
-
.find(|lp| {
219
219
-
self.valid_moves(lp.clone())
220
220
-
.contains(&(dest_file, dest_rank))
221
221
-
})
222
222
-
.unwrap();
223
223
-
224
224
-
self.capture_if_possible(dest_file, dest_rank);
225
225
-
piece_to_move.rank = dest_rank;
226
226
-
piece_to_move.file = dest_file;
227
227
-
}
228
329
fn valid_moves(&self, lp: &LocatedPiece) -> Vec<(usize, usize)> {
229
330
let mut moves = vec![];
230
331
match lp.piece {
···
239
340
moves.retain(|(file, rank)| !self.mover_is_in_check(file, rank));
240
341
moves
241
342
}
242
242
-
fn movers_or_not(&mut self) -> (&mut Vec<LocatedPiece>, &mut Vec<LocatedPiece>) {
243
243
-
if self.white_to_move {
244
244
-
(&mut self.white, &mut self.black)
245
245
-
} else {
246
246
-
(&mut self.black, &mut self.white)
247
247
-
}
248
248
-
}
249
249
-
fn capture_if_possible(&mut self, file: usize, rank: usize) {
250
250
-
self.movers_or_not()
251
251
-
.1
252
252
-
.retain(|lp| lp.rank != rank && lp.file != file)
253
253
-
}
343
343
+
}
344
344
+
345
345
+
#[derive(Clone, Copy, PartialEq, Eq)]
346
346
+
enum Direction {
347
347
+
North,
348
348
+
Northeast,
349
349
+
East,
350
350
+
Southeast,
351
351
+
South,
352
352
+
Southwest,
353
353
+
West,
354
354
+
Northwest,
254
355
}
255
356
256
357
#[derive(Clone, Copy, PartialEq, Eq)]