go_games_collection/tictactoe_game_test.go

110 lines
4 KiB
Go

package main
import "testing"
func TestNewTicTacToeGameXAlwaysStartsFirst(t *testing.T) {
g := NewTicTacToeGame(TicTacToeO)
if g.CurrentTurn != TicTacToeX {
t.Errorf("крестики должны ходить первыми независимо от того, за кого играет человек")
}
}
func TestNewTicTacToeGameDefaultsToXOnInvalidMark(t *testing.T) {
g := NewTicTacToeGame(TicTacToeEmpty)
if g.HumanMark != TicTacToeX {
t.Errorf("недопустимый знак человека должен откатываться на крестики по умолчанию")
}
}
func TestPlaceMarkRejectsOccupiedCell(t *testing.T) {
g := NewTicTacToeGame(TicTacToeX)
if err := g.PlaceMark(0); err != nil {
t.Fatalf("неожиданная ошибка: %v", err)
}
if err := g.PlaceMark(0); err != ErrTicTacToeCellOccupied {
t.Errorf("ожидалась ошибка занятой клетки, получено: %v", err)
}
}
func TestPlaceMarkRejectsOutOfRange(t *testing.T) {
g := NewTicTacToeGame(TicTacToeX)
if err := g.PlaceMark(-1); err != ErrTicTacToeInvalidPosition {
t.Errorf("ожидалась ошибка недопустимой позиции для -1, получено: %v", err)
}
if err := g.PlaceMark(9); err != ErrTicTacToeInvalidPosition {
t.Errorf("ожидалась ошибка недопустимой позиции для 9, получено: %v", err)
}
}
func TestPlaceMarkRejectsAfterGameOver(t *testing.T) {
g := NewTicTacToeGame(TicTacToeX)
// X быстро выигрывает верхнюю строку: 0,1,2
moves := []int{0, 3, 1, 4, 2} // X: 0,1,2 O: 3,4
for _, pos := range moves {
if err := g.PlaceMark(pos); err != nil {
t.Fatalf("неожиданная ошибка на ходу %d: %v", pos, err)
}
}
if g.Phase != TicTacToePhaseOver || g.Result.Winner != TicTacToeX {
t.Fatalf("ожидалась победа крестиков, получено Phase=%v Result=%+v", g.Phase, g.Result)
}
if err := g.PlaceMark(5); err != ErrTicTacToeGameOver {
t.Errorf("ожидалась ошибка завершённой игры, получено: %v", err)
}
}
func TestAllEightWinLinesDetected(t *testing.T) {
lines := [8][3]int{
{0, 1, 2}, {3, 4, 5}, {6, 7, 8},
{0, 3, 6}, {1, 4, 7}, {2, 5, 8},
{0, 4, 8}, {2, 4, 6},
}
for _, line := range lines {
var board [9]TicTacToeMark
board[line[0]] = TicTacToeX
board[line[1]] = TicTacToeX
board[line[2]] = TicTacToeX
winner, gotLine, ok := ticTacToeCheckWin(board)
if !ok || winner != TicTacToeX {
t.Errorf("линия %v должна была засчитаться как победная", line)
}
if gotLine != line {
t.Errorf("ожидалась выигрышная линия %v, получено %v", line, gotLine)
}
}
}
func TestDrawWhenBoardFullWithoutWinner(t *testing.T) {
g := NewTicTacToeGame(TicTacToeX)
// классическая ничейная раскладка:
// X O X
// X O O
// O X X
moves := []int{0, 1, 2, 4, 3, 5, 7, 6, 8}
for i, pos := range moves {
if err := g.PlaceMark(pos); err != nil {
t.Fatalf("ход %d (клетка %d): неожиданная ошибка %v", i, pos, err)
}
if g.Phase == TicTacToePhaseOver && i != len(moves)-1 {
t.Fatalf("партия завершилась преждевременно на ходу %d (клетка %d), доска: %v", i, pos, g.Board)
}
}
if g.Phase != TicTacToePhaseOver || !g.Result.Draw {
t.Fatalf("ожидалась ничья, получено Phase=%v Result=%+v", g.Phase, g.Result)
}
}
func TestTurnAlternatesBetweenMoves(t *testing.T) {
g := NewTicTacToeGame(TicTacToeX)
if g.CurrentTurn != TicTacToeX {
t.Fatalf("ожидался первый ход крестиков")
}
g.PlaceMark(0)
if g.CurrentTurn != TicTacToeO {
t.Errorf("после хода крестиков должна ходить нолики")
}
g.PlaceMark(1)
if g.CurrentTurn != TicTacToeX {
t.Errorf("после хода ноликов должны снова ходить крестики")
}
}