1
0
mirror of https://github.com/MADTeacher/go_basics.git synced 2025-11-23 21:34:47 +02:00

Крестики-нолики

Добавлен сквозной проект для 1-й главы
This commit is contained in:
Stanislav Chernyshev
2025-05-22 17:35:18 +03:00
parent e04e890078
commit 9a4cd8e60f
3 changed files with 264 additions and 0 deletions

14
part_1/tic_tac_toe/.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,14 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch Package",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${fileDirname}", // <- ставим запятую
"console": "integratedTerminal"
}
]
}

View File

@@ -0,0 +1,3 @@
module tic-tac-toe
go 1.24.0

247
part_1/tic_tac_toe/main.go Normal file
View File

@@ -0,0 +1,247 @@
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
type GameState int
type BoardField int
const (
empty BoardField = iota
cross
nought
)
const (
playing GameState = iota
draw
crossWin
noughtWin
quit
)
func main() {
reader := bufio.NewReader(os.Stdin)
boardSize := 3 // размер игрового поля по умолчанию
state := playing
currentPlayer := cross // текущий игрок
// Ввод размера доски
for {
fmt.Print("Enter the size of the board (3-9): ")
input, err := reader.ReadString('\n')
if err != nil {
fmt.Println("Error reading input. Please try again.")
continue
}
input = strings.TrimSpace(input)
size, err := strconv.Atoi(input)
if err != nil {
size = boardSize
}
if size < 3 || size > 9 {
fmt.Println("Invalid size, please enter again")
continue
}
boardSize = size
break
}
// Инициализация доски
board := make([][]BoardField, boardSize)
for i := range boardSize {
board[i] = make([]BoardField, boardSize)
}
// Вывод в терминал состояния игрового поля
fmt.Print(" ")
for i := range boardSize {
fmt.Printf("%d ", i+1) // вывод номера столбца
}
fmt.Println()
for i := range boardSize {
fmt.Printf("%d ", i+1) // вывод номера строки
for j := range boardSize {
switch board[i][j] {
case empty:
fmt.Print(". ")
case cross:
fmt.Print("X ")
case nought:
fmt.Print("O ")
}
}
fmt.Println()
}
// Завершение вывода в терминал
// Основной игровой цикл
for state == playing {
// Вывод сообщения о ходе текущего игрока
playerSymbol := "X"
if currentPlayer == nought {
playerSymbol = "O"
}
fmt.Printf("%s's turn. Enter row and column (e.g. 1 2): ",
playerSymbol)
validInput := false
for !validInput {
input, err := reader.ReadString('\n')
if err != nil {
fmt.Println("Invalid input. Please try again.")
continue
}
input = strings.TrimSpace(input)
if input == "q" {
state = quit
break
}
parts := strings.Fields(input)
if len(parts) != 2 {
fmt.Println("Invalid input. Please try again.")
continue
}
row, err1 := strconv.Atoi(parts[0])
col, err2 := strconv.Atoi(parts[1])
if err1 != nil || err2 != nil {
fmt.Println("Invalid input. Please try again.")
continue
}
if row < 1 || row > boardSize || col < 1 || col > boardSize {
fmt.Println("Invalid input. Please try again.")
continue
}
// Приведение к 0-индексации
row--
col--
if board[row][col] != empty {
fmt.Println("This cell is already occupied!")
continue
}
// Выполнение хода
board[row][col] = currentPlayer
// Проверка выигрыша по строкам и столбцам
winFound := false
for i := range boardSize {
rowWin := true
colWin := true
for j := range boardSize {
if board[i][j] != currentPlayer {
rowWin = false
}
if board[j][i] != currentPlayer {
colWin = false
}
}
if rowWin || colWin {
winFound = true
break
}
}
// Проверка главной диагонали
if !winFound {
diagWin := true
for i := range boardSize {
if board[i][i] != currentPlayer {
diagWin = false
break
}
}
if diagWin {
winFound = true
}
}
// Проверка обратной диагонали
if !winFound {
antiDiagWin := true
for i := range boardSize {
if board[i][boardSize-i-1] != currentPlayer {
antiDiagWin = false
break
}
}
if antiDiagWin {
winFound = true
}
}
if winFound {
if currentPlayer == cross {
state = crossWin
} else {
state = noughtWin
}
} else {
// Проверка на ничью (заполнена ли доска)
full := true
for i := range boardSize {
for j := range boardSize {
if board[i][j] == empty {
full = false
break
}
}
if !full {
break
}
}
if full {
state = draw
}
}
// Вывод текущего состояния доски
fmt.Print(" ")
for i := range boardSize {
fmt.Printf("%d ", i+1)
}
fmt.Println()
for i := range boardSize {
fmt.Printf("%d ", i+1)
for j := range boardSize {
switch board[i][j] {
case empty:
fmt.Print(". ")
case cross:
fmt.Print("X ")
case nought:
fmt.Print("O ")
}
}
fmt.Println()
}
// Вывод сообщения о результате, если игра окончена
if state == crossWin {
fmt.Println("X wins!")
} else if state == noughtWin {
fmt.Println("O wins!")
} else if state == draw {
fmt.Println("It's a draw!")
} else {
// Переключение игрока, если игра продолжается
if currentPlayer == cross {
currentPlayer = nought
} else {
currentPlayer = cross
}
}
validInput = true
}
}
}