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

small fix game

This commit is contained in:
Stanislav Chernyshev
2025-06-16 20:36:15 +03:00
parent 0029a1d728
commit 48f742916d
9 changed files with 52 additions and 83 deletions

View File

@@ -7,12 +7,13 @@ import (
s "tic-tac-toe/storage" s "tic-tac-toe/storage"
) )
// Game представляет состояние игры "Крестики-нолики"
type Game struct { type Game struct {
Board *b.Board `json:"board"` Board *b.Board `json:"board"`
Player p.IPlayer `json:"player"` Player p.IPlayer `json:"player"`
Player2 p.IPlayer `json:"-"` // Не сериализуется напрямую // Не сериализуется напрямую
CurrentPlayer p.IPlayer `json:"-"` // Не сериализуется напрямую Player2 p.IPlayer `json:"-"`
// Не сериализуется напрямую
CurrentPlayer p.IPlayer `json:"-"`
Reader *bufio.Reader `json:"-"` Reader *bufio.Reader `json:"-"`
State GameState `json:"state"` State GameState `json:"state"`
Saver s.IGameSaver `json:"-"` Saver s.IGameSaver `json:"-"`
@@ -24,7 +25,7 @@ type Game struct {
IsCurrentFirst bool `json:"is_current_first"` IsCurrentFirst bool `json:"is_current_first"`
} }
// NewGame создает новую игру // Создаем новую игру
func NewGame(board b.Board, reader *bufio.Reader, saver s.IGameSaver, func NewGame(board b.Board, reader *bufio.Reader, saver s.IGameSaver,
mode GameMode, difficulty p.Difficulty) *Game { mode GameMode, difficulty p.Difficulty) *Game {
// Создаем первого игрока (всегда человек на X) // Создаем первого игрока (всегда человек на X)
@@ -53,7 +54,7 @@ func NewGame(board b.Board, reader *bufio.Reader, saver s.IGameSaver,
} }
} }
// switchCurrentPlayer переключает активного игрока // Переключаем активного игрока
func (g *Game) switchCurrentPlayer() { func (g *Game) switchCurrentPlayer() {
if g.CurrentPlayer == g.Player { if g.CurrentPlayer == g.Player {
g.CurrentPlayer = g.Player2 g.CurrentPlayer = g.Player2
@@ -62,7 +63,7 @@ func (g *Game) switchCurrentPlayer() {
} }
} }
// updateState обновляет состояние игры на основе текущей доски // Обновляем состояние игры
func (g *Game) updateState() { func (g *Game) updateState() {
if g.Board.CheckWin(g.CurrentPlayer.GetFigure()) { if g.Board.CheckWin(g.CurrentPlayer.GetFigure()) {
if g.CurrentPlayer.GetFigure() == b.Cross { if g.CurrentPlayer.GetFigure() == b.Cross {

View File

@@ -4,11 +4,9 @@ import (
"fmt" "fmt"
"strings" "strings"
b "tic-tac-toe/board"
p "tic-tac-toe/player" p "tic-tac-toe/player"
) )
// Play запускает игровой цикл
func (g *Game) Play() bool { func (g *Game) Play() bool {
fmt.Println("For saving the game enter: save filename") fmt.Println("For saving the game enter: save filename")
fmt.Println("For exiting the game enter : q") fmt.Println("For exiting the game enter : q")
@@ -26,13 +24,10 @@ func (g *Game) Play() bool {
// Применяем ход компьютера к доске // Применяем ход компьютера к доске
g.Board.SetSymbol(row, col, g.CurrentPlayer.GetFigure()) g.Board.SetSymbol(row, col, g.CurrentPlayer.GetFigure())
} else { } else {
// Если ход человека, запрашиваем ввод fmt.Printf(
figure := g.CurrentPlayer.GetFigure() "%s's turn. Enter row and column (e.g. 1 2): ",
if figure == b.Cross { g.CurrentPlayer.GetSymbol(),
fmt.Print("X move: ") )
} else {
fmt.Print("O move: ")
}
// Читаем ввод пользователя // Читаем ввод пользователя
input, _ := g.Reader.ReadString('\n') input, _ := g.Reader.ReadString('\n')
@@ -96,9 +91,9 @@ func (g *Game) Play() bool {
return g.State != quit return g.State != quit
} }
// saveCheck проверяет, является ли ввод командой сохранения // Проверяем, являются ли введенные данные командой на сохранение
func (g *Game) saveCheck(input string) bool { func (g *Game) saveCheck(input string) bool {
// Проверяем, если пользователь ввёл только "save" без имени файла // Проверяем, если пользователь ввел только "save" без имени файла
if input == "save" { if input == "save" {
fmt.Println("Error: missing filename. " + fmt.Println("Error: missing filename. " +
"Please use the format: save filename") "Please use the format: save filename")

View File

@@ -9,14 +9,15 @@ import (
s "tic-tac-toe/storage" s "tic-tac-toe/storage"
) )
// PrepareForSave подготавливает игру к сохранению // Подготавливаем игру к сохранению
func (g *Game) PrepareForSave() { func (g *Game) prepareForSave() {
// Устанавливаем флаг текущего игрока // Устанавливаем флаг текущего игрока
g.IsCurrentFirst = (g.CurrentPlayer == g.Player) g.IsCurrentFirst = (g.CurrentPlayer == g.Player)
} }
// Возвращаем снапшот игровой сессии
func (g *Game) gameSnapshot() *m.GameSnapshot { func (g *Game) gameSnapshot() *m.GameSnapshot {
g.PrepareForSave() g.prepareForSave()
return &m.GameSnapshot{ return &m.GameSnapshot{
Board: g.Board, Board: g.Board,
PlayerFigure: g.Player.GetFigure(), PlayerFigure: g.Player.GetFigure(),
@@ -27,6 +28,7 @@ func (g *Game) gameSnapshot() *m.GameSnapshot {
} }
} }
// Восстанавливаем игру из снапшота
func (g *Game) RestoreFromSnapshot( func (g *Game) RestoreFromSnapshot(
snapshot *m.GameSnapshot, snapshot *m.GameSnapshot,
reader *bufio.Reader, reader *bufio.Reader,
@@ -47,7 +49,7 @@ func (g *Game) RestoreFromSnapshot(
g.recreatePlayersAfterLoad(reader) g.recreatePlayersAfterLoad(reader)
} }
// RecreatePlayersAfterLoad восстанавливает объекты игроков после загрузки из JSON // Восстанавливаем объекты игроков после загрузки из JSON
func (g *Game) recreatePlayersAfterLoad(reader *bufio.Reader) { func (g *Game) recreatePlayersAfterLoad(reader *bufio.Reader) {
// Создаем игроков в зависимости от режима игры // Создаем игроков в зависимости от режима игры
if g.Player == nil { if g.Player == nil {

View File

@@ -10,7 +10,7 @@ import (
s "tic-tac-toe/storage" s "tic-tac-toe/storage"
) )
// SetupGame создает новую игру с пользовательскими настройками // Создаем новую игру с пользовательскими настройками
func SetupGame(reader *bufio.Reader, saver s.IGameSaver) *Game { func SetupGame(reader *bufio.Reader, saver s.IGameSaver) *Game {
// Запрашиваем размер игрового поля // Запрашиваем размер игрового поля
size := getBoardSize(reader) size := getBoardSize(reader)
@@ -31,7 +31,7 @@ func SetupGame(reader *bufio.Reader, saver s.IGameSaver) *Game {
return NewGame(board, reader, saver, mode, difficulty) return NewGame(board, reader, saver, mode, difficulty)
} }
// getBoardSize запрашивает у пользователя размер доски // Запрашиваем у пользователя размер доски
func getBoardSize(reader *bufio.Reader) int { func getBoardSize(reader *bufio.Reader) int {
size := b.BoardDefaultSize size := b.BoardDefaultSize
var err error var err error
@@ -58,7 +58,7 @@ func getBoardSize(reader *bufio.Reader) int {
} }
} }
// getGameMode запрашивает у пользователя режим игры // Запрашиваем у пользователя режим игры
func getGameMode(reader *bufio.Reader) GameMode { func getGameMode(reader *bufio.Reader) GameMode {
for { for {
fmt.Println("Choose game mode:") fmt.Println("Choose game mode:")
@@ -85,7 +85,7 @@ func getGameMode(reader *bufio.Reader) GameMode {
} }
} }
// getDifficulty запрашивает у пользователя уровень сложности компьютера // Запрашиваем у пользователя уровень сложности компьютера
func getDifficulty(reader *bufio.Reader) p.Difficulty { func getDifficulty(reader *bufio.Reader) p.Difficulty {
for { for {
fmt.Println("Choose computer difficulty:") fmt.Println("Choose computer difficulty:")

View File

@@ -24,8 +24,7 @@ func main() {
input = strings.TrimSpace(input) input = strings.TrimSpace(input)
switch input { switch input {
case "1": case "1": // Загрузка сохраненной игры
// Загрузка сохраненной игры
loadedGame := &game.Game{} loadedGame := &game.Game{}
for { for {
@@ -51,9 +50,9 @@ func main() {
// Запускаем игру // Запускаем игру
loadedGame.Play() loadedGame.Play()
case "2": case "2": // Создаем новую игру с помощью диалога настройки
// Создаем новую игру с помощью диалога настройки newGame := game.SetupGame(reader,
newGame := game.SetupGame(reader, gameStorage.(storage.IGameSaver)) gameStorage.(storage.IGameSaver))
// Запускаем игру // Запускаем игру
newGame.Play() newGame.Play()

View File

@@ -1,4 +1,4 @@
package game package player
import ( import (
"fmt" "fmt"
@@ -16,14 +16,14 @@ const (
Hard Hard
) )
// ComputerPlayer представляет игрока-компьютера // Структура для представления игрока-компьютера
type ComputerPlayer struct { type ComputerPlayer struct {
Figure b.BoardField `json:"figure"` Figure b.BoardField `json:"figure"`
Difficulty Difficulty `json:"difficulty"` Difficulty Difficulty `json:"difficulty"`
rand *rand.Rand rand *rand.Rand
} }
// NewComputerPlayer создает нового игрока-компьютера с заданным уровнем сложности // Создаем нового игрока-компьютера с заданным уровнем сложности
func NewComputerPlayer( func NewComputerPlayer(
figure b.BoardField, figure b.BoardField,
difficulty Difficulty, difficulty Difficulty,
@@ -36,7 +36,6 @@ func NewComputerPlayer(
} }
} }
// GetSymbol возвращает символ игрока
func (p *ComputerPlayer) GetSymbol() string { func (p *ComputerPlayer) GetSymbol() string {
if p.Figure == b.Cross { if p.Figure == b.Cross {
return "X" return "X"
@@ -44,7 +43,6 @@ func (p *ComputerPlayer) GetSymbol() string {
return "O" return "O"
} }
// SwitchPlayer изменяет фигуру текущего игрока
func (p *ComputerPlayer) SwitchPlayer() { func (p *ComputerPlayer) SwitchPlayer() {
if p.Figure == b.Cross { if p.Figure == b.Cross {
p.Figure = b.Nought p.Figure = b.Nought
@@ -53,17 +51,15 @@ func (p *ComputerPlayer) SwitchPlayer() {
} }
} }
// GetFigure возвращает текущую фигуру игрока
func (p *ComputerPlayer) GetFigure() b.BoardField { func (p *ComputerPlayer) GetFigure() b.BoardField {
return p.Figure return p.Figure
} }
// IsComputer возвращает true для компьютера
func (p *ComputerPlayer) IsComputer() bool { func (p *ComputerPlayer) IsComputer() bool {
return true return true
} }
// MakeMove реализует ход компьютера в зависимости от выбранной сложности // Реализуем ход компьютера в зависимости от выбранной сложности
func (p *ComputerPlayer) MakeMove(board *b.Board) (int, int, bool) { func (p *ComputerPlayer) MakeMove(board *b.Board) (int, int, bool) {
fmt.Printf("%s (Computer) making move... ", p.GetSymbol()) fmt.Printf("%s (Computer) making move... ", p.GetSymbol())

View File

@@ -1,8 +1,8 @@
package game package player
import b "tic-tac-toe/board" import b "tic-tac-toe/board"
// IPlayer представляет интерфейс для любого игрока (человека или компьютера) // Интерфейс для любого игрока, будь то человек или компьютер
type IPlayer interface { type IPlayer interface {
// Получение символа игрока (X или O) // Получение символа игрока (X или O)
GetSymbol() string GetSymbol() string

View File

@@ -1,4 +1,4 @@
package game package player
import ( import (
"bufio" "bufio"
@@ -8,18 +8,20 @@ import (
b "tic-tac-toe/board" b "tic-tac-toe/board"
) )
// HumanPlayer представляет игрока-человека // Структура для представления игрока-человека
type HumanPlayer struct { type HumanPlayer struct {
Figure b.BoardField `json:"figure"` Figure b.BoardField `json:"figure"`
Reader *bufio.Reader `json:"-"` Reader *bufio.Reader `json:"-"`
} }
// NewHumanPlayer создает нового игрока-человека func NewHumanPlayer(
func NewHumanPlayer(figure b.BoardField, reader *bufio.Reader) *HumanPlayer { figure b.BoardField,
reader *bufio.Reader,
) *HumanPlayer {
return &HumanPlayer{Figure: figure, Reader: reader} return &HumanPlayer{Figure: figure, Reader: reader}
} }
// GetSymbol возвращает символ игрока // Возвращаем символ игрока
func (p *HumanPlayer) GetSymbol() string { func (p *HumanPlayer) GetSymbol() string {
if p.Figure == b.Cross { if p.Figure == b.Cross {
return "X" return "X"
@@ -27,7 +29,7 @@ func (p *HumanPlayer) GetSymbol() string {
return "O" return "O"
} }
// SwitchPlayer изменяет фигуру текущего игрока // Изменяем фигуру текущего игрока
func (p *HumanPlayer) SwitchPlayer() { func (p *HumanPlayer) SwitchPlayer() {
if p.Figure == b.Cross { if p.Figure == b.Cross {
p.Figure = b.Nought p.Figure = b.Nought
@@ -36,30 +38,20 @@ func (p *HumanPlayer) SwitchPlayer() {
} }
} }
// GetFigure возвращает текущую фигуру игрока // Возвращаем текущую фигуру игрока
func (p *HumanPlayer) GetFigure() b.BoardField { func (p *HumanPlayer) GetFigure() b.BoardField {
return p.Figure return p.Figure
} }
// MakeMove обрабатывает строку ввода от человека и преобразует её в координаты хода // Метод-заглушка, т.к. ввод игрока осуществляется на
// input - строка ввода в формате "1 2" // уровне пакета game, где нужно еще отрабатывать
// команду на выход и сохранение игровой сессии
func (p *HumanPlayer) MakeMove(board *b.Board) (int, int, bool) { func (p *HumanPlayer) MakeMove(board *b.Board) (int, int, bool) {
fmt.Printf( return -1, -1, false
"%s's turn. Enter row and column (e.g. 1 2): ",
p.GetSymbol(),
)
input, err := p.Reader.ReadString('\n')
input = strings.TrimSpace(input)
if err != nil {
fmt.Println("Invalid input. Please try again.")
return -1, -1, false
}
return p.ParseMove(input, board)
} }
// ParseMove обрабатывает строку ввода от человека и преобразует её в координаты хода // Обрабатываем строку ввода и
// преобразуем ее в координаты хода
func (p *HumanPlayer) ParseMove( func (p *HumanPlayer) ParseMove(
input string, input string,
board *b.Board, board *b.Board,
@@ -79,26 +71,11 @@ func (p *HumanPlayer) ParseMove(
return -1, -1, false return -1, -1, false
} }
// Преобразуем введенные координаты (начиная с 1) в индексы массива (начиная с 0) // Преобразуем введенные координаты (начиная с 1)
// в индексы массива (начиная с 0)
return row - 1, col - 1, true return row - 1, col - 1, true
} }
// IsComputer возвращает false для человека-игрока
func (p *HumanPlayer) IsComputer() bool { func (p *HumanPlayer) IsComputer() bool {
return false return false
} }
// Для обратной совместимости
type Player HumanPlayer
func NewPlayer() *Player {
return (*Player)(NewHumanPlayer(b.Cross, nil))
}
func (p *Player) SwitchPlayer() {
(*HumanPlayer)(p).SwitchPlayer()
}
func (p *Player) GetSymbol() string {
return (*HumanPlayer)(p).GetSymbol()
}

View File

@@ -1 +0,0 @@
{"board":{"board":[[1,2,0],[0,1,0],[0,2,0]],"size":3},"player_figure":1,"state":0,"mode":1,"is_current_first":true}