215 lines
6.7 KiB
Go
215 lines
6.7 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
)
|
|
|
|
func TestPokerModelBotsGetRandomDifficulties(t *testing.T) {
|
|
m := NewPokerModel(4)
|
|
if len(m.bots) != 3 {
|
|
t.Fatalf("ожидалось 3 бота (4 игрока минус человек), получено %d", len(m.bots))
|
|
}
|
|
for seat, bot := range m.bots {
|
|
if bot.Difficulty < PokerDifficultyEasy || bot.Difficulty > PokerDifficultyHard {
|
|
t.Errorf("бот на месте %d получил недопустимый уровень сложности %v", seat, bot.Difficulty)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPokerModelHumanIsSeatZero(t *testing.T) {
|
|
m := NewPokerModel(3)
|
|
if m.humanSeat != 0 {
|
|
t.Errorf("человек должен всегда занимать место 0, получено %d", m.humanSeat)
|
|
}
|
|
if _, isBot := m.bots[m.humanSeat]; isBot {
|
|
t.Errorf("на месте человека не должно быть бота")
|
|
}
|
|
}
|
|
|
|
func TestPokerModelFoldViaKey(t *testing.T) {
|
|
m := NewPokerModel(3)
|
|
m.game.CurrentPlayerIdx = m.humanSeat
|
|
next, _ := m.Update(key("1"))
|
|
m = next.(PokerModel)
|
|
if !m.game.Players[m.humanSeat].Folded {
|
|
t.Errorf("после выбора действия 'сбросить' игрок должен был сбросить карты")
|
|
}
|
|
}
|
|
|
|
func TestPokerModelRejectsActionWhenNotHumanTurn(t *testing.T) {
|
|
m := NewPokerModel(3)
|
|
m.game.CurrentPlayerIdx = (m.humanSeat + 1) % 3
|
|
next, _ := m.Update(key("1"))
|
|
m = next.(PokerModel)
|
|
if m.game.Players[m.humanSeat].Folded {
|
|
t.Errorf("действие не должно было приняться — сейчас не ход человека")
|
|
}
|
|
}
|
|
|
|
func TestPokerModelBetAmountSubmode(t *testing.T) {
|
|
m := NewPokerModel(2)
|
|
m.game.CurrentPlayerIdx = m.humanSeat
|
|
actions := m.pokerHumanActions()
|
|
betIdx := -1
|
|
for i, a := range actions {
|
|
if a == "bet" {
|
|
betIdx = i
|
|
}
|
|
}
|
|
if betIdx < 0 {
|
|
t.Fatalf("ожидалось действие 'bet' среди доступных: %v", actions)
|
|
}
|
|
|
|
next, _ := m.Update(key(fmt.Sprintf("%d", betIdx+1)))
|
|
m = next.(PokerModel)
|
|
if !m.choosingBetAmount {
|
|
t.Fatalf("ожидался переход в подрежим выбора суммы ставки")
|
|
}
|
|
before := m.betAmount
|
|
|
|
next, _ = m.Update(key("up"))
|
|
m = next.(PokerModel)
|
|
if m.betAmount != before+m.game.BigBlind {
|
|
t.Errorf("ожидалось увеличение ставки на большой блайнд, было %d, стало %d", before, m.betAmount)
|
|
}
|
|
|
|
next, _ = m.Update(key("enter"))
|
|
m = next.(PokerModel)
|
|
if m.choosingBetAmount {
|
|
t.Errorf("подрежим должен был закрыться после подтверждения")
|
|
}
|
|
human := m.game.Players[m.humanSeat]
|
|
if human.CurrentBet != before+m.game.BigBlind {
|
|
t.Errorf("ставка должна была реально примениться, ожидалось %d, получено %d", before+m.game.BigBlind, human.CurrentBet)
|
|
}
|
|
}
|
|
|
|
func TestPokerModelBetAmountCancelDoesNotApply(t *testing.T) {
|
|
m := NewPokerModel(2)
|
|
m.game.CurrentPlayerIdx = m.humanSeat
|
|
betBefore := m.game.Players[m.humanSeat].CurrentBet
|
|
|
|
actions := m.pokerHumanActions()
|
|
betIdx := 0
|
|
for i, a := range actions {
|
|
if a == "bet" {
|
|
betIdx = i
|
|
}
|
|
}
|
|
next, _ := m.Update(key(fmt.Sprintf("%d", betIdx+1)))
|
|
m = next.(PokerModel)
|
|
next, _ = m.Update(key("esc"))
|
|
m = next.(PokerModel)
|
|
if m.choosingBetAmount {
|
|
t.Errorf("esc должен был закрыть подрежим без применения ставки")
|
|
}
|
|
if m.game.Players[m.humanSeat].CurrentBet != betBefore {
|
|
t.Errorf("отменённая ставка не должна была примениться")
|
|
}
|
|
}
|
|
|
|
func TestPokerModelBotPlaysWhenNotHumanTurn(t *testing.T) {
|
|
m := NewPokerModel(3)
|
|
for m.game.CurrentPlayerIdx == m.humanSeat {
|
|
m.game.CurrentPlayerIdx = (m.game.CurrentPlayerIdx + 1) % 3
|
|
}
|
|
next, _ := m.Update(botMoveMsg{})
|
|
m = next.(PokerModel)
|
|
if m.isError {
|
|
t.Errorf("неожиданная ошибка хода бота: %s", m.message)
|
|
}
|
|
}
|
|
|
|
func TestPokerModelIgnoresBotMoveMsgOnHumanTurn(t *testing.T) {
|
|
m := NewPokerModel(3)
|
|
m.game.CurrentPlayerIdx = m.humanSeat
|
|
before := *m.game
|
|
next, _ := m.Update(botMoveMsg{})
|
|
m = next.(PokerModel)
|
|
if m.game.CurrentPlayerIdx != before.CurrentPlayerIdx {
|
|
t.Errorf("botMoveMsg не должно было ничего менять, пока сейчас ход человека")
|
|
}
|
|
}
|
|
|
|
func TestPokerModelQReturnsToMenuNotQuitsApp(t *testing.T) {
|
|
m := NewPokerModel(3)
|
|
next, _ := m.Update(key("q"))
|
|
m = next.(PokerModel)
|
|
if !m.backToMenu {
|
|
t.Errorf("ожидался флаг backToMenu после 'q'")
|
|
}
|
|
if m.quitting {
|
|
t.Errorf("'q' не должно завершать приложение целиком")
|
|
}
|
|
}
|
|
|
|
func TestPokerModelNextHandViaKey(t *testing.T) {
|
|
m := NewPokerModel(2)
|
|
m.game.Players[0].HoleCards = [2]Card{c(Ace, Spades), c(Ace, Hearts)}
|
|
m.game.Players[1].HoleCards = [2]Card{c(Two, Clubs), c(Seven, Diamonds)}
|
|
m.game.Board = []Card{c(Ace, Clubs), c(King, Spades), c(Queen, Hearts), c(Four, Diamonds), c(Nine, Clubs)}
|
|
m.game.Players[0].TotalContributed = 100
|
|
m.game.Players[1].TotalContributed = 100
|
|
m.game.resolveShowdown()
|
|
|
|
next, _ := m.Update(key("n"))
|
|
m = next.(PokerModel)
|
|
if m.game.Phase == PokerPhaseShowdown {
|
|
t.Errorf("после 'n' должна была начаться новая раздача")
|
|
}
|
|
}
|
|
|
|
func TestPokerModelFullTournamentAutoPlaythrough(t *testing.T) {
|
|
m := NewPokerModel(4)
|
|
humanBot := PokerBot{Difficulty: PokerDifficultyMedium}
|
|
|
|
steps := 0
|
|
for m.game.Phase != PokerPhaseTournamentOver && steps < 50000 {
|
|
steps++
|
|
g := m.game
|
|
if g.Phase == PokerPhaseShowdown {
|
|
next, _ := m.Update(key("n"))
|
|
m = next.(PokerModel)
|
|
continue
|
|
}
|
|
if g.CurrentPlayerIdx != m.humanSeat {
|
|
next, _ := m.Update(botMoveMsg{})
|
|
m = next.(PokerModel)
|
|
continue
|
|
}
|
|
action := humanBot.DecideAction(g, m.humanSeat, m.rng)
|
|
actions := m.pokerHumanActions()
|
|
labelToKey := map[string]int{}
|
|
for i, a := range actions {
|
|
labelToKey[a] = i + 1
|
|
}
|
|
var keyStr string
|
|
switch action.Kind {
|
|
case "fold":
|
|
keyStr = fmt.Sprintf("%d", labelToKey["fold"])
|
|
case "check":
|
|
if idx, ok := labelToKey["check"]; ok {
|
|
keyStr = fmt.Sprintf("%d", idx)
|
|
} else {
|
|
keyStr = fmt.Sprintf("%d", labelToKey["call"])
|
|
}
|
|
case "call":
|
|
keyStr = fmt.Sprintf("%d", labelToKey["call"])
|
|
case "bet":
|
|
keyStr = fmt.Sprintf("%d", labelToKey["bet"])
|
|
}
|
|
next, _ := m.Update(key(keyStr))
|
|
m = next.(PokerModel)
|
|
if m.choosingBetAmount {
|
|
next, _ = m.Update(key("enter"))
|
|
m = next.(PokerModel)
|
|
}
|
|
if m.isError {
|
|
t.Fatalf("неожиданная ошибка при автопрогоне: %s", m.message)
|
|
}
|
|
}
|
|
if m.game.Phase != PokerPhaseTournamentOver {
|
|
t.Fatalf("турнир не завершился за %d шагов", steps)
|
|
}
|
|
}
|