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 { 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` with a game /// initialised with that pattern. Can return errors for failed parsing. pub fn read_game(file: impl Read) -> Result { 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 { match File::open(path) { Ok(file) => Ok(file), Err(_) => Err(ReaderError::FileAccessError), } }