Skip to main content
Verticopolis engineGitHub

verticopolis_engine/
snapshot.rs

1//! The hashed state view: the saved game without its prose, which the
2//! conformance suite hashes at every checkpoint. Hash it with
3//! [`crate::canonical::digest`] to tell whether two games are in the same
4//! state.
5//!
6//! ```
7//! use verticopolis_engine::canonical::digest;
8//! use verticopolis_engine::clock::GameMode;
9//! use verticopolis_engine::sim::Simulation;
10//! use verticopolis_engine::snapshot::state_view;
11//!
12//! let mut a = Simulation::new_game(9, GameMode::Classic);
13//! let mut b = Simulation::new_game(9, GameMode::Classic);
14//! a.tick(120.0);
15//! b.tick(60.0);
16//! b.tick(60.0);
17//! assert_eq!(digest(&state_view(&a)), digest(&state_view(&b)));
18//! ```
19use serde_json::Value;
20
21use crate::sim::Simulation;
22
23/// The saved game ([`Simulation::serialize`]) without the log messages' text
24/// and the pending choice's message, so wording changes never move a hash.
25pub fn state_view(sim: &Simulation) -> Value {
26    let mut v = sim.serialize();
27    if let Some(log) = v.get_mut("log").and_then(Value::as_array_mut) {
28        for e in log {
29            if let Some(o) = e.as_object_mut() {
30                o.remove("text");
31            }
32        }
33    }
34    if let Some(p) = v
35        .get_mut("events")
36        .and_then(|e| e.get_mut("pending"))
37        .and_then(Value::as_object_mut)
38    {
39        p.remove("message");
40    }
41    v
42}