Skip to content

Das ist ein Output der KI CLAUDE auf eine meiner Anfragen!

Leider, leider hat sich wieder ein BUG eingeschlichen: Einer der AI-Gegner ist scheinbar zwei Mal(!) geschwommen! Überprüfe das!

09:27
 

Ich schaue mir die loseLife-Funktion und den gesamten Eliminierungsfluss genau an.

4 Dateien angesehen
 

Den Bug habe ich gefunden! In showRoundResult — Zeile 1304:

js
if(state.eliminated[p]&&!(losers&&losers.includes(p))) continue;

Diese Bedingung lässt einen bereits eliminierten Spieler durch, wenn er in der losers-Liste steht. Das passiert genau dann, wenn ein Spieler in dieser Runde schwimmt UND gleichzeitig wieder der Verlierer ist — loseLife() setzt ihn auf eliminated=true, aber dann taucht er noch in losers auf. Die Folge: showRoundResult zeigt ihn mit ? und ? (aus dem swim-Check auf Zeile 1315 — aber state.swimming[p] ist jetzt schon false), und beim nächsten Durchlauf durch showRoundResult wird der showRoundResult-Human-eliminated-Check zu früh getriggert. Das eigentliche Problem aber: loseLife wird doppelt aufgerufen für denselben Spieler, wenn announceSchnauz / announceFeuer → showRoundResult → und der endRound-Pfad beide dieselben Losers berechnen.

Nein — nochmal genauer:

2 Dateien angesehen
 

Jetzt habe ich den Bug klar vor mir. In showRoundResult, Zeile 1304:

js
if(state.eliminated[p]&&!(losers&&losers.includes(p))) continue;

Das schließt eliminierte Spieler ein, wenn sie in losers sind — also genau der Spieler, der gerade in dieser Runde durch Schwimmen eliminiert wurde. Er wird angezeigt. Soweit OK. Aber das eigentliche Problem ist subtiler:

Der echte Bug: renderLives() zeigt für einen schwimmenden Spieler alle 3 Dots rot+pulsierend. Wenn dieser Spieler dann nochmal verliert, ruft loseLife() ihn von swimming=true auf eliminated=true. Aber showRoundResult zeigt ihn danach mit state.swimming[p] — das ist jetzt false (korrekt) — aber in der result-row steht swim=state.swimming[p]?' ?':'', also kein ?. Allerdings: state.eliminated[p] ist true, also steht da ?.

Das ist eigentlich kein Anzeigeproblem... Lass mich den wirklichen Doppelschwimm-Pfad finden:

2 Dateien angesehen
 

Jetzt habe ich den Bug exakt identifiziert. Er ist in highlightActiveZone(), Zeile 1714:

js
z.classList.toggle('swimming', state.swimming[p]);

Das CSS .swimming::after erzeugt den roten Pulsierrahmen. Aber: state.swimming[p] bleibt true für die gesamte Runde, in der der Spieler schwimmt — auch wenn er in dieser Runde wieder verliert und loseLife() ihn auf eliminated=true setzt (und swimming auf false).

Warte — nein. loseLife setzt swimming[p]=false und eliminated[p]=true sofort. Das ist korrekt.

Der Bug muss woanders liegen. Der Spieler erscheint visuell als zweimal schwimmend. Das deutet auf ein Render-Timing-Problem hin: render() wird nach loseLife() aufgerufen, aber dann kommt nochmal ein render() aus einem anderen Pfad mit einem veralteten State-Snapshot. Oder: Die swimming-Dots bleiben durch CSS-Animation im DOM hängen, weil innerHTML nur bei eliminated überschrieben wird.

Moment — ich sehe es jetzt: In renderLives():

js
for(let l=0;l<3;l++){
  const isSwimming=state.swimming[p];
  const lost=l>=state.lives[p]&&!isSwimming;
  html+=`<span ...${isSwimming?' swimming':''}...></span>`;
}
if(state.eliminated[p]) html='?';

Wenn lives[p]===0 und swimming[p]===true: alle 3 Dots bekommen .swimming → rot pulsierend. ? Korrekt.

Dann loseLife() nächste Runde: swimming→false, eliminated→true. renderLives zeigt ?. ?

Aber! — was wenn lives[p] bereits 0 ist und swimming[p]===false (noch nicht geschwommen, hat einfach 0 Leben)? Das kann nicht passieren wegen loseLife-Logik...

Lass mich den einzigen echten Doppel-Schwimm-Pfad prüfen: Was wenn ein Spieler beim Feuer alle anderen verlieren ein Leben — und ein Spieler hat bereits 0 Leben und schwimmt? Dann loseLife(p): swimming[p] ist true → swimming=false, eliminated=true. Korrekt.

Aber: in announceFeuer werden die scores vor loseLife berechnet, die losers-Liste enthält den schwimmenden Spieler. Dann showRoundResult(p, scores, losers) — und dort:

js
if(state.eliminated[p]&&!(losers&&losers.includes(p))) continue;

Der eliminierte Spieler wird angezeigt. Sein state.swimming[p] ist jetzt false. Sein state.eliminated[p] ist true. Zeige ?. Korrekt.

Ich muss den Bug aus einer anderen Richtung angehen — wann kann swimming zweimal true sein?

Check startRound for swimming state reset
 

Gefunden! startRound() setzt swimming und lives nicht zurück — nur state-Felder die runden-intern sind. swimming und lives und eliminated bleiben aus dem vorherigen newGame()-Aufruf oder der Initialisierung. Das ist gewollt — sie sollen über Runden bestehen bleiben. Das ist korrekt.

Aber ich sehe jetzt das eigentliche Problem: loseLife kann einen Spieler der bereits schwimmt erneut in den Swimming-Zustand versetzen, wenn die Logik falsch greift. Konkret:

js
function loseLife(p){
  if(state.swimming[p]){          // schwimmt schon → eliminieren
    state.swimming[p]
                                         0 Kommentare
                                                                    
59 Klicks