Add UNO sudden death and multiplayer bot turn announcements

2-player UNO (especially No Mercy) regularly stalls past 100 turns.
Sudden death announces at turn 80 with a 20-turn countdown, then
scores hands by card point values — lowest total wins. Applies to
solo (vs bot) and multiplayer when 2 active players remain.

Also adds "It's X's turn" labels to bot plays in multiplayer,
matching the format human plays already had, and adds sudden death
checks to all turn advancement paths.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
prosolis
2026-03-29 09:27:00 -07:00
parent 50cacd42c5
commit b188d7036b
4 changed files with 452 additions and 1 deletions

View File

@@ -288,3 +288,58 @@ func TestUnoColor_Emoji(t *testing.T) {
t.Errorf("blue emoji: got %q", unoBlue.Emoji())
}
}
// ---------------------------------------------------------------------------
// Card point values (sudden death scoring)
// ---------------------------------------------------------------------------
func TestCardPointValue(t *testing.T) {
tests := []struct {
name string
card unoCard
want int
}{
{"zero", unoCard{unoRed, unoZero}, 0},
{"five", unoCard{unoBlue, unoFive}, 5},
{"nine", unoCard{unoGreen, unoNine}, 9},
{"skip", unoCard{unoRed, unoSkip}, 20},
{"reverse", unoCard{unoBlue, unoReverse}, 20},
{"draw two", unoCard{unoYellow, unoDrawTwo}, 20},
{"skip everyone", unoCard{unoRed, unoSkipEveryone}, 30},
{"draw four colored", unoCard{unoGreen, unoDrawFour}, 30},
{"discard all", unoCard{unoBlue, unoDiscardAll}, 30},
{"wild", unoCard{unoWild, unoWildCard}, 50},
{"wild draw four", unoCard{unoWild, unoWildDrawFour}, 50},
{"wild reverse draw 4", unoCard{unoWild, unoWildReverseDraw4}, 60},
{"wild draw six", unoCard{unoWild, unoWildDrawSix}, 60},
{"wild color roulette", unoCard{unoWild, unoWildColorRoulette}, 60},
{"wild draw ten", unoCard{unoWild, unoWildDrawTen}, 75},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := cardPointValue(tt.card); got != tt.want {
t.Errorf("cardPointValue(%v) = %d, want %d", tt.card, got, tt.want)
}
})
}
}
func TestScoreHand(t *testing.T) {
hand := []unoCard{
{unoRed, unoFive}, // 5
{unoBlue, unoNine}, // 9
{unoGreen, unoSkip}, // 20
{unoWild, unoWildCard}, // 50
}
got := scoreHand(hand)
want := 84
if got != want {
t.Errorf("scoreHand() = %d, want %d", got, want)
}
}
func TestScoreHandEmpty(t *testing.T) {
if got := scoreHand(nil); got != 0 {
t.Errorf("scoreHand(nil) = %d, want 0", got)
}
}