int_world::{decode, decode_deltas, decode_planes} render through world/1 and
return a Result; int_world::{load, World} hold the set lowered and loaded once,
with step, step_delta, step_action and render for the live path, which replace
the per-row step functions of a parsed model. int_world::legacy is test-only
(legacy_int). wai-web's WorldModel loads its set once and renders through it;
its methods throw on a refusal.
Callers moved: tests int_world, int_world2, int_world_shared,
int_kernels_vectors; the int_world_decode example; the decode bench's world
row. tests/int_world_memory.rs (its own binary; both fast-kernel steps): a
clip, a step and a frame hold no more than the direct renderer's.
Text: integer-operators' status note, §13.5 (before the first frame: the
plan, T giving the shape back, the informative codes), §15.3 items 2 and 3;
SPEC §8's planned breaks; CHANGELOG.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
54 lines
2.6 KiB
Rust
54 lines
2.6 KiB
Rust
//! `wai.world.model` TWO-AGENT co-control — both agents' actions drive one frame.
|
|
//! The committed transition + synthesis (A=4 input planes: dxA,dyA,dxB,dyB), an
|
|
//! initial latent, and a sequence of combined (agent-A, agent-B) actions regenerate a
|
|
//! frame sequence whose per-frame + clip hashes reproduce on every machine. Two
|
|
//! participants co-render one byte-exact world — true simultaneous multiplayer, not
|
|
//! serialized. Committed tiny vector under `tests/vectors/int_world2/`; never skips.
|
|
#![cfg(feature = "world_int")]
|
|
|
|
use std::path::PathBuf;
|
|
|
|
use wai::int_hyper_synth::IntModel;
|
|
use wai::int_world::{decode_planes, ACTIONS};
|
|
|
|
fn dir() -> PathBuf {
|
|
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/vectors/int_world2")
|
|
}
|
|
|
|
#[test]
|
|
fn two_agent_world_regenerates_byte_for_byte() {
|
|
let t = IntModel::from_bytes(&std::fs::read(dir().join("world2_T.bin")).unwrap()).expect("transition WHM1");
|
|
let gs = IntModel::from_bytes(&std::fs::read(dir().join("world2_gs.bin")).unwrap()).expect("synthesis WHM1");
|
|
let j: serde_json::Value = serde_json::from_slice(&std::fs::read(dir().join("world2.json")).unwrap()).unwrap();
|
|
|
|
let c = j["c"].as_u64().unwrap() as usize;
|
|
let lat = j["lat"].as_u64().unwrap() as usize;
|
|
let one = 1i64 << j["afrac"].as_u64().unwrap();
|
|
let z0: Vec<i64> = j["z0"].as_array().unwrap().iter().map(|v| v.as_i64().unwrap()).collect();
|
|
|
|
// Each step's action PLANE row combines both agents: [dxA, dyA, dxB, dyB] at
|
|
// 2^afrac — the A=4 input the two-agent transition consumes.
|
|
let rows: Vec<Vec<i64>> = j["pairs"]
|
|
.as_array()
|
|
.unwrap()
|
|
.iter()
|
|
.map(|p| {
|
|
let aa = p[0].as_u64().unwrap() as usize;
|
|
let ab = p[1].as_u64().unwrap() as usize;
|
|
let (axa, aya) = ACTIONS[aa];
|
|
let (axb, ayb) = ACTIONS[ab];
|
|
vec![axa * one, aya * one, axb * one, ayb * one]
|
|
})
|
|
.collect();
|
|
|
|
let clip = decode_planes(&t, &gs, &z0, &rows, c, lat).expect("the committed clip renders");
|
|
let want = j["frame_hashes"].as_array().unwrap();
|
|
assert_eq!(clip.frames.len(), rows.len() + 1, "initial + one frame per combined action");
|
|
for i in 0..clip.frames.len() {
|
|
let got = format!("{:016x}", clip.frame_hash(i));
|
|
assert_eq!(got, want[i].as_str().unwrap(), "two-agent frame {i} must reproduce its committed hash");
|
|
}
|
|
let clip_hash = format!("{:016x}", clip.clip_hash());
|
|
assert_eq!(clip_hash, j["clip_hash"].as_str().unwrap(), "clip hash");
|
|
println!("int_world2: {} frames {}px, two agents co-rendered byte-exact, clip {clip_hash}", clip.frames.len(), clip.frame_px);
|
|
}
|