Various pre-release cosmetic fixes

This commit is contained in:
2026-05-21 21:21:32 +03:00
parent cb0abb3e3b
commit f817c7b93e
8 changed files with 373 additions and 38 deletions

View File

@@ -8,4 +8,7 @@ Third level is dictionaries. Each direction now leads to a feature with its own
depth: 10
straight:
type: wall
depth:
depth:
The rendered description ends with a hint reminding the player that each
feature's name goes under a `type:` key (the property keeps its own name).

148
src/levels/l03_dict.rs Normal file
View File

@@ -0,0 +1,148 @@
//! Level 3 — dictionaries. Each direction leads to a feature with its
//! own type + one characteristic property.
//!
//! Paired design note: `l03.md`.
use rand::seq::SliceRandom;
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
use serde::Serialize;
use serde_yaml::{Mapping, Value};
use crate::describe::Describer;
use super::{Generated, Level};
pub struct Dict;
const DIRECTIONS: &[&str] = &["left", "right", "straight", "back", "up", "down"];
enum Feature {
Door,
Tunnel,
Pit,
Stairs,
Wall,
Altar,
}
impl Feature {
fn name(&self) -> &'static str {
match self {
Feature::Door => "door",
Feature::Tunnel => "tunnel",
Feature::Pit => "pit",
Feature::Stairs => "stairs",
Feature::Wall => "wall",
Feature::Altar => "altar",
}
}
fn random(rng: &mut ChaCha8Rng) -> Self {
match rng.gen_range(0..6) {
0 => Feature::Door,
1 => Feature::Tunnel,
2 => Feature::Pit,
3 => Feature::Stairs,
4 => Feature::Wall,
_ => Feature::Altar,
}
}
/// One characteristic property: (key, value).
fn property(&self, rng: &mut ChaCha8Rng) -> (&'static str, Value) {
match self {
Feature::Door => ("locked", Value::Bool(rng.gen_bool(0.5))),
Feature::Tunnel => ("depth", Value::from(rng.gen_range(5..=30i64))),
Feature::Pit => ("depth", Value::from(rng.gen_range(5..=30i64))),
Feature::Stairs => {
let going = if rng.gen_bool(0.5) { "up" } else { "down" };
("going", Value::String(going.to_string()))
}
Feature::Wall => ("cracked", Value::Bool(rng.gen_bool(0.5))),
Feature::Altar => ("blessed", Value::Bool(rng.gen_bool(0.5))),
}
}
}
#[derive(Serialize)]
struct DescCtx {
entries: Vec<DescEntry>,
}
#[derive(Serialize)]
struct DescEntry {
direction: String,
feature: String,
prop_name: String,
prop_value: String,
}
impl Level for Dict {
fn id(&self) -> u8 {
3
}
fn name(&self) -> &'static str {
"Dictionaries"
}
fn generate(&self, seed: u64) -> Generated {
// Per-level constant so the same `current_seed` produces different
// content per level.
let mut rng = ChaCha8Rng::seed_from_u64(seed ^ 0x0000_0000_0000_0003);
let n = rng.gen_range(2..=3);
let directions: Vec<&'static str> =
DIRECTIONS.choose_multiple(&mut rng, n).copied().collect();
let mut top = Mapping::new();
let mut entries = Vec::with_capacity(directions.len());
for d in &directions {
let feature = Feature::random(&mut rng);
let (prop_name, prop_value) = feature.property(&mut rng);
let mut inner = Mapping::new();
inner.insert(
Value::String("type".to_string()),
Value::String(feature.name().to_string()),
);
inner.insert(
Value::String(prop_name.to_string()),
prop_value.clone(),
);
top.insert(Value::String((*d).to_string()), Value::Mapping(inner));
let prop_value_str = match &prop_value {
Value::Bool(b) => b.to_string(),
Value::Number(n) => n.to_string(),
Value::String(s) => s.clone(),
_ => String::new(),
};
entries.push(DescEntry {
direction: (*d).to_string(),
feature: feature.name().to_string(),
prop_name: prop_name.to_string(),
prop_value: prop_value_str,
});
}
let target_yaml =
serde_yaml::to_string(&Value::Mapping(top)).expect("serialise mapping");
let mut d = Describer::new();
d.register(
"l03",
"{% for e in entries %}- {{ e.direction }} → {{ e.feature }} ({{ e.prop_name }}: {{ e.prop_value }})\n{% endfor %}\n💡 Each feature is a dictionary — give it a `type:` key plus its property.",
)
.expect("register template");
let description = d
.render("l03", &DescCtx { entries })
.expect("render template");
Generated {
target_yaml,
description,
flavor: "🧭 You stand at a junction. Each path reveals its own detail.".to_string(),
}
}
}

View File

@@ -12,6 +12,7 @@
pub mod l01_minimum;
pub mod l02_kv;
pub mod l03_dict;
use serde::{Deserialize, Serialize};
@@ -81,5 +82,6 @@ pub fn registry() -> Vec<Box<dyn Level>> {
vec![
Box::new(l01_minimum::Minimum),
Box::new(l02_kv::KeyValue),
Box::new(l03_dict::Dict),
]
}