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_v8/client/menu.go
Stanislav Chernyshev 1c2614a78d fix game
2025-06-21 13:28:09 +03:00

159 lines
3.9 KiB
Go

package client
import (
"bufio"
"encoding/json"
"fmt"
"log"
"os"
"strconv"
"strings"
"tic-tac-toe/network"
"time"
)
func (c *Client) menu() {
reader := bufio.NewReader(os.Stdin)
encoder := json.NewEncoder(c.conn)
fmt.Print("Enter your nickname: ")
input, _ := reader.ReadString('\n')
input = strings.TrimSpace(input)
c.playerName = input
var msg network.Message
msg.Cmd = network.CmdNickname
payloadData := network.NicknameRequest{Nickname: c.playerName}
jsonPayload, err := json.Marshal(payloadData)
if err != nil {
log.Printf("Error marshalling payload for command %s: %v", msg.Cmd, err)
return
}
msg.Payload = jsonPayload
if err := encoder.Encode(msg); err != nil {
log.Printf("Failed to send message to server: %v. Disconnecting.", err)
return // Exit if we can't send to server
}
for {
switch c.getState() {
case waitNickNameConfirm:
time.Sleep(100 * time.Millisecond)
continue
case mainMenu:
c.mainMenu(reader, encoder)
case playerMove:
c.playing(reader, encoder)
case opponentMove:
// Just wait silently for opponent's move
time.Sleep(1000 * time.Millisecond)
continue
case endGame:
fmt.Println("\nGame has ended. Restarting in 10 seconds...")
time.Sleep(10 * time.Second)
continue
case waitResponseFromServer:
time.Sleep(100 * time.Millisecond)
continue
case waitingOpponentInRoom:
// Rate-limit messages to once every 3 seconds
now := time.Now()
if now.Sub(c.lastMsgTime) > 3*time.Second {
c.lastMsgTime = now
fmt.Println("\nWaiting for opponent to join...")
fmt.Println("Press 'q' and Enter to return to main menu")
fmt.Print("> ")
}
// Poll for input every cycle but don't block
var buffer [1]byte
n, _ := os.Stdin.Read(buffer[:])
if n > 0 && (buffer[0] == 'q' || buffer[0] == 'Q') {
fmt.Println("Leaving room...")
var msg network.Message
msg.Cmd = network.CmdLeaveRoomRequest
payload := network.LeaveRoomRequest{
RoomName: c.roomName,
PlayerName: c.playerName,
}
jsonPayload, _ := json.Marshal(payload)
msg.Payload = jsonPayload
encoder.Encode(msg)
c.setState(mainMenu)
continue
}
// Short sleep to avoid CPU spinning
time.Sleep(100 * time.Millisecond)
continue
}
}
}
func (c *Client) mainMenu(reader *bufio.Reader, encoder *json.Encoder) {
var msg network.Message
fmt.Println("Enter command:")
fmt.Println("1 - Get room list")
fmt.Println("2 - Join room")
fmt.Println("3 - Get finished games")
fmt.Println("4 - Get finished game by id")
fmt.Println("5 - Exit")
fmt.Print("> ")
input, _ := reader.ReadString('\n')
input = strings.TrimSpace(input)
command, err := strconv.Atoi(input)
if err != nil {
fmt.Println("Invalid command.")
return
}
switch command {
case 1:
msg.Cmd = network.CmdListRoomsRequest
encoder.Encode(msg)
c.setState(waitResponseFromServer)
case 2:
fmt.Print("Enter room name: ")
input, _ := reader.ReadString('\n')
input = strings.TrimSpace(input)
c.roomName = input
msg.Cmd = network.CmdJoinRoomRequest
payload := network.JoinRoomRequest{
RoomName: c.roomName,
PlayerName: c.playerName,
}
jsonPayload, _ := json.Marshal(payload)
msg.Payload = jsonPayload
encoder.Encode(msg)
c.setState(waitResponseFromServer)
case 3:
msg.Cmd = network.CmdFinishedGamesRequest
encoder.Encode(msg)
c.setState(waitResponseFromServer)
case 4:
fmt.Print("Enter game id: ")
input, _ := reader.ReadString('\n')
input = strings.TrimSpace(input)
gameId, err := strconv.Atoi(input)
if err != nil {
fmt.Println("Invalid game id.")
return
}
msg.Cmd = network.CmdFinishedGameByIdRequest
payload := network.GetFinishedGameByIdRequest{GameID: gameId}
jsonPayload, _ := json.Marshal(payload)
msg.Payload = jsonPayload
encoder.Encode(msg)
c.setState(waitResponseFromServer)
case 5:
os.Exit(0)
default:
fmt.Println("Unknown command.")
return
}
}