game-of-life/src/writer.rs

87 lines
2.7 KiB
Rust

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<File, WriterError> {
match File::create(path) {
Ok(file) => Ok(file),
Err(_) => Err(WriterError::FileAccessError),
}
}
#[derive(Default)]
struct CellRows {
rows: HashMap<isize, BinaryHeap<Reverse<isize>>>,
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});
}
}