game-of-life/src/reader.rs

63 lines
2.0 KiB
Rust

use std::{path::Path, fs::File, io::{self, BufRead, Read}};
use crate::game::Game;
/// An error when reading the file
#[derive(Debug)]
pub enum ReaderError {
FileAccessError,
ParseError,
}
/// Read the file at a given path. If all goes well, will return `Ok(game)`, with a game
/// initialised with that pattern. Can return errors for either file access or failed parsing.
pub fn read_game_at_path(path: &str) -> Result<Game, ReaderError> {
let path = Path::new(path);
let file = open_file(path)?;
read_game(file)
}
/// Read from any `impl Read`. If all goes well, will return `Ok<Game>` with a game
/// initialised with that pattern. Can return errors for failed parsing.
pub fn read_game(file: impl Read) -> Result<Game, ReaderError> {
let lines = io::BufReader::new(file).lines();
let mut game = Game::new();
let mut x_index = 0;
for line in lines {
if let Ok(ip) = line {
// Comment/metadata
if ip.starts_with("!") || ip.starts_with("#") {continue}
x_index += 1;
for (cell, y_index) in ip.chars().zip(0..) {
match cell {
// Live cell
'*' | 'O' => {game.flip_state((y_index, x_index));},
// Dead cell
'.' | ' ' => continue,
// Invalid character
_ => {return Err(ReaderError::ParseError);},
}
/*if cell == '*' || cell == 'O' {
// Live cell
game.flip_state((y_index, x_index));
} else if cell == '.' || cell == ' ' {
// Dead cell
continue
} else {
// Invalid character
return Err(ReaderError::ParseError);
}*/
}
}
}
Ok(game)
}
fn open_file(path: &Path) -> Result<File, ReaderError> {
match File::open(path) {
Ok(file) => Ok(file),
Err(_) => Err(ReaderError::FileAccessError),
}
}