235 lines
8.9 KiB
Go
235 lines
8.9 KiB
Go
package main
|
||
|
||
import "testing"
|
||
|
||
func TestNewCheckersGameSetup(t *testing.T) {
|
||
g := NewCheckersGame()
|
||
whiteCount, blackCount := 0, 0
|
||
for r := 0; r < 8; r++ {
|
||
for c := 0; c < 8; c++ {
|
||
p := g.Board[r][c]
|
||
if p == nil {
|
||
continue
|
||
}
|
||
if (r+c)%2 == 0 {
|
||
t.Errorf("шашка на светлой клетке (%d,%d)", r, c)
|
||
}
|
||
if p.Color == CheckersWhite {
|
||
whiteCount++
|
||
} else {
|
||
blackCount++
|
||
}
|
||
}
|
||
}
|
||
if whiteCount != 12 || blackCount != 12 {
|
||
t.Errorf("ожидалось по 12 шашек, получено white=%d black=%d", whiteCount, blackCount)
|
||
}
|
||
if g.Turn != CheckersWhite {
|
||
t.Errorf("первый ход должен быть за белыми")
|
||
}
|
||
}
|
||
|
||
func TestSimpleManMoveForwardOnly(t *testing.T) {
|
||
g := &CheckersGameState{Turn: CheckersWhite}
|
||
g.Board[5][2] = &CheckersPiece{Color: CheckersWhite}
|
||
|
||
if err := g.Move(CheckersPos{5, 2}, CheckersPos{4, 1}); err != nil {
|
||
t.Fatalf("неожиданная ошибка хода вперёд: %v", err)
|
||
}
|
||
}
|
||
|
||
func TestSimpleManCannotMoveBackward(t *testing.T) {
|
||
g := &CheckersGameState{Turn: CheckersWhite}
|
||
g.Board[5][2] = &CheckersPiece{Color: CheckersWhite}
|
||
|
||
if err := g.Move(CheckersPos{5, 2}, CheckersPos{6, 1}); err != ErrCheckersInvalidMove {
|
||
t.Errorf("простая шашка не должна ходить назад, ожидалась ErrCheckersInvalidMove, получено: %v", err)
|
||
}
|
||
}
|
||
|
||
func TestManCapturesBackward(t *testing.T) {
|
||
g := &CheckersGameState{Turn: CheckersWhite}
|
||
g.Board[4][3] = &CheckersPiece{Color: CheckersWhite}
|
||
g.Board[5][4] = &CheckersPiece{Color: CheckersBlack}
|
||
|
||
if err := g.Move(CheckersPos{4, 3}, CheckersPos{6, 5}); err != nil {
|
||
t.Fatalf("шашка должна была взять назад: %v", err)
|
||
}
|
||
if g.Board[5][4] != nil {
|
||
t.Errorf("взятая шашка должна была исчезнуть с доски")
|
||
}
|
||
if g.Board[6][5] == nil {
|
||
t.Errorf("шашка должна была оказаться на клетке приземления")
|
||
}
|
||
}
|
||
|
||
func TestCaptureIsMandatory(t *testing.T) {
|
||
g := &CheckersGameState{Turn: CheckersWhite}
|
||
g.Board[5][2] = &CheckersPiece{Color: CheckersWhite}
|
||
g.Board[4][3] = &CheckersPiece{Color: CheckersBlack}
|
||
g.Board[5][6] = &CheckersPiece{Color: CheckersWhite}
|
||
|
||
if err := g.Move(CheckersPos{5, 6}, CheckersPos{4, 5}); err != ErrCheckersMustCapture {
|
||
t.Errorf("простой ход должен быть запрещён при доступном взятии, получено: %v", err)
|
||
}
|
||
if err := g.Move(CheckersPos{5, 2}, CheckersPos{3, 4}); err != nil {
|
||
t.Fatalf("взятие должно было пройти: %v", err)
|
||
}
|
||
}
|
||
|
||
func TestMultiJumpMustContinueWithSamePiece(t *testing.T) {
|
||
g := &CheckersGameState{Turn: CheckersWhite}
|
||
g.Board[6][1] = &CheckersPiece{Color: CheckersWhite}
|
||
g.Board[5][2] = &CheckersPiece{Color: CheckersBlack}
|
||
g.Board[3][4] = &CheckersPiece{Color: CheckersBlack}
|
||
g.Board[6][7] = &CheckersPiece{Color: CheckersWhite} // другая белая шашка — ходить ею сейчас нельзя
|
||
|
||
if err := g.Move(CheckersPos{6, 1}, CheckersPos{4, 3}); err != nil {
|
||
t.Fatalf("первое взятие должно было пройти: %v", err)
|
||
}
|
||
if g.ChainPos == nil {
|
||
t.Fatalf("ожидалось продолжение серии взятий той же шашкой")
|
||
}
|
||
if g.Turn != CheckersWhite {
|
||
t.Errorf("ход не должен был перейти сопернику в середине серии")
|
||
}
|
||
|
||
if err := g.Move(CheckersPos{6, 7}, CheckersPos{5, 6}); err != ErrCheckersMustContinue {
|
||
t.Errorf("ход другой шашкой в середине серии взятий должен быть запрещён, получено: %v", err)
|
||
}
|
||
|
||
if err := g.Move(CheckersPos{4, 3}, CheckersPos{2, 5}); err != nil {
|
||
t.Fatalf("второе взятие в серии должно было пройти: %v", err)
|
||
}
|
||
if g.ChainPos != nil {
|
||
t.Errorf("серия должна была завершиться — больше взятий нет")
|
||
}
|
||
if g.Turn != CheckersBlack {
|
||
t.Errorf("ход должен был перейти чёрным после завершения серии")
|
||
}
|
||
if g.Board[5][2] != nil || g.Board[3][4] != nil {
|
||
t.Errorf("обе взятые шашки должны были исчезнуть с доски")
|
||
}
|
||
}
|
||
|
||
func TestPromotionToKing(t *testing.T) {
|
||
g := &CheckersGameState{Turn: CheckersWhite}
|
||
g.Board[1][2] = &CheckersPiece{Color: CheckersWhite}
|
||
|
||
if err := g.Move(CheckersPos{1, 2}, CheckersPos{0, 1}); err != nil {
|
||
t.Fatalf("неожиданная ошибка: %v", err)
|
||
}
|
||
if !g.Board[0][1].King {
|
||
t.Errorf("шашка должна была стать дамкой на последней горизонтали")
|
||
}
|
||
}
|
||
|
||
func TestPromotionDuringCaptureContinuesAsKing(t *testing.T) {
|
||
g := &CheckersGameState{Turn: CheckersWhite}
|
||
g.Board[2][1] = &CheckersPiece{Color: CheckersWhite}
|
||
g.Board[1][2] = &CheckersPiece{Color: CheckersBlack}
|
||
g.Board[2][5] = &CheckersPiece{Color: CheckersBlack}
|
||
|
||
if err := g.Move(CheckersPos{2, 1}, CheckersPos{0, 3}); err != nil {
|
||
t.Fatalf("неожиданная ошибка: %v", err)
|
||
}
|
||
if !g.Board[0][3].King {
|
||
t.Fatalf("шашка должна была стать дамкой при взятии на последней горизонтали")
|
||
}
|
||
if g.ChainPos == nil {
|
||
t.Fatalf("если дальнейшее взятие возможно дамкой — серия должна продолжиться")
|
||
}
|
||
}
|
||
|
||
func TestKingFlyingMove(t *testing.T) {
|
||
g := &CheckersGameState{Turn: CheckersWhite}
|
||
g.Board[4][4] = &CheckersPiece{Color: CheckersWhite, King: true}
|
||
|
||
if err := g.Move(CheckersPos{4, 4}, CheckersPos{1, 1}); err != nil {
|
||
t.Fatalf("дамка должна летать на любое расстояние по диагонали: %v", err)
|
||
}
|
||
}
|
||
|
||
func TestKingFlyingCaptureWithChoiceOfLanding(t *testing.T) {
|
||
g := &CheckersGameState{Turn: CheckersWhite}
|
||
g.Board[7][0] = &CheckersPiece{Color: CheckersWhite, King: true}
|
||
g.Board[4][3] = &CheckersPiece{Color: CheckersBlack}
|
||
|
||
options := g.captureMoveOptions(CheckersPos{7, 0})
|
||
if len(options) == 0 {
|
||
t.Fatalf("ожидались варианты взятия дамкой")
|
||
}
|
||
landed := false
|
||
for _, opt := range options {
|
||
if opt.To == (CheckersPos{2, 5}) {
|
||
landed = true
|
||
}
|
||
}
|
||
if !landed {
|
||
t.Errorf("среди вариантов должна быть клетка (2,5)")
|
||
}
|
||
|
||
if err := g.Move(CheckersPos{7, 0}, CheckersPos{1, 6}); err != nil {
|
||
t.Fatalf("выбор дальней клетки приземления должен быть допустим: %v", err)
|
||
}
|
||
if g.Board[4][3] != nil {
|
||
t.Errorf("взятая шашка должна была исчезнуть")
|
||
}
|
||
}
|
||
|
||
func TestKingCannotJumpOverTwoPiecesInARow(t *testing.T) {
|
||
g := &CheckersGameState{Turn: CheckersWhite}
|
||
g.Board[7][0] = &CheckersPiece{Color: CheckersWhite, King: true}
|
||
g.Board[4][3] = &CheckersPiece{Color: CheckersBlack}
|
||
g.Board[3][4] = &CheckersPiece{Color: CheckersBlack}
|
||
|
||
options := g.captureMoveOptions(CheckersPos{7, 0})
|
||
for _, opt := range options {
|
||
if opt.To.Row <= 3 {
|
||
t.Errorf("нельзя приземлиться за второй подряд фигурой, но получен вариант %v", opt.To)
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestGameOverWhenNoLegalMoves(t *testing.T) {
|
||
g := &CheckersGameState{Turn: CheckersBlack}
|
||
g.Board[0][7] = &CheckersPiece{Color: CheckersBlack}
|
||
g.Board[1][6] = &CheckersPiece{Color: CheckersWhite}
|
||
// (2,5) занята — иначе чёрная шашка могла бы взять белую назад
|
||
// через прыжок (0,7)->(2,5), ведь простые шашки в русских шашках
|
||
// бьют в любом направлении, включая назад
|
||
g.Board[2][5] = &CheckersPiece{Color: CheckersWhite}
|
||
g.Board[5][0] = &CheckersPiece{Color: CheckersWhite}
|
||
|
||
g.Turn = CheckersWhite
|
||
if err := g.Move(CheckersPos{5, 0}, CheckersPos{4, 1}); err != nil {
|
||
t.Fatalf("неожиданная ошибка: %v", err)
|
||
}
|
||
if g.Result == nil {
|
||
t.Fatalf("партия должна была завершиться — у чёрных нет ходов")
|
||
}
|
||
if g.Result.Winner != CheckersWhite {
|
||
t.Errorf("ожидался победитель — белые")
|
||
}
|
||
}
|
||
|
||
func TestDrawByNoCaptureLimit(t *testing.T) {
|
||
g := &CheckersGameState{Turn: CheckersWhite, MovesSinceCapture: maxCheckersMovesWithoutCapture - 1}
|
||
g.Board[5][2] = &CheckersPiece{Color: CheckersWhite}
|
||
|
||
if err := g.Move(CheckersPos{5, 2}, CheckersPos{4, 1}); err != nil {
|
||
t.Fatalf("неожиданная ошибка: %v", err)
|
||
}
|
||
if g.Result == nil || !g.Result.Draw {
|
||
t.Fatalf("ожидалась ничья по лимиту ходов без взятия")
|
||
}
|
||
}
|
||
|
||
func TestCannotMoveOpponentPiece(t *testing.T) {
|
||
g := &CheckersGameState{Turn: CheckersWhite}
|
||
g.Board[2][1] = &CheckersPiece{Color: CheckersBlack}
|
||
|
||
if err := g.Move(CheckersPos{2, 1}, CheckersPos{3, 2}); err != ErrCheckersNoPiece {
|
||
t.Errorf("ожидалась ошибка хода чужой шашкой, получено: %v", err)
|
||
}
|
||
}
|