use std::path::{Path, PathBuf}; use std::fs::File; use std::collections::{HashMap, BinaryHeap}; use std::cmp::Reverse; use std::io::Write; use crate::game::{Game, Coord}; /// An error when writing to a file #[derive(Debug)] pub enum WriterError { FileAccessError, WriteError, } /// Write the given game to the file at the given path. pub fn write_game_at_path(path: PathBuf, game: &Game) -> Result<(), WriterError> { let mut file = create_file(path.as_path())?; write_game(&mut file, game) } /// Write the given game to the writer. Currently only accept `std::io::Write` implementors. pub fn write_game(writer: &mut impl Write, game: &Game) -> Result<(), WriterError> { //let path = Path::new(path); let mut string = String::new(); let mut values = CellRows::new(); for i in game.cells() { values.insert(i); } for y in values.smallest_y..values.greatest_y+1 { if let Some(row) = values.rows.get_mut(&y) { for x in values.smallest_x..values.greatest_x+1 { if let Some(ch) = row.peek() { if ch.0 == x { string.push_str("*"); row.pop(); } else { string.push_str("."); } } else { string.push_str("."); } } } string.push_str("\n"); } match write!(writer, "{}", string) { Ok(_) => Ok(()), Err(_) => Err(WriterError::WriteError), } } fn create_file(path: &Path) -> Result { match File::create(path) { Ok(file) => Ok(file), Err(_) => Err(WriterError::FileAccessError), } } #[derive(Default)] struct CellRows { rows: HashMap>>, smallest_x: isize, greatest_x: isize, smallest_y: isize, greatest_y: isize, smallest_x_set: bool, smallest_y_set: bool, greatest_x_set: bool, greatest_y_set: bool, } impl CellRows { pub fn new() -> Self { Self::default() } pub fn insert(&mut self, (x, y): Coord) { if x < self.smallest_x || !self.smallest_x_set { self.smallest_x = x; self.smallest_x_set = true }; if y < self.smallest_y || !self.smallest_y_set { self.smallest_y = y; self.smallest_y_set = true }; if x > self.greatest_x || !self.greatest_x_set { self.greatest_x = x; self.greatest_x_set = true }; if y > self.greatest_y || !self.greatest_y_set { self.greatest_y = y; self.greatest_y_set = true }; self.rows.entry(y).and_modify(|heap| {heap.push(Reverse(x))}).or_insert({let mut heap = BinaryHeap::new(); heap.push(Reverse(x)); heap}); } }