From b31d7a677481b4a09168c43d203bfd6d7badf577 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Fri, 25 Oct 2024 17:26:20 +0200 Subject: implement mementos snapshots --- ArtistData.h | 11 +++++++++++ Canvas.cpp | 23 +++++++++++++++++++++++ Canvas.h | 4 ++++ CanvasData.h | 11 +++++++++++ Memento.h | 13 +++++++++++++ Museum.cpp | 49 +++++++++++++++++++++++++++++++++++++++++++------ Museum.h | 14 ++++++++++++-- People.cpp | 20 ++++++++++++++++++++ People.h | 4 ++++ TileData.h | 11 +++++++++++ docs/class-diag.puml | 11 +++++++++-- readme.md | 5 ++--- 12 files changed, 163 insertions(+), 13 deletions(-) create mode 100644 Memento.h diff --git a/ArtistData.h b/ArtistData.h index 1c3c88c..1a75842 100644 --- a/ArtistData.h +++ b/ArtistData.h @@ -1,5 +1,7 @@ #pragma once +#include "Memento.h" + struct ArtistData { float x = 0.0; float y = 0.0; @@ -7,3 +9,12 @@ struct ArtistData { float vy = 0.0; }; +class ArtistDataMemento : public Memento { + friend class People; + +public: + ArtistDataMemento(const ArtistData & data) : data(data) {} +private: + ArtistData data; +}; + diff --git a/Canvas.cpp b/Canvas.cpp index b7cc8a5..86b5bec 100644 --- a/Canvas.cpp +++ b/Canvas.cpp @@ -109,3 +109,26 @@ void Canvas::update_tiles() { } } +Memories Canvas::save() { + Memories data; + data.push_back(make_unique(this->data)); + for (Tile * tile : this->tiles) { + data.push_back(make_unique(tile->data)); + } + return data; +} + +void Canvas::restore(const Memories & memories) { + for (const unique_ptr & memory : memories) { + auto canvas = dynamic_cast(memory.get()); + if (canvas != nullptr) { + this->set_data(canvas->data); + } + + auto tile = dynamic_cast(memory.get()); + if (tile != nullptr) { + this->set_tile(tile->data); + } + } +} + diff --git a/Canvas.h b/Canvas.h index b602fb2..294b335 100644 --- a/Canvas.h +++ b/Canvas.h @@ -27,6 +27,10 @@ public: void update(); void set_data(CanvasData data); +public: + Memories save(); + void restore(const Memories &); + public: TileColorFactory tile_color; TileBehaviorFactory tile_behavior; diff --git a/CanvasData.h b/CanvasData.h index d2b0666..69e8c8c 100644 --- a/CanvasData.h +++ b/CanvasData.h @@ -1,7 +1,18 @@ #pragma once +#include "Memento.h" + struct CanvasData { unsigned rows = 0; unsigned columns = 0; }; +class CanvasDataMemento : public Memento { + friend class Canvas; + +public: + CanvasDataMemento(const CanvasData & data) : data(data) {} +private: + CanvasData data; +}; + diff --git a/Memento.h b/Memento.h new file mode 100644 index 0000000..0bc6c92 --- /dev/null +++ b/Memento.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include + +class Memento { +public: + Memento() = default; + virtual ~Memento() = default; +}; + +typedef std::vector> Memories; + diff --git a/Museum.cpp b/Museum.cpp index 4a12038..d389602 100644 --- a/Museum.cpp +++ b/Museum.cpp @@ -20,22 +20,39 @@ void Museum::update() { this->canvas.update(); this->collision.update(); this->tick++; + + unsigned long long next_snapshot = this->snapshot_ticks; + if (!this->history.empty()) next_snapshot += this->history.top().tick; + if (next_snapshot > this->tick) return; + this->history.push(this->save_snapshot()); + printf("saved snapshot at tick %llu\n", this->tick); } void Museum::skip_forward() { - this->jump += this->snapshot_ticks; + this->jump++; } - void Museum::skip_backward() { - + this->jump--; } void Museum::work() { while (this->working) { - // immediately process forward jumps, even if paused + // immediately process jumps, even if paused if (this->jump > 0) { - for (; this->jump != 0; this->jump--) - this->update(); + // forward jump + for (; this->jump != 0; this->jump--) { + printf("jumping forward %u ticks\n", this->snapshot_ticks); + for (size_t i = 0; i < this->snapshot_ticks; i++) + this->update(); + } + } else if (this->jump < 0) { + // backward jump + for (; this->jump != 0; this->jump++) { + if (this->history.empty()) continue; + printf("restoring snapshot from tick %llu\n", this->history.top().tick); + this->restore_snapshot(this->history.top()); + this->history.pop(); + } } // wait with regular update if paused @@ -48,3 +65,23 @@ void Museum::work() { } } +static void memories_concat(Memories & a, Memories b) { + a.insert(a.end(), make_move_iterator(b.begin()), make_move_iterator(b.end())); +} + +Museum::Snapshot Museum::save_snapshot() { + Snapshot snapshot = { + .tick = this->tick, + .memories = {}, + }; + memories_concat(snapshot.memories, this->canvas.save()); + memories_concat(snapshot.memories, this->people.save()); + return snapshot; +} + +void Museum::restore_snapshot(const Snapshot & snapshot) { + this->tick = snapshot.tick; + this->canvas.restore(snapshot.memories); + this->people.restore(snapshot.memories); +} + diff --git a/Museum.h b/Museum.h index 27e7915..bc5b590 100644 --- a/Museum.h +++ b/Museum.h @@ -2,6 +2,7 @@ #include #include +#include #include "People.h" #include "Canvas.h" @@ -28,7 +29,7 @@ public: void skip_backward(); private: - unsigned long jump = 0; + int jump = 0; private: bool working = true; @@ -37,7 +38,16 @@ private: private: unsigned long long tick = 0; - static constexpr unsigned snapshot_ticks = 50; static constexpr std::chrono::milliseconds tick_interval = 15ms; + +private: + static constexpr unsigned snapshot_ticks = 50; + struct Snapshot { + unsigned long long tick; + Memories memories; + }; + std::stack> history; + Snapshot save_snapshot(); + void restore_snapshot(const Snapshot &); }; diff --git a/People.cpp b/People.cpp index 39d44db..d11434d 100644 --- a/People.cpp +++ b/People.cpp @@ -1,6 +1,8 @@ #include +#include #include "People.h" +#include "ArtistData.h" #include "util.h" using namespace std; @@ -50,3 +52,21 @@ void People::update(bool tick) { } } +Memories People::save() { + Memories data; + for (Artist * artist : this->artists) { + data.push_back(make_unique(artist->data)); + } + return data; +} + +void People::restore(const Memories & memories) { + this->artists.clear(); + this->artist_count = 0; + for (const unique_ptr & memory : memories) { + auto data = dynamic_cast(memory.get()); + if (data == nullptr) continue; + this->add_artist(data->data); + } +} + diff --git a/People.h b/People.h index 940a6d5..83516c9 100644 --- a/People.h +++ b/People.h @@ -22,6 +22,10 @@ public: void update(bool tick = true); +public: + Memories save(); + void restore(const Memories &); + private: std::forward_list artists; size_t artist_count = 0; diff --git a/TileData.h b/TileData.h index 87d9003..314466c 100644 --- a/TileData.h +++ b/TileData.h @@ -2,9 +2,20 @@ #include +#include "Memento.h" + struct TileData { unsigned int x = 0; unsigned int y = 0; std::string type = ""; }; +class TileDataMemento : public Memento { + friend class Canvas; + +public: + TileDataMemento(const TileData & data) : data(data) {} +private: + TileData data; +}; + diff --git a/docs/class-diag.puml b/docs/class-diag.puml index 9ce43eb..f695ed3 100644 --- a/docs/class-diag.puml +++ b/docs/class-diag.puml @@ -111,7 +111,7 @@ rectangle Group_Collisions as "Collisions" <> { -- - museum : Museum & } - class CollisionChecker <> { + abstract class CollisionChecker { + CollisionChecker(Museum &) + check() <> -- @@ -169,7 +169,7 @@ rectangle Group_Pathfinding as "Pathfinding" <> { -- - museum : Museum & } - class Pathfinder <> { + abstract class Pathfinder { + Pathfinder(Museum &) + find_between(const XY &, const XY &) < -- @@ -260,6 +260,9 @@ rectangle Group_Model as "Model" <> { - artist_count : size_t - museum : Museum & } + interface Memento { + } + People -r[hidden] Canvas } together { class Tile { @@ -383,6 +386,10 @@ rectangle Group_Model as "Model" <> { Tile --> "state" TileBehavior Tile .[norank].> TileBehaviorFactory + Memento <|.[norank]. TileData + Memento <|.[norank]. ArtistData + Memento <|.[norank]. CanvasData + ' LAYOUT Artist -r[hidden] Tile } diff --git a/readme.md b/readme.md index 309abed..42c9aaf 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,5 @@ # TODO -DPA: - -- state snapshots (memento) +- update class diagram +- triple check class diagram -- cgit v1.2.3