go_games_collection/go_bot_test.go

98 lines
3.3 KiB
Go

package main
import (
"math/rand"
"testing"
)
// goRandomLegalMove находит случайную легальную точку для текущего
// игрока (или сигнализирует, что стоит пасовать, если ничего не
// нашлось за разумное число попыток).
func goRandomLegalMove(g *GoGameState, rnd *rand.Rand) (GoPos, bool) {
size := g.Size
order := rnd.Perm(size * size)
for _, idx := range order {
pos := GoPos{Row: idx / size, Col: idx % size}
if g.IsLegal(pos) {
return pos, true
}
}
return GoPos{}, false
}
func TestGoRandomGamesNoCorruption(t *testing.T) {
rnd := rand.New(rand.NewSource(1))
for _, size := range []int{9, 13, 19} {
for game := 0; game < 10; game++ {
g := NewGoGame(size)
const maxMoves = 500
moves := 0
for ; moves < maxMoves && g.Result == nil; moves++ {
pos, ok := goRandomLegalMove(g, rnd)
if !ok {
if err := g.Pass(); err != nil {
t.Fatalf("размер %d, игра %d: неожиданная ошибка паса: %v", size, game, err)
}
continue
}
if err := g.Play(pos); err != nil {
t.Fatalf("размер %d, игра %d, ход %d: неожиданная ошибка легального хода %v: %v",
size, game, moves, pos, err)
}
}
if g.Result == nil {
g.Pass()
g.Pass()
}
if g.Result == nil {
t.Fatalf("размер %d, игра %d: партия так и не завершилась", size, game)
}
if g.Result.BlackScore < 0 || g.Result.WhiteScore < GoKomi {
t.Errorf("размер %d, игра %d: подозрительный счёт %+v", size, game, g.Result)
}
}
}
}
func TestGoLegalMoveEnumerationPerformance19x19(t *testing.T) {
g := NewGoGame(19)
rnd := rand.New(rand.NewSource(2))
for i := 0; i < 60; i++ {
pos, ok := goRandomLegalMove(g, rnd)
if !ok {
break
}
if err := g.Play(pos); err != nil {
t.Fatalf("шаг %d: неожиданная ошибка: %v", i, err)
}
}
}
// TestGoBotFullGames прогоняет несколько полных партий бота против
// самого себя на каждом размере доски и уровне сложности, проверяя
// отсутствие паник, зависаний и корректность итогового результата.
func TestGoBotFullGames(t *testing.T) {
rnd := rand.New(rand.NewSource(3))
for _, size := range []int{9, 13, 19} {
for _, diff := range []GoDifficulty{GoDifficultyEasy, GoDifficultyMedium, GoDifficultyHard} {
bot := GoBot{Difficulty: diff}
g := NewGoGame(size)
const maxMoves = 800
moves := 0
for ; moves < maxMoves && g.Result == nil; moves++ {
if err := bot.PlayFullTurn(g, rnd); err != nil {
t.Fatalf("размер %d, сложность %d, ход %d: неожиданная ошибка: %v", size, diff, moves, err)
}
}
if g.Result == nil {
t.Fatalf("размер %d, сложность %d: партия не завершилась за %d ходов", size, diff, maxMoves)
}
if g.Result.WhiteScore < GoKomi {
t.Errorf("размер %d, сложность %d: подозрительный счёт белых %v (меньше коми)", size, diff, g.Result.WhiteScore)
}
}
}
}