Skip to main content

chess/
magic.rs

1use crate::bitboard::{BitBoard, EMPTY};
2use crate::color::Color;
3use crate::file::File;
4use crate::rank::Rank;
5use crate::square::Square;
6#[cfg(target_feature = "bmi2")]
7use std::arch::x86_64::{_pdep_u64, _pext_u64};
8
9// Include the generated lookup tables
10include!(concat!(env!("OUT_DIR"), "/magic_gen.rs"));
11
12/// Get the rays for a bishop on a particular square.
13#[inline]
14pub fn get_bishop_rays(sq: Square) -> BitBoard {
15	unsafe { *RAYS.get_unchecked(BISHOP).get_unchecked(sq.to_index()) }
16}
17
18/// Get the rays for a rook on a particular square.
19#[inline]
20pub fn get_rook_rays(sq: Square) -> BitBoard {
21	unsafe { *RAYS.get_unchecked(ROOK).get_unchecked(sq.to_index()) }
22}
23
24/// Get the moves for a rook on a particular square, given blockers blocking my movement.
25#[inline]
26pub fn get_rook_moves(sq: Square, blockers: BitBoard) -> BitBoard {
27	unsafe {
28		let magic: Magic = *MAGIC_NUMBERS.get_unchecked(ROOK).get_unchecked(sq.to_int() as usize);
29		*MOVES.get_unchecked((magic.offset as usize) + (magic.magic_number * (blockers & magic.mask)).to_size(magic.rightshift)) & get_rook_rays(sq)
30	}
31}
32
33/// Get the moves for a rook on a particular square, given blockers blocking my movement.
34#[cfg(target_feature = "bmi2")]
35#[inline]
36pub fn get_rook_moves_bmi(sq: Square, blockers: BitBoard) -> BitBoard {
37	unsafe {
38		let bmi2_magic = *ROOK_BMI_MASK.get_unchecked(sq.to_int() as usize);
39		let index = (_pext_u64(blockers.0, bmi2_magic.blockers_mask.0) as usize) + (bmi2_magic.offset as usize);
40		let result = _pdep_u64(*BMI_MOVES.get_unchecked(index as usize) as u64, get_rook_rays(sq).0);
41		return BitBoard(result);
42	}
43}
44
45/// Get the moves for a bishop on a particular square, given blockers blocking my movement.
46#[inline]
47pub fn get_bishop_moves(sq: Square, blockers: BitBoard) -> BitBoard {
48	unsafe {
49		let magic: Magic = *MAGIC_NUMBERS.get_unchecked(BISHOP).get_unchecked(sq.to_int() as usize);
50		*MOVES.get_unchecked((magic.offset as usize) + (magic.magic_number * (blockers & magic.mask)).to_size(magic.rightshift)) & get_bishop_rays(sq)
51	}
52}
53
54/// Get the moves for a bishop on a particular square, given blockers blocking my movement.
55#[inline]
56#[cfg(target_feature = "bmi2")]
57pub fn get_bishop_moves_bmi(sq: Square, blockers: BitBoard) -> BitBoard {
58	unsafe {
59		let bmi2_magic = *BISHOP_BMI_MASK.get_unchecked(sq.to_int() as usize);
60		let index = (_pext_u64(blockers.0, bmi2_magic.blockers_mask.0) as usize) + (bmi2_magic.offset as usize);
61		let result = _pdep_u64(*BMI_MOVES.get_unchecked(index as usize) as u64, get_bishop_rays(sq).0);
62		return BitBoard(result);
63	}
64}
65
66/// Get the king moves for a particular square.
67#[inline]
68pub fn get_king_moves(sq: Square) -> BitBoard {
69	unsafe { *KING_MOVES.get_unchecked(sq.to_index()) }
70}
71
72/// Get the knight moves for a particular square.
73#[inline]
74pub fn get_knight_moves(sq: Square) -> BitBoard {
75	unsafe { *KNIGHT_MOVES.get_unchecked(sq.to_index()) }
76}
77
78/// Get the pawn capture move for a particular square, given the pawn's color and the potential
79/// victims
80#[inline]
81pub fn get_pawn_attacks(sq: Square, color: Color, blockers: BitBoard) -> BitBoard {
82	unsafe { *PAWN_ATTACKS.get_unchecked(color.to_index()).get_unchecked(sq.to_index()) & blockers }
83}
84/// Get the legal destination castle squares for both players
85#[inline]
86pub fn get_castle_moves() -> BitBoard {
87	CASTLE_MOVES
88}
89
90/// Get the quiet pawn moves (non-captures) for a particular square, given the pawn's color and
91/// the potential blocking pieces.
92#[inline]
93pub fn get_pawn_quiets(sq: Square, color: Color, blockers: BitBoard) -> BitBoard {
94	unsafe {
95		if (BitBoard::from_square(sq.uforward(color)) & blockers) != EMPTY {
96			EMPTY
97		} else {
98			*PAWN_MOVES.get_unchecked(color.to_index()).get_unchecked(sq.to_index()) & !blockers
99		}
100	}
101}
102
103/// Get all the pawn moves for a particular square, given the pawn's color and the potential
104/// blocking pieces and victims.
105#[inline]
106pub fn get_pawn_moves(sq: Square, color: Color, blockers: BitBoard) -> BitBoard {
107	get_pawn_attacks(sq, color, blockers) ^ get_pawn_quiets(sq, color, blockers)
108}
109
110/// Get a line (extending to infinity, which in chess is 8 squares), given two squares.
111/// This line does extend past the squares.
112#[inline]
113pub fn line(sq1: Square, sq2: Square) -> BitBoard {
114	unsafe { *LINE.get_unchecked(sq1.to_index()).get_unchecked(sq2.to_index()) }
115}
116
117/// Get a line between these two squares, not including the squares themselves.
118#[inline]
119pub fn between(sq1: Square, sq2: Square) -> BitBoard {
120	unsafe { *BETWEEN.get_unchecked(sq1.to_index()).get_unchecked(sq2.to_index()) }
121}
122
123/// Get a `BitBoard` that represents all the squares on a particular rank.
124#[inline]
125pub fn get_rank(rank: Rank) -> BitBoard {
126	unsafe { *RANKS.get_unchecked(rank.to_index()) }
127}
128
129/// Get a `BitBoard` that represents all the squares on a particular file.
130#[inline]
131pub fn get_file(file: File) -> BitBoard {
132	unsafe { *FILES.get_unchecked(file.to_index()) }
133}
134
135/// Get a `BitBoard` that represents the squares on the 1 or 2 files next to this file.
136#[inline]
137pub fn get_adjacent_files(file: File) -> BitBoard {
138	unsafe { *ADJACENT_FILES.get_unchecked(file.to_index()) }
139}
140
141#[inline]
142pub fn get_pawn_source_double_moves() -> BitBoard {
143	PAWN_SOURCE_DOUBLE_MOVES
144}
145
146#[inline]
147pub fn get_pawn_dest_double_moves() -> BitBoard {
148	PAWN_DEST_DOUBLE_MOVES
149}