extends SceneTree const DeterministicRngScript = preload("res://scripts/core/deterministic_rng.gd") const SimulationDigestScript = preload("res://scripts/core/simulation_digest.gd") var _checks := 0 var _failures := 0 func _initialize() -> void: call_deferred("_run") func _run() -> void: print("S0: deterministic RNG and simulation digest") _test_stream_reproducibility() _test_stream_isolation() _test_snapshot_restore() _test_unbiased_range_contract() _test_digest_normalization() _test_digest_sequence_sensitivity() _test_digest_float_normalization() if _failures == 0: print("PASS: %d checks" % _checks) else: push_error("FAIL: %d of %d checks failed" % [_failures, _checks]) quit(_failures) func _test_stream_reproducibility() -> void: var first = DeterministicRngScript.from_root_seed(20260827, &"guest_ai") var second = DeterministicRngScript.from_root_seed(20260827, &"guest_ai") var first_values: Array[int] = [] var second_values: Array[int] = [] for draw_index in range(64): first_values.append(first.next_u32()) second_values.append(second.next_u32()) _expect(first_values == second_values, "same root seed and stream ID reproduce the sequence") _expect(first.get_counter() == 64, "raw draw counter advances exactly once per sample") func _test_stream_isolation() -> void: var guest = DeterministicRngScript.from_root_seed(20260827, &"guest_ai") var events = DeterministicRngScript.from_root_seed(20260827, &"event_service") var guest_values: Array[int] = [] var event_values: Array[int] = [] for draw_index in range(16): guest_values.append(guest.next_u32()) event_values.append(events.next_u32()) _expect(guest_values != event_values, "different subsystem stream IDs derive isolated sequences") func _test_snapshot_restore() -> void: var original = DeterministicRngScript.from_root_seed(-17, &"authority_service") for draw_index in range(11): original.next_u32() var saved_state: Dictionary = original.snapshot() var expected_tail: Array[int] = [] for draw_index in range(20): expected_tail.append(original.next_u32()) var restored = DeterministicRngScript.from_root_seed(0, &"temporary") _expect(restored.restore(saved_state), "valid RNG snapshot restores") var actual_tail: Array[int] = [] for draw_index in range(20): actual_tail.append(restored.next_u32()) _expect(actual_tail == expected_tail, "restored state continues at the exact next sample") _expect(restored.get_counter() == 31, "snapshot restores and continues the draw counter") func _test_unbiased_range_contract() -> void: var rng = DeterministicRngScript.from_root_seed(99, &"range_test") var all_samples_inside := true for draw_index in range(4096): var sample: int = rng.randi_range(-7, 13) all_samples_inside = all_samples_inside and sample >= -7 and sample <= 13 _expect(all_samples_inside, "inclusive integer range never produces an out-of-range value") var counter_before_constant: int = rng.get_counter() _expect(rng.randi_range(5, 5) == 5, "single-value range returns that value") _expect(rng.get_counter() == counter_before_constant, "single-value range consumes no random sample") func _test_digest_normalization() -> void: var first := {} first[&"resources"] = {&"gold": 4500, &"mana": 100} first[&"minute"] = 721 first[&"positions"] = [Vector2i(3, 4), Vector2i(-2, 8)] var second := {} second[&"positions"] = [Vector2i(3, 4), Vector2i(-2, 8)] second[&"minute"] = 721 var reversed_resources := {} reversed_resources[&"mana"] = 100 reversed_resources[&"gold"] = 4500 second[&"resources"] = reversed_resources var first_digest: String = SimulationDigestScript.compute(first) var second_digest: String = SimulationDigestScript.compute(second) _expect(first_digest.length() == 64, "simulation digest is a 256-bit lowercase hexadecimal value") _expect(first_digest == second_digest, "dictionary insertion order does not affect the digest") func _test_digest_sequence_sensitivity() -> void: var forward: String = SimulationDigestScript.compute([1, 2, 3]) var reversed: String = SimulationDigestScript.compute([3, 2, 1]) _expect( forward == "4e32bb2921e1b879d5b8778789d3bc7e46559d4448e95f9c2fed427d7e5c7b93", "canonical digest format matches its versioned reference vector" ) _expect(forward != reversed, "array order remains significant") _expect( SimulationDigestScript.compute({"value": 1}) != SimulationDigestScript.compute({"value": "1"}), "value types remain significant" ) func _test_digest_float_normalization() -> void: _expect( SimulationDigestScript.compute({"zero": 0.0}) == SimulationDigestScript.compute({"zero": -0.0}), "positive and negative floating-point zero share one canonical representation" ) func _expect(condition: bool, label: String) -> void: _checks += 1 if condition: print(" ✓ %s" % label) return _failures += 1 push_error(" ✗ %s" % label)