From 07f82a708649853b52e3f108aa1ac9e2c1d9436e Mon Sep 17 00:00:00 2001 From: Simonas Kareiva Date: Thu, 21 May 2026 21:51:35 +0300 Subject: [PATCH] Add level 4: The Chest (lists) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Top-level `chest:` key with a 3-5 item sequence drawn from a small pool. Per-seed deterministic via ChaCha8Rng XOR'd with 0x..04. Description rendered with tera; flavor uses a šŸ“¦ emoji. Not wired into levels::registry() yet — integration belongs to a follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/levels/l04_list.rs | 71 ++++++++++++++++++++++++++++++++++++++++++ src/levels/mod.rs | 1 + 2 files changed, 72 insertions(+) create mode 100644 src/levels/l04_list.rs diff --git a/src/levels/l04_list.rs b/src/levels/l04_list.rs new file mode 100644 index 0000000..da113eb --- /dev/null +++ b/src/levels/l04_list.rs @@ -0,0 +1,71 @@ +//! Level 4 — lists. A chest of loot lies open before you. +//! +//! Paired design note: `l04.md`. + +use rand::seq::SliceRandom; +use rand::{Rng, SeedableRng}; +use rand_chacha::ChaCha8Rng; +use serde::Serialize; +use serde_yaml::{Mapping, Sequence, Value}; + +use crate::describe::Describer; + +use super::{Generated, Level}; + +pub struct List; + +const ITEMS: &[&str] = &[ + "sword", "torch", "rope", "bread", "dagger", "scroll", "gem", "coin", "potion", "shield", +]; + +#[derive(Serialize)] +struct DescCtx { + items: Vec, +} + +impl Level for List { + fn id(&self) -> u8 { + 4 + } + + fn name(&self) -> &'static str { + "The Chest" + } + + fn generate(&self, seed: u64) -> Generated { + let mut rng = ChaCha8Rng::seed_from_u64(seed ^ 0x0000_0000_0000_0004); + let n = rng.gen_range(3..=5); + let items: Vec<&'static str> = ITEMS.choose_multiple(&mut rng, n).copied().collect(); + + let seq: Sequence = items + .iter() + .map(|i| Value::String((*i).to_string())) + .collect(); + + let mut top = Mapping::new(); + top.insert(Value::String("chest".to_string()), Value::Sequence(seq)); + let target_yaml = + serde_yaml::to_string(&Value::Mapping(top)).expect("serialise mapping"); + + let mut d = Describer::new(); + d.register( + "l04", + "A chest lies open. Inside:\n{% for it in items %}- {{ it }}\n{% endfor %}\nšŸ’” Wrap the items as a YAML list under a `chest:` key.", + ) + .expect("register template"); + let description = d + .render( + "l04", + &DescCtx { + items: items.iter().map(|s| s.to_string()).collect(), + }, + ) + .expect("render template"); + + Generated { + target_yaml, + description, + flavor: "šŸ“¦ A chest of loot lies open before you.".to_string(), + } + } +} diff --git a/src/levels/mod.rs b/src/levels/mod.rs index f3c78cc..baef294 100644 --- a/src/levels/mod.rs +++ b/src/levels/mod.rs @@ -13,6 +13,7 @@ pub mod l01_minimum; pub mod l02_kv; pub mod l03_dict; +pub mod l04_list; use serde::{Deserialize, Serialize}; -- 2.49.1