mirror of
https://github.com/MADTeacher/go_basics.git
synced 2025-11-23 21:34:47 +02:00
204 lines
4.2 KiB
Go
204 lines
4.2 KiB
Go
package board
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
)
|
|
|
|
const (
|
|
BoardDefaultSize int = 3
|
|
BoardMinSize int = 3
|
|
BoardMaxSize int = 9
|
|
)
|
|
|
|
type Board struct {
|
|
Board [][]BoardField `json:"board"`
|
|
Size int `json:"size"`
|
|
}
|
|
|
|
func NewBoard(size int) *Board {
|
|
board := make([][]BoardField, size)
|
|
for i := range board {
|
|
board[i] = make([]BoardField, size)
|
|
}
|
|
return &Board{Board: board, Size: size}
|
|
}
|
|
|
|
func (b *Board) IsEmpty() bool {
|
|
for i := range b.Size {
|
|
for j := range b.Size {
|
|
if b.Board[i][j] != Empty {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Отображение игрового поля
|
|
func (b *Board) PrintBoard() {
|
|
fmt.Print(" ")
|
|
for i := range b.Size {
|
|
fmt.Printf("%d ", i+1)
|
|
}
|
|
fmt.Println()
|
|
for i := range b.Size {
|
|
fmt.Printf("%d ", i+1)
|
|
for j := range b.Size {
|
|
switch b.Board[i][j] {
|
|
case Empty:
|
|
fmt.Print(". ")
|
|
case Cross:
|
|
fmt.Print("X ")
|
|
case Nought:
|
|
fmt.Print("O ")
|
|
}
|
|
}
|
|
fmt.Println()
|
|
}
|
|
}
|
|
|
|
// Проверка возможности и выполнения хода
|
|
func (b *Board) makeMove(x, y int) bool {
|
|
return b.Board[x][y] == Empty
|
|
}
|
|
|
|
func (b *Board) SetSymbol(x, y int, player BoardField) bool {
|
|
if b.makeMove(x, y) {
|
|
b.Board[x][y] = player
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Проверка выигрыша
|
|
func (b *Board) CheckWin(player BoardField) bool {
|
|
if b.Size <= 4 {
|
|
// Для маленьких досок используем обычную проверку
|
|
return b.checkWinSequential(player)
|
|
}
|
|
|
|
// Для больших досок используем параллельную проверку
|
|
|
|
// 3 направления проверок: строки/столбцы, 2 диагонали
|
|
resultChan := make(chan bool, 3)
|
|
var wg sync.WaitGroup
|
|
wg.Add(3)
|
|
|
|
// Параллельная проверка строк и столбцов
|
|
go func() {
|
|
defer wg.Done()
|
|
for i := range b.Size {
|
|
rowWin, colWin := true, true
|
|
for j := 0; j < b.Size; j++ {
|
|
if b.Board[i][j] != player {
|
|
rowWin = false
|
|
}
|
|
if b.Board[j][i] != player {
|
|
colWin = false
|
|
}
|
|
}
|
|
if rowWin || colWin {
|
|
resultChan <- true
|
|
return // Нашли выигрыш, выходим из горутины
|
|
}
|
|
}
|
|
resultChan <- false
|
|
}()
|
|
|
|
// Параллельная проверка главной диагонали
|
|
go func() {
|
|
defer wg.Done()
|
|
mainDiag := true
|
|
for i := range b.Size {
|
|
if b.Board[i][i] != player {
|
|
mainDiag = false
|
|
break
|
|
}
|
|
}
|
|
resultChan <- mainDiag
|
|
}()
|
|
|
|
// Параллельная проверка побочной диагонали
|
|
go func() {
|
|
defer wg.Done()
|
|
antiDiag := true
|
|
for i := range b.Size {
|
|
if b.Board[i][b.Size-i-1] != player {
|
|
antiDiag = false
|
|
break
|
|
}
|
|
}
|
|
resultChan <- antiDiag
|
|
}()
|
|
|
|
// Запускаем горутину, которая закроет канал после завершения всех проверок
|
|
go func() {
|
|
wg.Wait()
|
|
close(resultChan)
|
|
}()
|
|
|
|
// Получаем результаты проверок с помощью for range.
|
|
// Этот цикл будет ждать, пока канал не будет закрыт.
|
|
for result := range resultChan {
|
|
if result {
|
|
return true // Найден выигрыш.
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// Оригинальный алгоритм проверки выигрыша для малых досок
|
|
func (b *Board) checkWinSequential(player BoardField) bool {
|
|
// Проверка строк и столбцов
|
|
for i := range b.Size {
|
|
rowWin, colWin := true, true
|
|
for j := range b.Size {
|
|
if b.Board[i][j] != player {
|
|
rowWin = false
|
|
}
|
|
if b.Board[j][i] != player {
|
|
colWin = false
|
|
}
|
|
}
|
|
if rowWin || colWin {
|
|
return true
|
|
}
|
|
}
|
|
|
|
// Главная диагональ
|
|
mainDiag := true
|
|
for i := range b.Size {
|
|
if b.Board[i][i] != player {
|
|
mainDiag = false
|
|
break
|
|
}
|
|
}
|
|
if mainDiag {
|
|
return true
|
|
}
|
|
|
|
// Побочная диагональ
|
|
antiDiag := true
|
|
for i := range b.Size {
|
|
if b.Board[i][b.Size-i-1] != player {
|
|
antiDiag = false
|
|
break
|
|
}
|
|
}
|
|
return antiDiag
|
|
}
|
|
|
|
// Проверка на ничью
|
|
func (b *Board) CheckDraw() bool {
|
|
for i := range b.Size {
|
|
for j := range b.Size {
|
|
if b.Board[i][j] == Empty {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
return true
|
|
}
|