Make grid axes dumb enums
This commit is contained in:
211
rs/src/board.rs
211
rs/src/board.rs
@@ -19,10 +19,10 @@ impl Color {
|
|||||||
Color::White => Rank::_2,
|
Color::White => Rank::_2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn get_direction(&self) -> i8 {
|
fn other(&self) -> Color {
|
||||||
match self {
|
match self {
|
||||||
Color::Black => -1,
|
Color::Black => Color::White,
|
||||||
Color::White => 1,
|
Color::White => Color::Black,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -40,12 +40,15 @@ impl Position {
|
|||||||
file,
|
file,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn delta(&self, delta_rank_file: (i8, i8)) -> Result<Position, ()> {
|
fn delta(
|
||||||
let (delta_rank, delta_file) = delta_rank_file;
|
&self,
|
||||||
Ok(Position::new(
|
file_direction: &Direction,
|
||||||
self.rank.delta(delta_rank)?,
|
rank_direction: &Direction,
|
||||||
self.file.delta(delta_file)?,
|
) -> Option<Position> {
|
||||||
))
|
Some(Position {
|
||||||
|
rank: self.rank.delta(rank_direction)?,
|
||||||
|
file: self.file.delta(file_direction)?,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,33 +76,25 @@ pub enum File {
|
|||||||
H,
|
H,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum Direction {
|
||||||
|
Incr,
|
||||||
|
Decr,
|
||||||
|
Stay,
|
||||||
|
}
|
||||||
|
|
||||||
pub trait GridAxis
|
pub trait GridAxis
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
Self: Clone,
|
Self: Clone,
|
||||||
{
|
{
|
||||||
const ALL_VALUES: [Self; 8];
|
const ALL_VALUES: [Self; 8];
|
||||||
fn new(index: u8) -> Result<Self, ()> {
|
fn incr(&self) -> Option<Self>;
|
||||||
Ok(Self::ALL_VALUES[Self::validate_index(index)? as usize].clone())
|
fn decr(&self) -> Option<Self>;
|
||||||
}
|
fn delta(&self, direction: &Direction) -> Option<Self> {
|
||||||
fn validate_index(index: u8) -> Result<u8, ()> {
|
match direction {
|
||||||
if index as usize >= Self::ALL_VALUES.len() {
|
Direction::Incr => self.incr(),
|
||||||
Err(())
|
Direction::Decr => self.decr(),
|
||||||
} else {
|
Direction::Stay => Some(self.clone()),
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,8 +110,29 @@ impl GridAxis for Rank {
|
|||||||
Rank::_7,
|
Rank::_7,
|
||||||
Rank::_8,
|
Rank::_8,
|
||||||
];
|
];
|
||||||
fn get_index(&self) -> u8 {
|
fn incr(&self) -> Option<Self> {
|
||||||
*self as u8
|
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::G,
|
||||||
File::H,
|
File::H,
|
||||||
];
|
];
|
||||||
fn get_index(&self) -> u8 {
|
fn incr(&self) -> Option<Self> {
|
||||||
*self as u8
|
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 {
|
struct Ray {
|
||||||
unit: (i8, i8),
|
positions: Vec<Position>,
|
||||||
coefs: Option<Vec<u8>>,
|
|
||||||
source: Position,
|
|
||||||
current: u8,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ray {
|
fn pawn_move_rays(position: &Position, color: &Color) -> Vec<Ray> {
|
||||||
fn new(unit: (i8, i8), coefs: Option<Vec<u8>>, source: Position) -> Self {
|
let direction = match color {
|
||||||
Ray {
|
Color::Black => Direction::Decr,
|
||||||
unit,
|
Color::White => Direction::Incr,
|
||||||
coefs,
|
};
|
||||||
source,
|
if position.rank == color.get_pawn_rank() {
|
||||||
current: 0,
|
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 {
|
fn pawn_capture_rays(position: &Position, color: &Color) -> Vec<Ray> {
|
||||||
type Item = Position;
|
let direction = match color {
|
||||||
fn next(&mut self) -> Option<Position> {
|
Color::Black => Direction::Decr,
|
||||||
let (delta_unit_rank, delta_unit_file) = self.unit;
|
Color::White => Direction::Incr,
|
||||||
let coef = i8::try_from(match &self.coefs {
|
};
|
||||||
None => self.current + 1,
|
let mut capture_rays = vec![];
|
||||||
Some(coefs) => {
|
if let Some(p) = position.delta(&Direction::Incr, &direction) {
|
||||||
let crt_usize = self.current as usize;
|
capture_rays.push(Ray {
|
||||||
if crt_usize >= coefs.len() {
|
positions: vec![p],
|
||||||
return None;
|
});
|
||||||
}
|
}
|
||||||
coefs[crt_usize]
|
if let Some(p) = position.delta(&Direction::Decr, &direction) {
|
||||||
}
|
capture_rays.push(Ray {
|
||||||
})
|
positions: vec![p],
|
||||||
.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
|
|
||||||
}
|
}
|
||||||
|
capture_rays
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Piece {
|
impl Piece {
|
||||||
fn get_move_rays(&self, position: &Position) -> Vec<Ray> {
|
fn get_move_rays(&self, position: &Position) -> Vec<Ray> {
|
||||||
match self.piece_type {
|
match self.piece_type {
|
||||||
PieceType::Pawn => {
|
PieceType::Pawn => pawn_move_rays(position, &self.color),
|
||||||
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())]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn get_capture_rays(&self, position: &Position) -> Vec<Ray> {
|
fn get_capture_rays(&self, position: &Position) -> Vec<Ray> {
|
||||||
match self.piece_type {
|
match self.piece_type {
|
||||||
PieceType::Pawn => {
|
PieceType::Pawn => pawn_capture_rays(position, &self.color),
|
||||||
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()),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -284,14 +309,19 @@ impl Board {
|
|||||||
self.state.iter()
|
self.state.iter()
|
||||||
}
|
}
|
||||||
fn cut_move_ray(&self, ray: Ray) -> impl Iterator<Item = Position> + '_ {
|
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
|
// 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.positions.into_iter().find(|p| match self.get_at(p) {
|
||||||
ray.into_iter().find(|p| match self.get_at(p) {
|
|
||||||
None => false,
|
None => false,
|
||||||
Some(piece) => piece.color != crt_piece.color,
|
Some(piece) => &piece.color == captured_color,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn find_moves(
|
pub fn find_moves(
|
||||||
@@ -312,10 +342,9 @@ impl Board {
|
|||||||
position: &Position,
|
position: &Position,
|
||||||
) -> Result<impl Iterator<Item = Position> + '_, ()> {
|
) -> Result<impl Iterator<Item = Position> + '_, ()> {
|
||||||
if let Some(piece) = self.get_at(position) {
|
if let Some(piece) = self.get_at(position) {
|
||||||
Ok(piece
|
Ok(piece.get_capture_rays(position).into_iter().filter_map(
|
||||||
.get_capture_rays(position)
|
|ray| self.find_capture_along_ray(ray, &piece.color.other()),
|
||||||
.into_iter()
|
))
|
||||||
.filter_map(|ray| self.find_capture_along_ray(ray)))
|
|
||||||
} else {
|
} else {
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
|
|||||||
58
rs/src/ui.rs
58
rs/src/ui.rs
@@ -30,30 +30,70 @@ trait GridAxisIO: std::fmt::Display
|
|||||||
where
|
where
|
||||||
Self: GridAxis,
|
Self: GridAxis,
|
||||||
{
|
{
|
||||||
const ALL_CHARS: [char; 8];
|
fn parse(c: char) -> Result<Self, ()>;
|
||||||
fn parse(c: char) -> Result<Self, ()> {
|
|
||||||
let index = Self::ALL_CHARS.iter().position(|p| p == &c).ok_or(())?;
|
|
||||||
Ok(Self::ALL_VALUES[index].clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GridAxisIO for board::Rank {
|
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 {
|
impl std::fmt::Display for board::Rank {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
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 {
|
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 {
|
impl std::fmt::Display for board::File {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user