Compare commits

..
2 Commits
Author SHA1 Message Date
Richard ZinkandClaude Opus 5.5 0b2d327791 Bump version to v202611-00060
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 09:54:19 +01:00
Richard ZinkandClaude Opus 5.5 cccb6b64c3 AI masters build only rooms and towers they have researched
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 09:54:19 +01:00
3 changed files with 42 additions and 2 deletions

No files matched your search

+1 -1
View File
@@ -1 +1 @@
v202611-00059
v202611-00060
+10 -1
View File
@@ -221,6 +221,10 @@ impl Game {
// the next room of the build order, where there is free own floor for it
fn ai_rooms(&mut self, cx: i32, cy: i32) {
for &(room, w, h, n) in BUILD.iter() {
// only what this master has researched (the same rules as the player)
if !self.ai_knows(crate::ui::Tool::Room(room)) {
continue;
}
let tiles = self.counts[room];
if tiles >= (w * h) as usize * n {
continue;
@@ -236,6 +240,11 @@ impl Game {
}
}
// has this master researched the tool (rooms, towers)?
fn ai_knows(&self, tool: crate::ui::Tool) -> bool {
crate::ui::TOOLS.iter().position(|&t| t == tool).map_or(false, |i| self.tool_allowed(i))
}
// a rectangle of own plain floor, as near the heart as possible (not right next to it)
fn ai_free_rect(&self, cx: i32, cy: i32, w: i32, h: i32) -> Option<(i32, i32)> {
let me = self.me;
@@ -260,7 +269,7 @@ impl Game {
fn ai_towers(&mut self, d: usize, cx: i32, cy: i32) {
let me = self.me;
let mine = self.towers.iter().filter(|t| !t.hero && self.map.t[t.tile].owner == me).count();
if mine >= MAX_TOWERS[d] || self.gold < 1800.0 || self.counts[0] == 0 {
if mine >= MAX_TOWERS[d] || self.gold < 1800.0 || self.counts[0] == 0 || !self.ai_knows(crate::ui::Tool::Tower(TowerKind::Arrow)) {
return;
}
let spot = (0..self.map.t.len()).filter(|&i| {
+31
View File
@@ -600,6 +600,37 @@ mod tests {
g
}
#[test]
fn the_ai_partner_builds_only_what_is_researched() {
// the first missions of both co-op campaigns: no library, no forge yet
let doc = crate::editor::coop_campaign::coop_campaign();
let games = [
crate::campaign::start_editor_coop_mission(&doc.missions[0], 0, 77),
crate::campaign::start_coop_mission(crate::campaign::coop_mission_indexes()[0], None),
];
let lib = crate::ui::TOOLS.iter().position(|&t| t == crate::ui::Tool::Room(4)).unwrap();
let forge = crate::ui::TOOLS.iter().position(|&t| t == crate::ui::Tool::Room(8)).unwrap();
for mut g in games {
g.coop = true;
assert!(g.start_match(&[0, 2], 0));
g.sync_ai_sides(&[2], 1);
g.end_match();
let mine_knows = (g.tool_allowed(lib), g.tool_allowed(forge));
for _ in 0..(10 * 60 * 20) {
g.update(0.05);
}
let owner = Owner::of_side(2);
let has = |k: Kind| g.map.t.iter().any(|t| t.kind == k && t.owner == owner);
if !mine_knows.0 {
assert!(!has(Kind::Library), "the partner has no library either");
}
if !mine_knows.1 {
assert!(!has(Kind::Forge), "the partner has no forge either");
}
assert!(has(Kind::Lair) || has(Kind::Treasury), "but builds what it knows");
}
}
#[test]
fn imps_take_ground_from_enemies_but_never_from_allies() {
let mut g = offline_league_game();