Make grid axes dumb enums

This commit is contained in:
2025-02-18 21:27:12 +01:00
parent c7f82769e3
commit 98645f01d0
2 changed files with 170 additions and 101 deletions

View File

@@ -19,10 +19,10 @@ impl Color {
Color::White => Rank::_2,
}
}
fn get_direction(&self) -> i8 {
fn other(&self) -> Color {
match self {
Color::Black => -1,
Color::White => 1,
Color::Black => Color::White,
Color::White => Color::Black,
}
}
}
@@ -40,12 +40,15 @@ impl Position {
file,
}
}
fn delta(&self, delta_rank_file: (i8, i8)) -> Result<Position, ()> {
let (delta_rank, delta_file) = delta_rank_file;
Ok(Position::new(
self.rank.delta(delta_rank)?,
self.file.delta(delta_file)?,
))
fn delta(
&self,
file_direction: &Direction,
rank_direction: &Direction,
) -> Option<Position> {
Some(Position {
rank: self.rank.delta(rank_direction)?,
file: self.file.delta(file_direction)?,
})
}
}
@@ -73,33 +76,25 @@ pub enum File {
H,
}
enum Direction {
Incr,
Decr,
Stay,
}
pub trait GridAxis
where
Self: Sized,
Self: Clone,
{
const ALL_VALUES: [Self; 8];
fn new(index: u8) -> Result<Self, ()> {
Ok(Self::ALL_VALUES[Self::validate_index(index)? as usize].clone())
}
fn validate_index(index: u8) -> Result<u8, ()> {
if index as usize >= Self::ALL_VALUES.len() {
Err(())
} else {
Ok(index)
}
}
fn get_index(&self) -> u8;
fn delta(&self, delta: i8) -> Result<Self, ()> {
let highest = Self::ALL_VALUES.len() as i8 - 1;
if delta > highest
|| delta < -highest
|| (delta < 0 && self.get_index() < delta.abs() as u8)
|| (delta > 0 && self.get_index() + delta as u8 > highest as u8)
{
Err(())
} else {
Self::new(((self.get_index() as i8) + delta) as u8)
fn incr(&self) -> Option<Self>;
fn decr(&self) -> Option<Self>;
fn delta(&self, direction: &Direction) -> Option<Self> {
match direction {
Direction::Incr => self.incr(),
Direction::Decr => self.decr(),
Direction::Stay => Some(self.clone()),
}
}
}
@@ -115,8 +110,29 @@ impl GridAxis for Rank {
Rank::_7,
Rank::_8,
];
fn get_index(&self) -> u8 {
*self as u8
fn incr(&self) -> Option<Self> {
match self {
Rank::_1 => Some(Rank::_2),
Rank::_2 => Some(Rank::_3),
Rank::_3 => Some(Rank::_4),
Rank::_4 => Some(Rank::_5),
Rank::_5 => Some(Rank::_6),
Rank::_6 => Some(Rank::_7),
Rank::_7 => Some(Rank::_8),
Rank::_8 => None,
}
}
fn decr(&self) -> Option<Self> {
match self {
Rank::_1 => None,
Rank::_2 => Some(Rank::_1),
Rank::_3 => Some(Rank::_2),
Rank::_4 => Some(Rank::_3),
Rank::_5 => Some(Rank::_4),
Rank::_6 => Some(Rank::_5),
Rank::_7 => Some(Rank::_6),
Rank::_8 => Some(Rank::_7),
}
}
}
@@ -131,8 +147,29 @@ impl GridAxis for File {
File::G,
File::H,
];
fn get_index(&self) -> u8 {
*self as u8
fn incr(&self) -> Option<Self> {
match self {
File::A => Some(File::B),
File::B => Some(File::C),
File::C => Some(File::D),
File::D => Some(File::E),
File::E => Some(File::F),
File::F => Some(File::G),
File::G => Some(File::H),
File::H => None,
}
}
fn decr(&self) -> Option<Self> {
match self {
File::A => None,
File::B => Some(File::A),
File::C => Some(File::B),
File::D => Some(File::C),
File::E => Some(File::D),
File::F => Some(File::E),
File::G => Some(File::F),
File::H => Some(File::G),
}
}
}
@@ -168,71 +205,59 @@ pub struct Piece {
}
struct Ray {
unit: (i8, i8),
coefs: Option<Vec<u8>>,
source: Position,
current: u8,
positions: Vec<Position>,
}
impl Ray {
fn new(unit: (i8, i8), coefs: Option<Vec<u8>>, source: Position) -> Self {
Ray {
unit,
coefs,
source,
current: 0,
fn pawn_move_rays(position: &Position, color: &Color) -> Vec<Ray> {
let direction = match color {
Color::Black => Direction::Decr,
Color::White => Direction::Incr,
};
if position.rank == color.get_pawn_rank() {
let one = position.delta(&Direction::Stay, &direction).unwrap();
let two = one.delta(&Direction::Stay, &direction).unwrap();
vec![Ray {
positions: vec![one, two],
}]
} else {
if let Some(position) = position.delta(&Direction::Stay, &direction) {
vec![Ray {
positions: vec![position],
}]
} else {
vec![]
}
}
}
impl Iterator for Ray {
type Item = Position;
fn next(&mut self) -> Option<Position> {
let (delta_unit_rank, delta_unit_file) = self.unit;
let coef = i8::try_from(match &self.coefs {
None => self.current + 1,
Some(coefs) => {
let crt_usize = self.current as usize;
if crt_usize >= coefs.len() {
return None;
fn pawn_capture_rays(position: &Position, color: &Color) -> Vec<Ray> {
let direction = match color {
Color::Black => Direction::Decr,
Color::White => Direction::Incr,
};
let mut capture_rays = vec![];
if let Some(p) = position.delta(&Direction::Incr, &direction) {
capture_rays.push(Ray {
positions: vec![p],
});
}
coefs[crt_usize]
}
})
.unwrap();
let delta = (
delta_unit_rank.checked_mul(coef).unwrap(),
delta_unit_file.checked_mul(coef).unwrap(),
);
let rval = self.source.delta(delta).ok();
self.current = self.current.wrapping_add(1);
rval
if let Some(p) = position.delta(&Direction::Decr, &direction) {
capture_rays.push(Ray {
positions: vec![p],
});
}
capture_rays
}
impl Piece {
fn get_move_rays(&self, position: &Position) -> Vec<Ray> {
match self.piece_type {
PieceType::Pawn => {
let direction = self.color.get_direction();
let coefs = if position.rank == self.color.get_pawn_rank() {
vec![1, 2]
} else {
vec![1]
};
vec![Ray::new((direction, 0), Some(coefs), position.clone())]
}
PieceType::Pawn => pawn_move_rays(position, &self.color),
}
}
fn get_capture_rays(&self, position: &Position) -> Vec<Ray> {
match self.piece_type {
PieceType::Pawn => {
let direction = self.color.get_direction();
vec![
Ray::new((direction, 1), Some(vec![1]), position.clone()),
Ray::new((direction, -1), Some(vec![1]), position.clone()),
]
}
PieceType::Pawn => pawn_capture_rays(position, &self.color),
}
}
}
@@ -284,14 +309,19 @@ impl Board {
self.state.iter()
}
fn cut_move_ray(&self, ray: Ray) -> impl Iterator<Item = Position> + '_ {
ray.into_iter().take_while(|position| self.get_at(position).is_none())
ray.positions
.into_iter()
.take_while(|position| self.get_at(position).is_none())
}
fn find_capture_along_ray(&self, ray: Ray) -> Option<Position> {
fn find_capture_along_ray(
&self,
ray: Ray,
captured_color: &Color,
) -> Option<Position> {
// I'm not expecting to call this if there's no piece in the position
let crt_piece = self.get_at(&ray.source).unwrap();
ray.into_iter().find(|p| match self.get_at(p) {
ray.positions.into_iter().find(|p| match self.get_at(p) {
None => false,
Some(piece) => piece.color != crt_piece.color,
Some(piece) => &piece.color == captured_color,
})
}
pub fn find_moves(
@@ -312,10 +342,9 @@ impl Board {
position: &Position,
) -> Result<impl Iterator<Item = Position> + '_, ()> {
if let Some(piece) = self.get_at(position) {
Ok(piece
.get_capture_rays(position)
.into_iter()
.filter_map(|ray| self.find_capture_along_ray(ray)))
Ok(piece.get_capture_rays(position).into_iter().filter_map(
|ray| self.find_capture_along_ray(ray, &piece.color.other()),
))
} else {
Err(())
}

View File

@@ -30,30 +30,70 @@ trait GridAxisIO: std::fmt::Display
where
Self: GridAxis,
{
const ALL_CHARS: [char; 8];
fn parse(c: char) -> Result<Self, ()> {
let index = Self::ALL_CHARS.iter().position(|p| p == &c).ok_or(())?;
Ok(Self::ALL_VALUES[index].clone())
}
fn parse(c: char) -> Result<Self, ()>;
}
impl GridAxisIO for board::Rank {
const ALL_CHARS: [char; 8] = ['1', '2', '3', '4', '5', '6', '7', '8'];
fn parse(c: char) -> Result<Self, ()> {
match c {
'1' => Ok(board::Rank::_1),
'2' => Ok(board::Rank::_2),
'3' => Ok(board::Rank::_3),
'4' => Ok(board::Rank::_4),
'5' => Ok(board::Rank::_5),
'6' => Ok(board::Rank::_6),
'7' => Ok(board::Rank::_7),
'8' => Ok(board::Rank::_8),
_ => Err(()),
}
}
}
impl std::fmt::Display for board::Rank {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", Self::ALL_CHARS[self.get_index() as usize])
let c = match self {
board::Rank::_1 => '1',
board::Rank::_2 => '2',
board::Rank::_3 => '3',
board::Rank::_4 => '4',
board::Rank::_5 => '5',
board::Rank::_6 => '6',
board::Rank::_7 => '7',
board::Rank::_8 => '8',
};
write!(f, "{}", c)
}
}
impl GridAxisIO for board::File {
const ALL_CHARS: [char; 8] = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
fn parse(c: char) -> Result<Self, ()> {
match c {
'a' => Ok(board::File::A),
'b' => Ok(board::File::B),
'c' => Ok(board::File::C),
'd' => Ok(board::File::D),
'e' => Ok(board::File::E),
'f' => Ok(board::File::F),
'g' => Ok(board::File::G),
'h' => Ok(board::File::H),
_ => Err(()),
}
}
}
impl std::fmt::Display for board::File {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", Self::ALL_CHARS[self.get_index() as usize])
let c = match self {
board::File::A => 'a',
board::File::B => 'b',
board::File::C => 'c',
board::File::D => 'd',
board::File::E => 'e',
board::File::F => 'f',
board::File::G => 'g',
board::File::H => 'h',
};
write!(f, "{}", c)
}
}