use super::notation::Notation;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Coordinates {
pub x: i8,
pub y: i8,
}
impl Coordinates {
pub fn new(x: i8, y: i8) -> Coordinates {
Coordinates { x, y }
}
pub fn to_tuple(&self) -> (usize, usize) {
((self.x) as usize, (self.y) as usize)
}
pub fn to_file(&self) -> char {
(self.x as u8 + b'a' - 1) as char
}
pub fn to_rank(&self) -> char {
(self.y as u8 + b'1' - 1) as char
}
pub fn from_string(input: &str) -> Result<Coordinates, &'static str> {
let parts: Vec<&str> = input.split(',').collect();
if parts.len() != 2 {
return Err("Input should be in the format 'x,y'");
}
let x = parts[0]
.trim()
.parse::<i8>()
.map_err(|_| "Invalid x coordinate")?;
let y = parts[1]
.trim()
.parse::<i8>()
.map_err(|_| "Invalid y coordinate")?;
if x < 1 || x > 8 || y < 1 || y > 8 {
return Err("Coordinates should be between 1 and 8");
}
Ok(Coordinates::new(x, y))
}
pub fn from_notation_string(s: &str) -> Result<Self, &'static str> {
if s.len() != 2 {
return Err("Invalid notation string");
}
let file = s.chars().nth(0).unwrap().to_ascii_lowercase();
let rank = s.chars().nth(1).unwrap().to_digit(10).unwrap();
if file < 'a' || file > 'h' || rank < 1 || rank > 8 {
return Err("Invalid notation string");
}
let x = file as i8 - 'a' as i8 + 1;
let y = rank as i8;
Ok(Self { x, y })
}
pub fn to_string(&self) -> String {
format!("{}{}", self.x + 1, self.y + 1)
}
pub fn from_notation(notation: Notation) -> Result<Coordinates, &'static str> {
let x = match notation.file {
'a'..='h' => (notation.file as u8 - 'a' as u8 + 1) as i8,
_ => return Err("Invalid file"),
};
let y = match notation.rank {
'1'..='8' => (notation.rank as u8 - '1' as u8 + 1) as i8,
_ => return Err("Invalid rank"),
};
Ok(Coordinates::new(x, y))
}
pub fn to_notation(&self) -> Result<Notation, &'static str> {
let file = match self.x {
1 => 'a',
2 => 'b',
3 => 'c',
4 => 'd',
5 => 'e',
6 => 'f',
7 => 'g',
8 => 'h',
_ => return Err("Invalid x coordinate"),
};
let rank = match self.y {
1 => '1',
2 => '2',
3 => '3',
4 => '4',
5 => '5',
6 => '6',
7 => '7',
8 => '8',
_ => return Err("Invalid y coordinate"),
};
Ok(Notation { file, rank })
}
pub fn to_index(&self) -> Result<usize, &'static str> {
if self.y < 1 || self.y > 8 {
return Err("y coordinate is out of bounds");
}
let x = (self.x - 1) as usize;
let y = (self.y - 1) as usize;
Ok(y * 8 + x)
}
pub fn from_index(index: usize) -> Coordinates {
Coordinates::new((index % 8 + 1) as i8, (index / 8 + 1) as i8)
}
pub fn is_valid(&self) -> bool {
self.x >= 1 && self.x <= 8 && self.y >= 1 && self.y <= 8
}
pub fn is_diagonal(&self, other: Coordinates) -> bool {
let dx = (self.x - other.x).abs();
let dy = (self.y - other.y).abs();
dx == dy
}
pub fn is_straight(&self, other: Coordinates) -> bool {
self.x == other.x || self.y == other.y
}
pub fn is_adjacent(&self, other: Coordinates) -> bool {
let dx = (self.x - other.x).abs();
let dy = (self.y - other.y).abs();
dx <= 1 && dy <= 1
}
}