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

145 lines
4.9 KiB
Go
Raw Normal View History

2025-06-21 13:28:09 +03:00
package client
import (
"encoding/json"
"fmt"
"log"
"net"
"sync"
"time"
b "tic-tac-toe/board"
"tic-tac-toe/network"
)
2025-06-23 17:12:57 +03:00
// Объявление структуры клиента
2025-06-21 13:28:09 +03:00
type Client struct {
2025-06-23 17:12:57 +03:00
// подключение к серверу
conn net.Conn
// игровое поле
board *b.Board
// фигура игрока
mySymbol b.BoardField
// фигура игрока, ход которой сейчас
2025-06-21 13:28:09 +03:00
currentPlayer b.BoardField
2025-06-23 17:12:57 +03:00
// никнейм игрока
playerName string
// имя комнаты
roomName string
// текущее состояние клиента
state State
// мьютекс для защиты доступа к данным
mutex sync.RWMutex
// время последнего сообщения
lastMsgTime time.Time
2025-06-21 13:28:09 +03:00
}
2025-06-23 17:12:57 +03:00
// Констукторная функция для создания клиента
2025-06-21 13:28:09 +03:00
func NewClient(addr string) (*Client, error) {
conn, err := net.Dial("tcp", addr)
if err != nil {
return nil, err
}
return &Client{
2025-06-23 17:12:57 +03:00
// подключение к серверу
conn: conn,
// начальное состояние клиента
state: waitNickNameConfirm,
// mySymbol будет установлен при подключении к комнате
mySymbol: b.Empty,
2025-06-21 13:28:09 +03:00
}, nil
}
2025-06-23 17:12:57 +03:00
// Устанавливаем никнейм игрока
2025-06-21 13:28:09 +03:00
func (c *Client) setNickname(nickname string) {
c.playerName = nickname
}
2025-06-23 17:12:57 +03:00
// Получаем текущее состояние клиента
2025-06-21 13:28:09 +03:00
func (c *Client) getState() State {
2025-06-23 17:12:57 +03:00
c.mutex.RLock() // защищаем доступ к данным
2025-06-21 13:28:09 +03:00
defer c.mutex.RUnlock()
return c.state
}
2025-06-23 17:12:57 +03:00
// Устанавливаем текущее состояние клиента
2025-06-21 13:28:09 +03:00
func (c *Client) setState(state State) {
2025-06-23 17:12:57 +03:00
c.mutex.Lock() // защищаем доступ к данным
2025-06-21 13:28:09 +03:00
defer c.mutex.Unlock()
2025-06-23 17:12:57 +03:00
// Если переходим в состояние opponentMove
2025-06-21 13:28:09 +03:00
if state == opponentMove && c.state != opponentMove {
fmt.Println("\nWaiting for opponent's move...")
2025-06-23 17:12:57 +03:00
} else if state == waitingOpponentInRoom &&
c.state != waitingOpponentInRoom {
// Если переходим в состояние waitingOpponentInRoom
2025-06-21 13:28:09 +03:00
fmt.Println("\nWaiting for opponent to join...")
}
2025-06-23 17:12:57 +03:00
c.state = state // устанавливаем новое состояние
2025-06-21 13:28:09 +03:00
}
2025-06-23 17:12:57 +03:00
// Запускаем клиента
2025-06-21 13:28:09 +03:00
func (c *Client) Start() {
defer c.conn.Close()
fmt.Println("Connected to server. ")
2025-06-23 17:12:57 +03:00
// Запускаем горутину для чтения сообщений от сервера
2025-06-21 13:28:09 +03:00
go c.readFromServer()
2025-06-23 17:12:57 +03:00
// Запускаем меню клиента для взаимодействия с пользователем
2025-06-21 13:28:09 +03:00
c.menu()
}
2025-06-23 17:12:57 +03:00
// Читаем сообщения от сервера
2025-06-21 13:28:09 +03:00
func (c *Client) readFromServer() {
2025-06-23 17:12:57 +03:00
decoder := json.NewDecoder(c.conn) // Создаем декодер
for { // Бесконечный цикл
2025-06-21 13:28:09 +03:00
var msg network.Message
if err := decoder.Decode(&msg); err != nil {
log.Printf("Disconnected from server: %v", err)
2025-06-23 17:12:57 +03:00
return // если соединение потеряно, то выходим из горутины
2025-06-21 13:28:09 +03:00
}
switch msg.Cmd {
2025-06-23 17:12:57 +03:00
// Обрабатываем ответ на запрос на присоединение к комнате
2025-06-21 13:28:09 +03:00
case network.CmdRoomJoinResponse:
c.handleRoomJoinResponse(msg.Payload)
2025-06-23 17:12:57 +03:00
// Обрабатываем сообщение об инициализацию игры
2025-06-21 13:28:09 +03:00
case network.CmdInitGame:
c.handleInitGame(msg.Payload)
2025-06-23 17:12:57 +03:00
// Обрабатываем сообщение об обновлении состояния игры
2025-06-21 13:28:09 +03:00
case network.CmdUpdateState:
c.handleUpdateState(msg.Payload)
2025-06-23 17:12:57 +03:00
// Обрабатываем сообщение об окончании игры
2025-06-21 13:28:09 +03:00
case network.CmdEndGame:
c.handleEndGame(msg.Payload)
2025-06-23 17:12:57 +03:00
// Обрабатываем сообщение об ошибке
2025-06-21 13:28:09 +03:00
case network.CmdError:
c.handleError(msg.Payload)
2025-06-23 17:12:57 +03:00
// Обрабатываем сообщение о списке комнат
2025-06-21 13:28:09 +03:00
case network.CmdRoomListResponse:
c.handleRoomListResponse(msg.Payload)
2025-06-23 17:12:57 +03:00
// Обрабатываем сообщение о подтверждении никнейма
2025-06-21 13:28:09 +03:00
case network.CmdNickNameResponse:
c.handleNickNameResponse(msg.Payload)
2025-06-23 17:12:57 +03:00
// Обрабатываем сообщение об отключении оппонента
2025-06-21 13:28:09 +03:00
case network.CmdOpponentLeft:
c.handleOpponentLeft(msg.Payload)
2025-06-23 17:12:57 +03:00
// Обрабатываем сообщение о списке завершенных игр
2025-06-21 13:28:09 +03:00
case network.CmdFinishedGamesResponse:
c.handleFinishedGamesResponse(msg.Payload)
2025-06-23 17:12:57 +03:00
// Обрабатываем сообщение с данными по
// запрошенной завершенной игре
2025-06-21 13:28:09 +03:00
case network.CmdFinishedGameResponse:
c.handleFinishedGameResponse(msg.Payload)
2025-06-23 17:12:57 +03:00
default: // Если пришло неизвестное сообщение
2025-06-21 13:28:09 +03:00
log.Printf(
"Received unhandled message type '%s' "+
"from server. Payload: %s\n> ",
msg.Cmd, string(msg.Payload),
)
}
}
}