mirror of
https://github.com/MADTeacher/go_basics.git
synced 2025-11-23 21:34:47 +02:00
добавлены более подробные комментарии
This commit is contained in:
@@ -14,24 +14,15 @@ import (
|
|||||||
|
|
||||||
// Объявление структуры клиента
|
// Объявление структуры клиента
|
||||||
type Client struct {
|
type Client struct {
|
||||||
// подключение к серверу
|
conn net.Conn // подключение к серверу
|
||||||
conn net.Conn
|
board *b.Board // игровое поле
|
||||||
// игровое поле
|
mySymbol b.BoardField // фигура игрока
|
||||||
board *b.Board
|
currentPlayer b.BoardField // фигура игрока, чей сейчас ход
|
||||||
// фигура игрока
|
playerName string // имя комнаты
|
||||||
mySymbol b.BoardField
|
roomName string // имя комнаты
|
||||||
// фигура игрока, ход которой сейчас
|
state State // текущее состояние клиента
|
||||||
currentPlayer b.BoardField
|
mutex sync.RWMutex // мьютекс для защиты доступа к данным
|
||||||
// никнейм игрока
|
lastMsgTime time.Time // время последнего сообщения
|
||||||
playerName string
|
|
||||||
// имя комнаты
|
|
||||||
roomName string
|
|
||||||
// текущее состояние клиента
|
|
||||||
state State
|
|
||||||
// мьютекс для защиты доступа к данным
|
|
||||||
mutex sync.RWMutex
|
|
||||||
// время последнего сообщения
|
|
||||||
lastMsgTime time.Time
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Констукторная функция для создания клиента
|
// Констукторная функция для создания клиента
|
||||||
@@ -51,7 +42,7 @@ func NewClient(addr string) (*Client, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Устанавливаем никнейм игрока
|
// Устанавливаем никнейма игрока
|
||||||
func (c *Client) setNickname(nickname string) {
|
func (c *Client) setNickname(nickname string) {
|
||||||
c.playerName = nickname
|
c.playerName = nickname
|
||||||
}
|
}
|
||||||
@@ -88,7 +79,7 @@ func (c *Client) Start() {
|
|||||||
// Запускаем горутину для чтения сообщений от сервера
|
// Запускаем горутину для чтения сообщений от сервера
|
||||||
go c.readFromServer()
|
go c.readFromServer()
|
||||||
// Запускаем меню клиента для взаимодействия с пользователем
|
// Запускаем меню клиента для взаимодействия с пользователем
|
||||||
c.menu()
|
c.handleUserFlow()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Читаем сообщения от сервера
|
// Читаем сообщения от сервера
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Метод для взаимодействия с пользователем
|
// Метод управления всем пользовательским потоком
|
||||||
func (c *Client) menu() {
|
func (c *Client) handleUserFlow() {
|
||||||
// Создаем буфер для чтения ввода
|
// Создаем буфер для чтения ввода
|
||||||
reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
// Создаем энкодер для отправки сообщений
|
// Создаем энкодер для отправки сообщений
|
||||||
|
|||||||
@@ -5,106 +5,20 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
b "tic-tac-toe/board" // Added for g.GameMode
|
b "tic-tac-toe/board"
|
||||||
"tic-tac-toe/network"
|
"tic-tac-toe/network"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Обрабатываем ответ на запрос на присоединение к комнате
|
// Обрабатываем ответ сервера, содержащий никнейм игрока
|
||||||
func (c *Client) handleRoomJoinResponse(payload json.RawMessage) {
|
func (c *Client) handleNickNameResponse(payload json.RawMessage) {
|
||||||
var res network.RoomJoinResponse // Десериализуем ответ
|
var res network.NickNameResponse // Десериализуем ответ
|
||||||
if err := json.Unmarshal(payload, &res); err == nil {
|
if err := json.Unmarshal(payload, &res); err == nil {
|
||||||
c.mySymbol = res.PlayerSymbol // Устанавливаем фигуру игрока
|
fmt.Printf("\nWelcome, %s!\n> ", res.Nickname)
|
||||||
c.roomName = res.RoomName // Устанавливаем имя комнаты
|
c.setNickname(res.Nickname) // Устанавливаем никнейм игрока
|
||||||
if res.Board.Size > 0 { // Проверяем размер поля
|
c.setState(mainMenu) // Переходим в главное меню
|
||||||
c.board = &res.Board // Устанавливаем игровое поле
|
|
||||||
fmt.Printf(
|
|
||||||
"\nSuccessfully joined room '%s' as %s.\n",
|
|
||||||
res.RoomName, res.PlayerSymbol,
|
|
||||||
)
|
|
||||||
c.board.PrintBoard()
|
|
||||||
} else {
|
|
||||||
fmt.Printf(
|
|
||||||
"\nSuccessfully joined room '%s' as %s. "+
|
|
||||||
"Waiting for game to start...\n",
|
|
||||||
res.RoomName, res.PlayerSymbol,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Error unmarshalling RoomJoinResponse: %v", err)
|
log.Printf("Error unmarshalling NickNameResponse: %v", err)
|
||||||
}
|
}
|
||||||
// Устанавливаем состояние клиента
|
|
||||||
c.setState(waitingOpponentInRoom)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Обрабатываем ответ на запрос на инициализацию игры
|
|
||||||
func (c *Client) handleInitGame(payload json.RawMessage) {
|
|
||||||
var res network.InitGameResponse // Десериализуем ответ
|
|
||||||
if err := json.Unmarshal(payload, &res); err == nil {
|
|
||||||
c.board = &res.Board // Устанавливаем игровое поле
|
|
||||||
c.currentPlayer = res.CurrentPlayer // Устанавливаем фигуру игрока
|
|
||||||
fmt.Println("\n--- Game Started ---")
|
|
||||||
c.board.PrintBoard() // Выводим игровое поле
|
|
||||||
c.printTurnInfo() // Выводим информацию о ходе игрока
|
|
||||||
// Устанавливаем состояние клиента
|
|
||||||
if res.CurrentPlayer == c.mySymbol {
|
|
||||||
c.setState(playerMove)
|
|
||||||
} else {
|
|
||||||
c.setState(opponentMove)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.Printf("Error unmarshalling InitGameResponse: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Обрабатываем сообщение об обновлении состояния игры
|
|
||||||
func (c *Client) handleUpdateState(payload json.RawMessage) {
|
|
||||||
var res network.GameStateUpdate // Десериализуем ответ
|
|
||||||
if err := json.Unmarshal(payload, &res); err == nil {
|
|
||||||
c.board = &res.Board // Устанавливаем игровое поле
|
|
||||||
c.currentPlayer = res.CurrentPlayer // Устанавливаем фигуру игрока
|
|
||||||
fmt.Println("\n--- Game State Update ---")
|
|
||||||
c.board.PrintBoard() // Выводим игровое поле
|
|
||||||
c.printTurnInfo() // Выводим информацию о ходе игрока
|
|
||||||
// Устанавливаем состояние клиента
|
|
||||||
if res.CurrentPlayer == c.mySymbol {
|
|
||||||
c.setState(playerMove)
|
|
||||||
} else {
|
|
||||||
c.setState(opponentMove)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.Printf("Error unmarshalling GameStateUpdate: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Обрабатываем сообщение об окончании игры
|
|
||||||
func (c *Client) handleEndGame(payload json.RawMessage) {
|
|
||||||
var res network.EndGameResponse // Десериализуем ответ
|
|
||||||
if err := json.Unmarshal(payload, &res); err == nil {
|
|
||||||
c.board = &res.Board // Устанавливаем игровое поле
|
|
||||||
fmt.Println("\n--- Game Over ---")
|
|
||||||
c.board.PrintBoard() // Выводим игровое поле
|
|
||||||
// Выводим информацию о победителе
|
|
||||||
if res.CurrentPlayer == b.Empty {
|
|
||||||
fmt.Println("It's a Draw!")
|
|
||||||
} else {
|
|
||||||
fmt.Printf("Player %s wins!\n", res.CurrentPlayer)
|
|
||||||
}
|
|
||||||
c.setState(endGame) // Устанавливаем состояние клиента
|
|
||||||
fmt.Print("> ")
|
|
||||||
} else {
|
|
||||||
log.Printf("Error unmarshalling EndGameResponse: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Обрабатываем сообщение об ошибке
|
|
||||||
func (c *Client) handleError(payload json.RawMessage) {
|
|
||||||
var errPayload network.ErrorResponse // Десериализуем ответ
|
|
||||||
if err := json.Unmarshal(payload, &errPayload); err == nil {
|
|
||||||
fmt.Printf("\nServer Error: %s\n> ", errPayload.Message)
|
|
||||||
} else {
|
|
||||||
log.Printf("Error unmarshalling ErrorResponse: %v", err)
|
|
||||||
}
|
|
||||||
c.setState(mainMenu)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Обрабатываем сообщение о списке комнат
|
// Обрабатываем сообщение о списке комнат
|
||||||
@@ -130,30 +44,33 @@ func (c *Client) handleRoomListResponse(payload json.RawMessage) {
|
|||||||
} else {
|
} else {
|
||||||
log.Printf("Error unmarshalling RoomListResponse: %v", err)
|
log.Printf("Error unmarshalling RoomListResponse: %v", err)
|
||||||
}
|
}
|
||||||
c.setState(mainMenu)
|
c.setState(mainMenu) // Переходим в главное меню
|
||||||
}
|
}
|
||||||
|
|
||||||
// Обрабатываем ответ на запрос на присоединение к комнате
|
// Обрабатываем ответ на запрос на присоединение к комнате
|
||||||
func (c *Client) handleNickNameResponse(payload json.RawMessage) {
|
func (c *Client) handleRoomJoinResponse(payload json.RawMessage) {
|
||||||
var res network.NickNameResponse // Десериализуем ответ
|
var res network.RoomJoinResponse // Десериализуем ответ
|
||||||
if err := json.Unmarshal(payload, &res); err == nil {
|
if err := json.Unmarshal(payload, &res); err == nil {
|
||||||
fmt.Printf("\nWelcome, %s!\n> ", res.Nickname)
|
c.mySymbol = res.PlayerSymbol // Устанавливаем фигуру игрока
|
||||||
c.setNickname(res.Nickname) // Устанавливаем никнейм игрока
|
c.roomName = res.RoomName // Устанавливаем имя комнаты
|
||||||
c.setState(mainMenu) // Устанавливаем состояние клиента
|
if res.Board.Size > 0 { // Проверяем размер поля
|
||||||
|
c.board = &res.Board // Устанавливаем игровое поле
|
||||||
|
fmt.Printf(
|
||||||
|
"\nSuccessfully joined room '%s' as %s.\n",
|
||||||
|
res.RoomName, res.PlayerSymbol,
|
||||||
|
)
|
||||||
|
c.board.PrintBoard()
|
||||||
|
} else {
|
||||||
|
fmt.Printf(
|
||||||
|
"\nSuccessfully joined room '%s' as %s. "+
|
||||||
|
"Waiting for game to start...\n",
|
||||||
|
res.RoomName, res.PlayerSymbol,
|
||||||
|
)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Error unmarshalling NickNameResponse: %v", err)
|
log.Printf("Error unmarshalling RoomJoinResponse: %v", err)
|
||||||
}
|
}
|
||||||
}
|
// переходим в состояние ожидания присоединения оппонента к комнате
|
||||||
|
|
||||||
// Обрабатываем сообщение об отключении оппонента
|
|
||||||
func (c *Client) handleOpponentLeft(payload json.RawMessage) {
|
|
||||||
var res network.OpponentLeft // Десериализуем ответ
|
|
||||||
if err := json.Unmarshal(payload, &res); err == nil {
|
|
||||||
fmt.Printf("\nPlayer '%s' has left the game.\n> ", res.Nickname)
|
|
||||||
} else {
|
|
||||||
log.Printf("Error unmarshalling OpponentLeft: %v", err)
|
|
||||||
}
|
|
||||||
// Устанавливаем состояние клиента
|
|
||||||
c.setState(waitingOpponentInRoom)
|
c.setState(waitingOpponentInRoom)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,10 +92,12 @@ func (c *Client) handleFinishedGamesResponse(payload json.RawMessage) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Error unmarshalling FinishedGamesResponse: %v", err)
|
log.Printf(
|
||||||
|
"Error unmarshalling FinishedGamesResponse: %v",
|
||||||
|
err,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
// Устанавливаем состояние клиента
|
c.setState(mainMenu) // Переходим в главное меню
|
||||||
c.setState(mainMenu)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Обрабатываем ответ на запрос на получение данных
|
// Обрабатываем ответ на запрос на получение данных
|
||||||
@@ -197,7 +116,101 @@ func (c *Client) handleFinishedGameResponse(payload json.RawMessage) {
|
|||||||
c.board.PrintBoard()
|
c.board.PrintBoard()
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Error unmarshalling FinishedGameResponse: %v", err)
|
log.Printf(
|
||||||
|
"Error unmarshalling FinishedGameResponse: %v",
|
||||||
|
err,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
c.setState(mainMenu) // Устанавливаем состояние клиента
|
c.setState(mainMenu) // Переходим в главное меню
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обрабатываем ответ на запрос на инициализацию игры
|
||||||
|
func (c *Client) handleInitGame(payload json.RawMessage) {
|
||||||
|
var res network.InitGameResponse // Десериализуем ответ
|
||||||
|
if err := json.Unmarshal(payload, &res); err == nil {
|
||||||
|
c.board = &res.Board // Устанавливаем игровое поле
|
||||||
|
c.currentPlayer = res.CurrentPlayer // Устанавливаем фигуру игрока
|
||||||
|
fmt.Println("\n--- Game Started ---")
|
||||||
|
c.board.PrintBoard() // Выводим игровое поле
|
||||||
|
c.printTurnInfo() // Выводим информацию о ходе игрока
|
||||||
|
if res.CurrentPlayer == c.mySymbol {
|
||||||
|
// Устанавливаем состояние, что ходит игрок
|
||||||
|
c.setState(playerMove)
|
||||||
|
} else {
|
||||||
|
// Устанавливаем состояние, что ходит оппонент
|
||||||
|
c.setState(opponentMove)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Printf(
|
||||||
|
"Error unmarshalling InitGameResponse: %v",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обрабатываем сообщение об обновлении состояния игры
|
||||||
|
func (c *Client) handleUpdateState(payload json.RawMessage) {
|
||||||
|
var res network.GameStateUpdate // Десериализуем ответ
|
||||||
|
if err := json.Unmarshal(payload, &res); err == nil {
|
||||||
|
c.board = &res.Board // Устанавливаем игровое поле
|
||||||
|
c.currentPlayer = res.CurrentPlayer // Устанавливаем фигуру игрока
|
||||||
|
fmt.Println("\n--- Game State Update ---")
|
||||||
|
c.board.PrintBoard() // Выводим игровое поле
|
||||||
|
c.printTurnInfo() // Выводим информацию о ходе игрока
|
||||||
|
if res.CurrentPlayer == c.mySymbol {
|
||||||
|
// Устанавливаем состояние, что ходит игрок
|
||||||
|
c.setState(playerMove)
|
||||||
|
} else {
|
||||||
|
// Устанавливаем состояние, что ходит оппонент
|
||||||
|
c.setState(opponentMove)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Printf("Error unmarshalling GameStateUpdate: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обрабатываем сообщение об окончании игры
|
||||||
|
func (c *Client) handleEndGame(payload json.RawMessage) {
|
||||||
|
var res network.EndGameResponse // Десериализуем ответ
|
||||||
|
if err := json.Unmarshal(payload, &res); err == nil {
|
||||||
|
c.board = &res.Board // Устанавливаем игровое поле
|
||||||
|
fmt.Println("\n--- Game Over ---")
|
||||||
|
c.board.PrintBoard() // Выводим игровое поле
|
||||||
|
// Выводим информацию о победителе
|
||||||
|
if res.CurrentPlayer == b.Empty {
|
||||||
|
fmt.Println("It's a Draw!")
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Player %s wins!\n", res.CurrentPlayer)
|
||||||
|
}
|
||||||
|
c.setState(endGame) /// Переходи состояние завершения игры
|
||||||
|
fmt.Print("> ")
|
||||||
|
} else {
|
||||||
|
log.Printf("Error unmarshalling EndGameResponse: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обрабатываем сообщение об ошибке
|
||||||
|
func (c *Client) handleError(payload json.RawMessage) {
|
||||||
|
var errPayload network.ErrorResponse // Десериализуем ответ
|
||||||
|
if err := json.Unmarshal(payload, &errPayload); err == nil {
|
||||||
|
fmt.Printf("\nServer Error: %s\n> ", errPayload.Message)
|
||||||
|
} else {
|
||||||
|
log.Printf("Error unmarshalling ErrorResponse: %v", err)
|
||||||
|
}
|
||||||
|
c.setState(mainMenu) // Переходим в главное меню
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обрабатываем сообщение об отключении оппонента
|
||||||
|
func (c *Client) handleOpponentLeft(payload json.RawMessage) {
|
||||||
|
var res network.OpponentLeft // Десериализуем ответ
|
||||||
|
if err := json.Unmarshal(payload, &res); err == nil {
|
||||||
|
fmt.Printf(
|
||||||
|
"\nPlayer '%s' has left the game.\n> ",
|
||||||
|
res.Nickname,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
log.Printf("Error unmarshalling OpponentLeft: %v", err)
|
||||||
|
}
|
||||||
|
// Переходим в состояние ожидания присоединения оппонента к комнате
|
||||||
|
c.setState(waitingOpponentInRoom)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ func (c *Client) validateMove(row, col int) bool {
|
|||||||
)
|
)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// Преобразуем в 0-индексированный для доступа к полю
|
// Нормируем индекс для доступа к полю
|
||||||
if c.board.Board[row-1][col-1] != b.Empty {
|
if c.board.Board[row-1][col-1] != b.Empty {
|
||||||
fmt.Println("Invalid move. Cell is already occupied.")
|
fmt.Println("Invalid move. Cell is already occupied.")
|
||||||
return false
|
return false
|
||||||
|
|||||||
Reference in New Issue
Block a user