Renderer, Oberfläche, Eingabe, Sound-Modul, Simulationstest und Docker-Setup (Port 18093)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-02 22:16:41 +01:00
1 parent 14e481cffb
commit db417b3af8
13 files changed
+1930 -19

No files matched your search

+80 -4
View File
@@ -380,9 +380,6 @@ impl Game {
pub fn worker_count(&self) -> usize {
self.ents.iter().filter(|e| e.alive && !e.hero && e.kind == EK::Worker).count()
}
pub fn hero_count(&self) -> usize {
self.ents.iter().filter(|e| e.alive && e.hero).count()
}
pub fn summon_cost(&self) -> f32 {
80.0 + 20.0 * (self.worker_count() as f32 - 4.0).max(0.0)
}
@@ -1027,7 +1024,7 @@ impl Game {
let fxx = (e.x + tx as f32 + 0.5) * 0.5;
let fxy = (e.y + ty as f32 + 0.5) * 0.5;
let tl = &mut self.map.t[t];
let mut done = false;
let done;
if tl.kind == Kind::Gold {
let take = tl.gold.min(25);
tl.gold -= take;
@@ -1802,3 +1799,82 @@ pub fn job_name(e: &Ent) -> &'static str {
}
}
}
#[cfg(test)]
mod tests {
use super::*;
// Simuliert ein Spiel mit einfacher "KI-Spielerin" und prüft, dass nichts abstürzt.
#[test]
fn simulate_long_game() {
for seed in [1u32, 7, 12345] {
let mut g = Game::new(seed);
let (cx, cy) = g.map.core;
let (px, py) = g.map.portal;
// Weg zum Portal graben (durch Erde/Gold, um Fels herum)
let start = idx(cx - 1, cy + 1);
let goal = idx(px + 1, py + 1);
let path = g
.map
.search(start, |i| if g.map.t[i].kind == Kind::Rock { None } else { Some(1) }, |i| i == goal, false)
.expect("Portal erreichbar");
for i in path {
if g.map.t[i].diggable() {
g.map.t[i].marked = true;
}
}
g.mark_rect(cx - 6, cy - 6, cx + 9, cy + 9, true);
let (ox, oy) = (cx - 3, cy - 3);
g.build_rect(1, ox, oy, ox + 2, oy + 1); // Quartier 3x2
g.build_rect(2, ox + 5, oy, ox + 7, oy + 1); // Pilzgarten 3x2
let dt = 0.05;
let mut built = false;
let mut portal_logged = false;
for step in 0..(40 * 60 * 20) {
g.update(dt);
g.events.clear();
g.msgs.clear();
if step % 200 == 0 && !built && g.gold > 1900.0 {
g.build_rect(0, ox, oy + 6, ox + 1, oy + 8); // Schatzkammer
g.build_rect(3, ox + 6, oy + 6, ox + 8, oy + 8); // Training
g.build_rect(1, ox, oy + 2, ox + 2, oy + 2); // Quartier erweitern
built = true;
}
// Bot nutzt den Blitz gegen Helden am Kern
if step % 20 == 0 && g.mana >= 50.0 {
let target = g.ents.iter().find(|e| e.alive && e.hero && (e.x - cx as f32).abs() < 4.0 && (e.y - cy as f32).abs() < 4.0).map(|e| (e.x, e.y));
if let Some((x, y)) = target {
g.lightning(x, y);
}
}
if step == 20 * 60 * 20 {
let (gx, gy) = g.map.gate;
g.set_flag(gx + 1, gy + 1);
}
if step % 2400 == 0 {
println!(
"seed {} t={:>5.0}s gold={:>5.0} creatures={} workers={} wave={} core={:.0} gate={:.0} heroes={} army={:.0}",
seed,
g.time,
g.gold,
g.creature_count(),
g.worker_count(),
g.wave,
g.core_hp,
g.gate_hp,
g.ents.iter().filter(|e| e.alive && e.hero).count(),
g.army_value()
);
}
if g.portal_owned() && step % 20 == 0 && !portal_logged {
portal_logged = true;
println!("seed {} Portal erobert nach {:.0}s", seed, g.time);
}
if g.state != 0 {
println!("seed {} Ende nach {:.0}s, state={}", seed, g.time, g.state);
break;
}
}
}
}
}