splintersuidman / game-of-life

A Game of Life emulation with support for Life 1.06, Life 1.05, RLE, and plaintext files.
MIT License
2 stars 0 forks source link

Serialisation #15

Open splintersuidman opened 6 years ago

splintersuidman commented 6 years ago

Add support for serialisation: writing the current state to a file. To make this more convenient, perhaps a pause function (key P?) can be added.

Maybe:

syberant commented 6 years ago

In 06213a8 I began implementing this idea. For easier exchange of metadata such as the name, description, and author we might want to introduce a new Metadata struct. We might also consider using generics and having several ways of representing alive cells, this could be extremely useful; for example when outputting in Life 1.05 format.

splintersuidman commented 6 years ago

I'd rather have the serialiser in a different module than parser — probably serialise. I'll create the file structure.

syberant commented 6 years ago

I hope to explain myself somewhat clearer here.

My idea was to first export the board (Vec<Vec<CellState>>) to a Pattern and then export the Pattern into the desired filetype (placing the functions probably in the respective filetype parser file). This way we keep a nice structure where it's clear what does what and the higher-level GameOfLife struct stays clearly separated from the lower-level parsing and serialising.

What do you mean by this?

I meant having the Pattern have several ways of storing the data and introducing traits for usability, i.e.

pub struct Pattern<T>
where
    T: Into<CellList> + Into<CellTable>
{
    cells: T,
    metadata: Metadata,
}

pub struct CellList {
    cells: Vec<(isize, isize)>
}

pub struct CellTable {
    cells: Vec<Vec<CellState>>
}

impl From<CellTable> for CellList {}

impl From<CellList> for CellTable {}

When this is implemented we can easily switch from a Vec<(isize, isize)> to a Vec<Vec<CellState>> or even something else (I don't know what that could sensibly be) depending on which format we are reading or writing.

NOTE: These different representation methods should only be used by parsers && Pattern, NOT by GameOfLife since we should choose one efficient method (like Vec<Vec<CellState>>) and optimise it. Things like Vec<(isize, isize)> are needed for Life 1.06 but absolutely destroy any kind of speed when used by GameOfLife.

NOTE: Displayed suggestion was improved by @splintah's feedback and code.

NOTE: The structure we eventually implemented differs from the one displayed here.

splintersuidman commented 6 years ago

Yeah, I just got what you meant. It might be an idea to implement update as a trait on those different ways of representing the board, which gets called inside GameOfLife::update.

By the way: CellList should probably contain a HashSet<Coordinate> (type Coordinate = (isize, isize);?) — the lookup of neighbours will be much faster.

I'm now (drastically) redesigning the file parsing/serialising system.

syberant commented 6 years ago

It might be an idea to implement update as a trait on those different ways of representing the board, which gets called inside GameOfLife::update.

I didn't want to change GameOfLife.board, only Pattern.cells. I think Vec<Vec<CellState>> is much better once loaded into RAM but for reading and writing files it will be necessary to switch between Vec<Vec<CellState>> and Vec<(isize, isize)>.

the lookup of neighbours will be much faster.

This shouldn't be used for updating anyway since we should convert to the optimal representation method for updating for GameOfLife, this should solely be used for easier reading and writing of different file formats.

splintersuidman commented 6 years ago

I think Vec<Vec> is much better once loaded into RAM

This might not be true. HashSet lookup and insert are O(1). It will probably require more memory, though (perhaps this can be solved by using with_capacity?). We can try it, but it's not necessary, and might be too much a hassle.