package main

import (
	"math/rand"
	"testing"
)

// TestMinesweeperRandomGamesNoCorruption прогоняет много случайных
// партий на каждом классическом пресете размера, проверяя
// отсутствие паник и что каждая партия корректно завершается
// (победой или поражением) за разумное число ходов.
func TestMinesweeperRandomGamesNoCorruption(t *testing.T) {
	rnd := rand.New(rand.NewSource(1))

	presets := []struct{ w, h, mines int }{
		{9, 9, 10},
		{16, 16, 40},
		{30, 16, 99},
	}

	for _, p := range presets {
		for game := 0; game < 20; game++ {
			g := NewMinesweeperGame(p.w, p.h, p.mines)
			const maxMoves = 2000
			moves := 0
			for ; moves < maxMoves && g.Result == nil; moves++ {
				var candidates []MinesweeperPos
				for r := 0; r < g.Height; r++ {
					for c := 0; c < g.Width; c++ {
						cell := g.Board[r][c]
						if !cell.Revealed && !cell.Flagged {
							candidates = append(candidates, msp(r, c))
						}
					}
				}
				if len(candidates) == 0 {
					break
				}
				pos := candidates[rnd.Intn(len(candidates))]
				if err := g.Reveal(pos); err != nil {
					t.Fatalf("пресет %dx%d/%d, игра %d, ход %d: неожиданная ошибка: %v",
						p.w, p.h, p.mines, game, moves, err)
				}
			}
			if g.Result == nil {
				t.Fatalf("пресет %dx%d/%d, игра %d: партия не завершилась за %d ходов",
					p.w, p.h, p.mines, game, maxMoves)
			}
		}
	}
}
