Skip to content

KI erntet nach Erschöpfung ihres Feldes endlos weiter — TryGetOwnFieldCell prüft IsExhausted nicht #85

Description

@cubetribe

Aus dem Betatest vom 10.08.2026 (Build 4053c15, macOS). Quelle: docs/production/hashkrieg/Testberichte/2026-08-10_4053c15_T-01.md

@arn-c0de — das betrifft den Einheitenstrang (Sprint 13B, Paket B4). Die Datei liegt in deiner Schreibhoheit, deshalb ein Issue statt eines PR von uns.

Beobachtung

„1. AI baut zu Beginn drei bis vier Gebäude. 2. AI produziert einige Einheiten. 3. Es folgen einige Angriffswellen. 4. Das lokale AE-Vorkommen erschöpft sich. 5. Danach kommt die AI wirtschaftlich praktisch zum Stillstand."

„Ich konnte nicht beobachten, dass die AI aktiv weitere AE-Vorkommen erschließt bzw. um diese konkurriert."

Ursache

Das ist keine fehlende Strategie, sondern eine fehlende Prüfung — und sie erzeugt einen Livelock.

SkirmishAiSystem.TryGetOwnFieldCell wählt das Aetherium-Feld allein nach Distanz zum eigenen HQ, ohne IsExhausted zu betrachten:

// Assets/_Project/Scripts/AI/SkirmishAiSystem.cs:1268
for (ushort id = 1; id <= EconomySystem.MaxFields; id++)
{
    if (!_economy.TryGetField(id, out AetheriumField field)) continue;
    long dx = field.GridPos.X - hqCellX;
    long dy = field.GridPos.Y - hqCellY;
    long distanceSquared = dx * dx + dy * dy;
    if (distanceSquared < best)        // <-- keine IsExhausted-Prüfung
    {
        best = distanceSquared;
        fieldId = id;
        ...
    }
}

Damit dreht sich ab dem Moment der Erschöpfung folgende Schleife, jeden Entscheidungstick, dauerhaft:

  1. EconomySystem erkennt das leere Feld und räumt die Zuordnung: unit.HarvestFieldId = 0
    (EconomySystem.cs:587 und :620)
  2. Genau dadurch fällt der Harvester in idleHarvesterRaws
    (SkirmishAiSystem.cs:277: if (u.HarvestFieldId == 0 && !u.IsReturningCargo))
  3. Die KI schickt ihn per HarvestPayload(ids, ownFieldId) auf dasselbe leere Feld zurück
    (SkirmishAiSystem.cs:399)
  4. → zurück zu 1.

Die KI ist danach nicht „langsam", sondern wirtschaftlich tot: Einkommen 0, und die Harvester pendeln zwischen Zuweisung und Räumung.

Der Beleg, dass es genau diese eine Prüfung ist

Der Spielerpfad filtert bereits korrekt. RtsDeviceInput überspringt erschöpfte Felder an beiden Stellen, an denen es ein Feld auswählt:

// Assets/_Project/Scripts/Presentation/UI/RtsDeviceInput.cs:664 und :1403
if (field.IsExhausted) continue;

Menschlicher Spieler und KI liefen bei der Einführung der endlichen Felder (#80) also auseinander — der eine Pfad wurde nachgezogen, der andere nicht.

Warum die Karte das sichtbar macht

Die Feldlage steht in MatchBootstrap.cs:164 (Grid 128×128):

Feld Zelle Reserve
1 (7, 7) 9.000 AE
2 (117, 117) 9.000 AE
3 (24, 40) 9.000 AE
4 (100, 84) 9.000 AE
5 (62, 62) 15.000 AE

Die KI sitzt an Feld 1 oder 2 und hört nach dessen 9.000 AE auf — obwohl drei weitere Felder mit zusammen 33.000 AE registriert und über TryGetField erreichbar sind. Sie wählt sie nie, weil die Schleife oben nur nach Distanz sortiert.

Was hier hingehört — und was nicht

Das Minimum, das den Livelock beendet (klein, testbar, in einem PR):
IsExhausted-Felder in TryGetOwnFieldCell überspringen und, wenn kein Feld mehr übrig ist, die Harvester-Nachbestellung aussetzen statt Kommandos ins Leere zu schicken.

Die eigentliche Anforderung aus dem Bericht geht darüber hinaus und ist Stoff für mehrere Pakete — Restbestand überwachen, Erschöpfung prognostizieren, Harvester rechtzeitig umsetzen, Felder sichern und dem Gegner bestreiten, Eskorten für weite Wege. Der Berichttext dazu steht vollständig in der Quelle oben, Abschnitt 8.

Vorschlag: Dieses Issue nur auf den Livelock schneiden. Alles Strategische bekommt eigene Issues, sobald du sagst, wie du B4 schneiden willst.

Randbedingungen aus 13B

  • Determinismus: die Feldschleife läuft über aufsteigende Ids und long-Distanzen — bitte so lassen. Kein float, keine Hashmap-Reihenfolge.
  • Baseline nicht im selben PR (13B, Regel 2). Diese Änderung ändert Verhalten und damit sehr wahrscheinlich die Determinismus-Baseline der kanonischen KI-Partie.
  • Simulation/Economy/ gehört nicht deinem Strang. TryGetField/IsExhausted werden benutzt, nicht geändert — beide reichen für den Fix aus.
  • Fällt dir auf, dass du doch etwas an der Economy brauchst: hier melden, nicht im PR mitändern.

Fertig wenn

  1. Eine Partie läuft nach Erschöpfung des Startfeldes wirtschaftlich weiter — die KI erntet an einem anderen registrierten Feld.
  2. Ein Test unter tools/Nova.SimRunner.Tests/ hält fest, dass ein erschöpftes Feld nicht mehr zugewiesen wird.
  3. Im Spiel gesehen und im PR notiert (GOVERNANCE.md).

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingsimulationSimulationskern, Determinismus, Netzcode

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions