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:
@@ -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 {
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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:")
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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}
|
|
||||||
Reference in New Issue
Block a user