feat(ai): add strength-based wave gate - #72
Conversation
Die Welle marschierte auf einer ANZAHL gesammelter Einheiten, und eine Anzahl weiss nicht, was eine Einheit wert ist. Zwölf Allianz-Schützen wiegen 1200 Kampfpunkte, zwölf Legions-Rekruten 528 — dieselbe Regel, dasselbe Wort "volle Welle", und die Legion greift mit 44 % der Stärke an, die sie der Allianz gibt. Die Referenzpartie hat das in der Verlustspalte stehen: 51 gegen 23. CombatStrength bewertet eine Einheit als Schaden * Leben / Feuerintervall: ganzzahlig, eine Division, eine festgeschriebene Abschneidung, und unbewaffnete Rollen fallen ohne Sonderfall auf 0. Das neue Profilfeld waveStrengthPoints (ausgeliefert 1200, 0 schaltet die Regel bitgenau ab) summiert diese Punkte über die Einheiten im Sammelring, statt sie zu zählen. WaveStrengthGate hält die Schwellwert-Arithmetik als reine Funktion, und zwar als eigener Typ, damit sie an den Zuständen prüfbar ist, die eine Partie nicht auf Bestellung erzeugt: mehr Einheiten am Leben als die Kappe erlaubt, eine gerade zerstörte Kaserne, eine Schwelle die statt der Decke bindet. Der Grund ist eine Mutationsprobe — mit der Arithmetik im System vergraben blieb die ganze Suite grün, sowohl als der Negativ-Clamp gelöscht als auch als waveStrengthPoints ganz ignoriert wurde. Die r5-Regel wandert in Punkten mit: der Schwellwert bleibt gegen das gekappt, was die Produktion noch liefern kann, damit ein Überlebender ausserhalb des Rings die nächste Welle nicht blockiert. Ein freier Kopf zählt nur, solange eine Kaserne hineinbauen kann — sonst wartet die Welle die Partie aus auf Verstärkung, die niemand bauen kann, und das ist die r5-Blockade eine Ebene höher. Kredite gehen bewusst nicht ein: pleite ist vorübergehend, und ein Tor, das mit der Kasse flackert, ordnet die Armee jede Kadenz neu (Journal V002). AUSGELIEFERT IST DIE REGEL SCHLAFEND, UND EIN TEST NAGELT DAS FEST. Die Punktklausel kann nur entscheiden, solange ein Kopf der Armeeobergrenze frei ist — elf Schützen, 1100 Punkte, gegen eine Schwelle von 1200 — das Tor entscheidet also exakt wie die Kopfzahl, und die kanonische Partie ist byteidentisch (Endzustands-Pin unverändert bei Tick 2548 / 0x14472B2B943ED2BB; der KI-gegen-KI-Lauf des Labors ebenso bei 5773 / 0x2B34B4E194257940, nur der Bezeichner bewegt sich). Die Reserve beträgt neun Punkte pro Schütze, deshalb rechnet der Test sie aus CombatStrength statt aus einer abgeschriebenen Zahl: Waffenwerte sind der Auftrag genau dieses Strangs, und ein Schadenspunkt mehr würde das Tor wecken. Was die Revision bringt, ist die Entkopplung — der Schwellwert der Welle ist keine an die Produktionsobergrenze gekoppelte Kopfzahl mehr, und das ist die Voraussetzung dafür, diese Obergrenze überhaupt zu bewegen. Sie zu bewegen ist nicht Sache dieses Strangs: MatchRunner überschreibt vier Profilwerte mit eigenen Literalen, targetArmySize darunter, und diese Datei gehört dem Netzstrang. Ein neuer Test liest MatchRunners Quelltext und wird rot, wenn die vier von AiProfiles abweichen — das hat vorher nichts geprüft, und beide bestehenden Wächter sehen von je einer Seite an der Lücke vorbei. Einseitig im Labor gemessen: die Obergrenze ALLEIN anzuheben macht die Legion schlechter (eigene Verluste 51 -> 64, Austausch 45 -> 34); mit dem Tor und Obergrenze 30 entscheidet derselbe Sitz SCHNELLER als heute (5005 gegen 5773 Ticks) bei 23 eigenen Verlusten und Austausch 139. Die Rückfrage und die vollständige Kurve stehen im PR-Text — samt der Warnung, dass eine Abbruchregel davor gehört. Im laufenden Spiel ungesehen. Eine Labormessung ist Diagnose, kein Nachweis. Tests 649/649, Determinismus Exit 0, keine Baseline angefasst.
…bung ziehen Das Repo schreibt ueberwiegend mit ß — in docs/ 1240 zu 30, im CHANGELOG 54 zu 10 —, der eigene Eintrag trug an zwei Stellen die Schweizer Schreibung. Betroffen sind nur diese beiden Woerter im eigenen Absatz; die aelteren Eintraege des Maintainers, die stellenweise ebenfalls "ss" schreiben, bleiben unangetastet. Keine inhaltliche Aenderung, keine Codeaenderung. Tests 649/649.
|
Von Maintainer-Seite geprüft — Determinismus, Schreibhoheit und Handwerk. Der Code ist in Ordnung, und die Trennung ist sauber eingehalten. Drei Punkte, die vor dem Merge geklärt sein sollten, plus eine Frage. Was geprüft wurde und passtDeterminismus. Der ganze Diff auf Schreibhoheit. Alle 14 Dateien liegen im Terrain des Einheitenstrangs. Tests. 429 Zeilen neu, dazu die Ergänzungen an den bestehenden Dateien. Paket B5 ist erfüllt, und die Tests halten das beabsichtigte Verhalten fest statt nur den Ist-Zustand. Drei Punkte zur Klärung1. Beschreibung und Changelog widersprechen sich.
In diesem Projekt ist die gespielte Beobachtung Nachweispflicht, deshalb muss die Zeile eindeutig sein. Nach der Beschreibung zu urteilen ist „gespielt, zeigt erwartungsgemäß keinen Unterschied" das Richtige — dann müsste der Changelog nachziehen. 2. Die Laborzahlen passen nicht zusammen. Die Beschreibung nennt Stärketor plus Obergrenze 3. Ein Test hier bricht, wenn der Netzstrang seine eigene Datei ändert. Eine FrageBei leerem Sammelring und voll ausgeschöpfter Armeeobergrenze ( Die Begründung („mit null gesammelten Einheiten gibt es niemanden, den das Flag schicken könnte") klingt schlüssig, aber wir konnten sie von der Aufrufseite aus nicht selbst bestätigen. Kannst du kurz sagen, was hinter Zwei Lücken auf unserer Seite, die durch diesen PR sichtbar wurdenBeide sind nicht dir anzulasten, im Gegenteil — die erste hast du selbst im Quelltext vermerkt, statt sie zu übergehen. Danke dafür.
Zum roten Check
|
…becodingGermany#72) Zwei Fehler, beide vom Maintainer in der Pruefung gefunden. 1. Die Zeile "Im laufenden Spiel ungesehen" widersprach der PR-Beschreibung, die eine gespielte Partie meldet. "Ungesehen" ist in diesem Repo der Fachbegriff fuer "kein Nachweis erbracht", nicht fuer "nichts war zu sehen" — beides nebeneinander laesst offen, welche Aussage gilt. Es gilt die gespielte Partie: kein sichtbarer Unterschied, wie vorhergesagt, also Bestaetigung der Neutralitaet und ausdruecklich kein Beleg fuer eine Verbesserung. 2. Die Laborzahlen stammten aus einem ueberholten Lauf: Obergrenze 36 mit Austausch 45 -> 90, waehrend die PR-Beschreibung Obergrenze 30 mit Austausch 139 nennt. Der Eintrag traegt jetzt dieselbe Stellung wie die Beschreibung, samt der Warnung, dass eine Abbruchregel vor die Obergrenze gehoert (Aussetzzeit 3.502 -> 12.326 Einheit-Ticks je 1.000). Keine Codeaenderung. Tests 649/649.
Punkt 1 und 2Punkt 1 und 2 waren echte Fehler von mir, behoben in 1. Gespielte PartieEs gilt die Beschreibung. Der Changelog trug „ungesehen" aus einer Fassung, in der noch niemand gespielt hatte. Gespielt wurde, kein Unterschied zu sehen. Das bestätigt die Byte-Identität und belegt ausdrücklich keine Verbesserung. Der Changelog sagt das jetzt genauso. 2. LaborzahlenRichtig vermutet: zwei Läufe. Der Changelog trug noch Obergrenze 36 ( Ich hatte die Empfehlung auf 30 umgestellt. 30 folgt aus dem Schwellwert statt aus dem Kurvenmaximum. Ich hatte dabei nur die Beschreibung nachgezogen. Jetzt steht überall 30. 3. Kopplung an
|
| Messung | Ohne Eingriff | Flag umgedreht |
|---|---|---|
| Testsuite | 649/649 |
649/649 |
| Kanonische Laborpartie | 5773 / 0x2B34B4E194257940 |
identisch |
| Legionssitz, Obergrenze 30 | 5005 / 0x88C9F0FDCF98EC11 |
identisch |
Der zweite Lauf ist der, in dem der Zustand am häufigsten auftritt.
Probe nicht eingecheckt.
Das Flag ist dort also nicht „fälschlich true", sondern wirkungslos.
Der Unterschied zu r5 ist real, aber nicht beobachtbar.
Wenn ihr eine Zusicherung statt eines Nachweises wollt, baue ich den Test dazu.
Zu #74
Gern von mir, falls ihr wollt:
"AI""AI.Data"
in ScannedRoots beider Kopien.
Ich habe es nicht selbst gemacht, weil die EditMode-Kopie unter Assets/Tests/ keinem Strang zugeordnet ist. Das wäre dieselbe stille Grenzüberschreitung wie bei Punkt 3.
# Conflicts: # tools/Nova.SimRunner.Tests/SkirmishAiTests.cs
Was & Warum
Die Wellenlogik bewertet eine „volle Welle“ bisher ausschließlich nach der Anzahl gesammelter Einheiten. Das bildet die tatsächliche Kampfstärke der Fraktionen nicht ab: Zwölf Allianz-Schützen entsprechen 1200 Kampfpunkten, zwölf Legions-Rekruten nur 528. Damit greift die Legion unter derselben Kopfzahlregel mit rund 44 % der Stärke an, die dieselbe Regel der Allianz gibt.
Dieser PR führt deshalb
CombatStrengthals deterministische Ganzzahlbewertung einer Einheit ein:Schaden * Leben / FeuerintervallZusätzlich erhält das KI-Profil
waveStrengthPoints. Damit kann die Wellenfreigabe statt ausschließlich der Kopfzahl auch die aufsummierte Kampfstärke der Einheiten im Sammelring prüfen.Die neue Regel ist im ausgelieferten Profil absichtlich noch schlafend. Bei der aktuellen Armeeobergrenze entscheidet das Tor weiterhin exakt wie die bisherige Kopfzahlregel. Die kanonische Partie bleibt deshalb byteidentisch.
Technische Details, Tests und Laborbefunde
Die Berechnung von
CombatStrengthverwendet genau eine Ganzzahldivision mit festgelegter Abschneidung. Unbewaffnete Rollen ergeben ohne Sonderfall automatisch0.Der ausgelieferte Wert für
waveStrengthPointsbeträgt1200;0deaktiviert die neue Regel bitgenau.Die Schwellwertarithmetik liegt in
WaveStrengthGateals reine Funktion. Dadurch lassen sich auch Zustände direkt testen, die eine vollständige Partie nicht zuverlässig auf Bestellung erzeugt, darunter:Die Trennung folgt aus einer Mutationsprobe: Solange die Arithmetik im System selbst vergraben war, blieb die Testsuite sowohl beim Entfernen des Negativ-Clamps als auch beim vollständigen Ignorieren von
waveStrengthPointsgrün.Die bestehende r5-Regel wird auf die Punktelogik übertragen. Der Schwellwert bleibt auf das begrenzt, was die Produktion unter der aktuellen Armeeobergrenze noch liefern kann. Ein Überlebender außerhalb des Sammelrings darf die nächste Welle damit nicht auf Verstärkung warten lassen, die aufgrund fehlender Produktionskapazität gar nicht mehr gebaut werden kann.
Kredite gehen bewusst nicht in diese Entscheidung ein. Zahlungsunfähigkeit ist ein vorübergehender Zustand; ein von der aktuellen Kasse abhängiges Tor würde die Armee bei jeder Prüfkadenz erneut einordnen. Das entspricht der bereits dokumentierten Problematik aus Journal V002.
Ein Test hält den schlafenden Zustand der neuen Regel ausdrücklich fest: Bei elf Schützen liegen 1100 Punkte gegen eine Schwelle von 1200 vor, gleichzeitig ist aber noch ein Platz unter der Armeeobergrenze frei. Dadurch entscheidet das Tor weiterhin exakt wie die bisherige Kopfzahlregel.
Die kanonische Partie bleibt byteidentisch:
2548, Hash0x14472B2B943ED2BB5773, Hash0x2B34B4E194257940Nur der Bezeichner bewegt sich.
Die Reserve zur Aktivierung beträgt neun Punkte pro Schütze. Der entsprechende Test berechnet diesen Wert aus
CombatStrength, statt eine Konstante abzuschreiben. Damit reagiert der Test auch auf spätere Änderungen der Waffenwerte; bereits ein zusätzlicher Schadenspunkt würde die neue Klausel aktivieren.Ziel dieses PRs ist nicht, die Armeeobergrenze selbst zu verändern, sondern Wellenstärke und Kopfzahl voneinander zu entkoppeln. Erst dadurch kann
targetArmySizespäter unabhängig verändert werden.MatchRunnerüberschreibt derzeit vier Profilwerte mit eigenen Literalen, daruntertargetArmySize, und gehört zum Netzstrang. Ein neuer Test prüft deshalb den Quelltext vonMatchRunnergegenAiProfilesund schlägt fehl, sobald diese vier Werte auseinanderlaufen. Diese Lücke wurde von den bisherigen Wächtern nicht erfasst.Laborbefund zur späteren Weiterarbeit
51 → 64, Austausch45 → 3430: Entscheidung bei Tick5005statt5773,23eigene Verluste, Austausch139Das ist ausdrücklich keine Änderung dieses PRs. Vor einer solchen Aktivierung gehört außerdem eine Abbruchregel vor die neue Konfiguration: Im Labor steigt die Aussetzzeit am Sammelpunkt von
3.502auf12.326Einheit-Ticks je1.000, einzelne Einheiten warten dabei bis zu3.214Ticks.Gespielte Partie
Im laufenden Spiel gespielt. Eine Partie mit diesem Stand zeigt keinen Unterschied zum bisherigen Verhalten – und genau das ist das erwartete Ergebnis, weil das Tor bei der ausgelieferten Armeeobergrenze nachweislich identisch zur Kopfzahl entscheidet.
Die gespielte Partie bestätigt damit die Neutralität; sie belegt keine Verbesserung. Sichtbar wird der Effekt erst mit den darauf aufbauenden Änderungen.
Checkliste
dotnet test tools/Nova.SimRunner.Testslokal grün —649/649[Unreleased]in CHANGELOG.mdEchte Entscheidung getroffen? → D-ID im DecisionLog, sonst streichen— gestrichen: keine Inhaberentscheidung getroffen. Offen bleiben die Armeeobergrenze, die als Literal inMatchRunnerliegt, und die Frage, ob ein KI-Profil überhaupt in den Match-Fingerprint eingehen soll. Letzteres nenntAiBehaviorIdselbst eine Inhaberentscheidung mit Auswirkungen auf Simulation und Replays; dieser PR beantwortet sie ausdrücklich nicht.Determinismusprüfung: Exit
0. Keine Baseline geändert.Externe Beiträge