#[derive(Debug, Clone, PartialEq)]
pub struct Object {
pub coordinates: Vec<(usize, usize)>,
}
#[derive(Debug, PartialEq)]
pub enum LoadObjectError {
NoCoordinatesFound,
DuplicateCoordinate,
BadInput,
}
impl Object {
pub fn from_file(filename: &str) -> Result<Object, LoadObjectError> {
let file_contents = std::fs::read_to_string(filename).expect("Failed to read file");
Self::from_string(file_contents.as_str())
}
pub fn from_string(buffer: &str) -> Result<Object, LoadObjectError> {
let mut coordinates = vec![];
let buffer = buffer.replace("(", "");
let buffer = buffer.replace(")", "");
let buffer = buffer.replace(", ", ",");
let buffer = buffer.replace(" ,", ",");
let coords = buffer.split_whitespace();
for coord in coords {
let mut coord_vals = coord.split(",");
let x: usize = coord_vals
.next()
.expect("Failed to get next value in comma split")
.parse()
.expect("Failed to parse coordinate to usize");
let y: usize = coord_vals
.next()
.expect("Failed to get next value in comma split")
.parse()
.expect("Failed to parse coordinate to usize");
let pair = (x, y);
if coordinates.contains(&pair) {
return Err(LoadObjectError::DuplicateCoordinate);
}
coordinates.push(pair);
}
if coordinates.is_empty() {
return Err(LoadObjectError::NoCoordinatesFound);
}
Ok(Self { coordinates })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn load_from_empty_string_throws_error() {
let expected = Err(LoadObjectError::NoCoordinatesFound);
let actual = Object::from_string("");
assert_eq!(expected, actual);
}
#[test]
fn newlines_no_error() {
let glider_str = "(0,2)\n(1,2)\n(2,2)\n(1,0)\n(2,1)";
let glider = Object::from_string(glider_str);
assert!(glider.is_ok());
let glider = glider.unwrap();
assert_eq!(
glider.coordinates,
vec![(0, 2), (1, 2), (2, 2), (1, 0), (2, 1)]
);
}
#[test]
fn whitespace_around_comma() {
let object_str = "(0, 2) (1,3)";
let object = Object::from_string(object_str);
assert!(object.is_ok());
let object = object.unwrap();
assert_eq!(object.coordinates, vec![(0, 2), (1, 3)]);
}
#[test]
fn repeated_coordinates() {
let object_str = "(0,2) (3,4) (0,2)";
let object = Object::from_string(object_str);
assert_eq!(Err(LoadObjectError::DuplicateCoordinate), object);
}
#[test]
fn load_glider() {
let glider = Object::from_file("objects/glider.life");
assert!(glider.is_ok());
assert_eq!(
glider.unwrap().coordinates,
vec![(0, 2), (1, 2), (2, 2), (1, 0), (2, 1)]
);
}
}