Skip to content

Commit e06619f

Browse files
committed
Completely rework pin mechanics implementation
Implement pawn promote move Add more tests
1 parent bafa586 commit e06619f

23 files changed

Lines changed: 746 additions & 554 deletions

src/board.rs

Lines changed: 184 additions & 169 deletions
Large diffs are not rendered by default.

src/buff.rs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,17 @@
11
use std::cell::RefCell;
22
use crate::point::Point;
33

4-
#[derive(Debug, PartialEq, Copy, Clone)]
5-
pub enum PromotePiece {
6-
Bishop,
7-
Knight,
8-
Queen,
9-
Rook,
10-
}
11-
124
#[derive(Debug, PartialEq, Copy, Clone)]
135
pub enum Buff {
146
Castle,
157
EnPassant(Point, Point),
16-
Promote(PromotePiece),
178
AdditionalPoint, // A pawn buff to allow going one additional point further
189
}
1910

2011
#[derive(Debug)]
2112
struct BuffsList {
2213
pub castle: Option<Buff>,
2314
pub en_passant: Option<Buff>,
24-
pub promote: Option<Buff>,
2515
pub additional_point: Option<Buff>,
2616
}
2717

@@ -30,7 +20,6 @@ impl BuffsList {
3020
Self {
3121
castle: None,
3222
en_passant: None,
33-
promote: None,
3423
additional_point: None,
3524
}
3625
}
@@ -39,7 +28,6 @@ impl BuffsList {
3928
match buff {
4029
Buff::Castle => { self.castle = Some(buff) },
4130
Buff::EnPassant(_, _) => { self.en_passant = Some(buff) },
42-
Buff::Promote(_) => { self.promote = Some(buff) },
4331
Buff::AdditionalPoint => { self.additional_point = Some(buff) },
4432
}
4533
}
@@ -107,7 +95,6 @@ impl BuffsCollection {
10795
let buffs = [
10896
list.castle.as_ref(),
10997
list.en_passant.as_ref(),
110-
list.promote.as_ref(),
11198
list.additional_point.as_ref(),
11299
];
113100
buffs

src/debuff.rs

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
use std::cell::RefCell;
2-
use crate::vector::Vector;
32

43
#[derive(Debug, PartialEq, Copy, Clone)]
54
pub enum Debuff {
65
Captured,
76
Check,
87
Checkmate,
9-
Pin(Vector),
108
}
119

1210
#[derive(Debug)]
1311
struct DebuffsList {
1412
pub captured: Option<Debuff>,
1513
pub check: Option<Debuff>,
1614
pub checkmate: Option<Debuff>,
17-
pub pin: Option<Debuff>,
1815
}
1916

2017
impl DebuffsList {
@@ -23,7 +20,6 @@ impl DebuffsList {
2320
captured: None,
2421
check: None,
2522
checkmate: None,
26-
pin: None,
2723
}
2824
}
2925

@@ -32,7 +28,6 @@ impl DebuffsList {
3228
Debuff::Captured => { self.captured = Some(debuff) },
3329
Debuff::Check => { self.check = Some(debuff) },
3430
Debuff::Checkmate => { self.checkmate = Some(debuff) },
35-
Debuff::Pin(_) => { self.pin = Some(debuff) },
3631
}
3732
}
3833
}
@@ -55,22 +50,6 @@ impl DebuffsCollection {
5550
self.debuffs.borrow_mut().add(debuff)
5651
}
5752

58-
pub fn pin(&self) -> Option<Vector> {
59-
match self.debuffs.borrow().pin {
60-
Some(debuff) => {
61-
match debuff {
62-
Debuff::Pin(v) => Some(v),
63-
_ => panic!("Invalid pin debuff {:?}!", debuff)
64-
}
65-
},
66-
None => None
67-
}
68-
}
69-
70-
pub fn remove_pin(&self) {
71-
self.debuffs.borrow_mut().pin = None;
72-
}
73-
7453
pub fn remove_check(&self) {
7554
self.debuffs.borrow_mut().check = None;
7655
}
@@ -81,7 +60,7 @@ impl DebuffsCollection {
8160

8261
pub fn to_vec(&self) -> Vec<Debuff> {
8362
let list = self.debuffs.borrow();
84-
[list.captured, list.check, list.checkmate, list.pin]
63+
[list.captured, list.check, list.checkmate]
8564
.iter()
8665
.filter(|debuff| debuff.is_some())
8766
.map(|debuff| debuff.unwrap())

src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ pub mod debuff;
1313
pub mod moves_map;
1414
pub mod piece_move;
1515
pub mod castle_points;
16-
mod pins_map;
16+
mod promote_piece;
17+
mod x_ray_pieces;

src/moves_map.rs

Lines changed: 70 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
use std::rc::Rc;
22
use rustc_hash::{FxHashMap, FxHashSet};
3+
use crate::color::Color;
34
use crate::piece_move::PieceMove;
45
use crate::pieces::Piece;
56
use crate::point::Point;
67

78
type MovesSetT = FxHashSet<PieceMove>;
8-
type PiecesSetT = FxHashSet<(Rc<Piece>, PieceMove)>;
9+
type PiecesSetT = FxHashMap<Rc<Piece>, MovesSetT>;
910
type PieceToMovesMapT = FxHashMap<Rc<Piece>, MovesSetT>;
1011
type PointToPiecesMapT = FxHashMap<Point, PiecesSetT>;
1112

@@ -47,17 +48,23 @@ impl MoveConstraints {
4748

4849
pub struct MovesMap {
4950
piece_to_moves: PieceToMovesMapT,
51+
// This is Point-to-Pieces-to-Moves structure that allows to fetch all moves for the certain
52+
// piece in the given point. It is useful because there can be several moves that ends on the
53+
// same point, but have different meaning. E.g. a promotion of a pawn ends up on the same point,
54+
// but with different promotion piece
5055
point_to_pieces: PointToPiecesMapT,
5156
// Moves map of pieces, except the king when the king is in check
52-
constraints: MoveConstraints,
57+
general_constraints: MoveConstraints,
58+
pin_constraints: FxHashMap<Rc<Piece>, MovesSetT>,
5359
}
5460

5561
impl MovesMap {
5662
pub fn empty() -> Self {
5763
let piece_to_moves = FxHashMap::default();
5864
let point_to_pieces = FxHashMap::default();
59-
let constraints = MoveConstraints::empty();
60-
Self { piece_to_moves, point_to_pieces, constraints }
65+
let general_constraints = MoveConstraints::empty();
66+
let pin_constraints = FxHashMap::default();
67+
Self { piece_to_moves, point_to_pieces, general_constraints, pin_constraints }
6168
}
6269

6370
fn moves_mut(&mut self, piece: &Rc<Piece>) -> &mut MovesSetT {
@@ -67,21 +74,25 @@ impl MovesMap {
6774
self.piece_to_moves.get_mut(piece).unwrap()
6875
}
6976

70-
fn pieces_mut(&mut self, point: Point) -> &mut PiecesSetT {
77+
fn pieces_mut(&mut self, point: Point, piece: &Rc<Piece>) -> &mut MovesSetT {
7178
if !self.point_to_pieces.contains_key(&point) {
72-
self.point_to_pieces.insert(point, FxHashSet::default());
79+
self.point_to_pieces.insert(point, FxHashMap::default());
7380
}
74-
self.point_to_pieces.get_mut(&point).unwrap()
81+
let pieces_hashmap = self.point_to_pieces.get_mut(&point).unwrap();
82+
if !pieces_hashmap.contains_key(piece) {
83+
pieces_hashmap.insert(Rc::clone(piece), FxHashSet::default());
84+
}
85+
self.point_to_pieces.get_mut(&point).unwrap().get_mut(piece).unwrap()
7586
}
7687

7788
pub fn moves_of(&self, piece: &Rc<Piece>) -> Option<&MovesSetT> {
7889
match &**piece {
7990
Piece::King(_) => { self.piece_to_moves.get(piece) },
8091
_ => {
81-
if self.constraints.is_enabled() {
82-
self.constraints.get(piece)
92+
if self.general_constraints.is_enabled() {
93+
self.general_constraints.get(piece)
8394
} else {
84-
self.piece_to_moves.get(piece)
95+
self.pin_constraints.get(piece).or(self.piece_to_moves.get(piece))
8596
}
8697
},
8798
}
@@ -99,7 +110,7 @@ impl MovesMap {
99110
match piece_move.destination() {
100111
Some(point) => {
101112
self.moves_mut(piece).insert(piece_move)
102-
&& self.pieces_mut(point).insert((Rc::clone(piece), piece_move))
113+
&& self.pieces_mut(point, piece).insert(piece_move)
103114
},
104115
None => self.moves_mut(piece).insert(piece_move),
105116
}
@@ -111,7 +122,7 @@ impl MovesMap {
111122
for piece_move in moves.iter() {
112123
if let Some(point) = piece_move.destination() {
113124
if let Some(pieces) = self.point_to_pieces.get_mut(&point) {
114-
pieces.remove(&(Rc::clone(piece), *piece_move));
125+
pieces.remove(piece);
115126
if pieces.is_empty() {
116127
self.point_to_pieces.remove(&point);
117128
}
@@ -121,18 +132,59 @@ impl MovesMap {
121132
}
122133
}
123134

124-
pub fn clear_constraints(&mut self) {
125-
self.constraints.clear();
135+
pub fn clear_general_constraints(&mut self) {
136+
self.general_constraints.clear();
126137
}
127138

128-
pub fn add_constraints(&mut self, piece_move: PieceMove) {
129-
self.constraints.enable();
139+
pub fn add_general_constraints(&mut self, piece_move: PieceMove) {
140+
self.general_constraints.enable();
130141
if let Some(point) = piece_move.destination() {
131142
if let Some(pieces) = self.point_to_pieces.get(&point) {
132-
for (piece, piece_move) in pieces {
133-
self.constraints.get_mut(piece).insert(*piece_move);
143+
for (piece, piece_moves) in pieces {
144+
if let Some(pin_constraints) = self.pin_constraints.get(piece) {
145+
for piece_move in piece_moves {
146+
if pin_constraints.contains(piece_move) {
147+
self.general_constraints.get_mut(piece).insert(*piece_move);
148+
}
149+
}
150+
} else {
151+
for piece_move in piece_moves {
152+
self.general_constraints.get_mut(piece).insert(*piece_move);
153+
}
154+
}
155+
134156
}
135157
}
136158
}
137159
}
160+
161+
pub fn add_pin_constraints(&mut self, pinned: &Rc<Piece>, points: &Vec<Point>) {
162+
if !self.pin_constraints.contains_key(pinned) {
163+
self.pin_constraints.insert(Rc::clone(pinned), FxHashSet::default());
164+
}
165+
166+
// Build an intersection of moves of the given piece based on provided constraints and
167+
// available moves
168+
for point in points {
169+
if let Some(pieces) = self.point_to_pieces.get(&point) {
170+
if let Some(moves) = pieces.get(pinned) {
171+
for piece_move in moves {
172+
self.pin_constraints.get_mut(pinned).unwrap().insert(*piece_move);
173+
}
174+
}
175+
}
176+
}
177+
}
178+
179+
pub fn clear_pin_constraints_of(&mut self, pinned: &Rc<Piece>) {
180+
self.pin_constraints.remove(pinned);
181+
}
182+
183+
pub fn pinned_pieces(&self) -> Vec<&Rc<Piece>> {
184+
self.pin_constraints.keys().collect::<Vec<_>>()
185+
}
186+
187+
pub fn has_pin_constraints(&self, piece: &Rc<Piece>) -> bool {
188+
self.pin_constraints.contains_key(piece)
189+
}
138190
}

src/piece_move.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
use std::cmp::PartialEq;
22
use crate::castle_points::CastlePoints;
33
use crate::point::Point;
4+
use crate::promote_piece::PromotePiece;
45

56
#[derive(Hash, Debug, Eq, PartialEq, Copy, Clone)]
67
pub enum PieceMove {
78
Point(Point),
89
EnPassant(Point, Point),
910
Castle(CastlePoints),
10-
// This move is relate to pawns. More specifically - when a pawn is moved by two points instead
11-
// of one.
11+
// This move is related to pawns. More specifically - when a pawn is moved by two points instead
12+
// of one. We later use it to calculate EnPassant moves for the opposite color.
1213
LongMove(Point),
14+
Promote(Point, PromotePiece),
1315
// This variant indicates a move not possible to complete.
1416
UnreachablePoint,
1517
}
@@ -19,9 +21,8 @@ impl PieceMove {
1921
match self {
2022
Self::Point(point) |
2123
Self::EnPassant(point, _) |
22-
Self::LongMove(point) => {
23-
Some(*point)
24-
},
24+
Self::LongMove(point) |
25+
Self::Promote(point, _) => { Some(*point) },
2526
Self::Castle(castle_points) => {
2627
Some(*castle_points.king_point())
2728
},

src/pieces/bishop.rs

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ impl Bishop {
4949
for direction in Vector::diagonal_vectors() {
5050
let vector_points = VectorPoints::without_initial(
5151
self.current_position.get(),
52-
*board.get_dimension(),
52+
*board.dimension(),
5353
direction,
5454
);
5555
for point in vector_points {
@@ -69,7 +69,7 @@ impl Bishop {
6969
for direction in Vector::diagonal_vectors() {
7070
let vector_points = VectorPoints::without_initial(
7171
self.current_position.get(),
72-
*board.get_dimension(),
72+
*board.dimension(),
7373
direction,
7474
);
7575
for point in vector_points {
@@ -86,24 +86,12 @@ impl Bishop {
8686
}
8787

8888
pub fn moves(&self, board: &Board) -> Vec<PieceMove> {
89-
let pin = self.debuffs.pin();
90-
let available_directions =
91-
if pin.is_none() {
92-
Vector::diagonal_vectors()
93-
} else {
94-
let pin = pin.unwrap();
95-
Vector::diagonal_vectors()
96-
.iter()
97-
.filter(|&&vec| pin == vec || pin.inverse() == vec)
98-
.map(|&vec| vec)
99-
.collect::<Vec<_>>()
100-
};
10189
let mut moves: Vec<PieceMove> = vec![];
10290

103-
for direction in available_directions {
91+
for direction in Vector::diagonal_vectors() {
10492
let vector_points = VectorPoints::without_initial(
10593
self.current_position.get(),
106-
*board.get_dimension(),
94+
*board.dimension(),
10795
direction,
10896
);
10997
for point in vector_points {

0 commit comments

Comments
 (0)