mchess-server/chess/game.go
2023-06-25 16:11:29 +02:00

171 lines
3.5 KiB
Go

package chess
import (
"mchess_server/api"
"mchess_server/types"
"log"
"time"
"github.com/google/uuid"
)
type Game struct {
id uuid.UUID
board Board
players []*Player
currentTurnPlayer *Player
}
const (
PlayerToMove = iota
CheckMove
CheckPlayerChange
)
func NewGame() *Game {
var game Game = Game{
id: uuid.New(),
board: make(map[types.Coordinate]Piece),
}
game.board.Init()
return &game
}
func (game Game) GetPlayers() []*Player {
return game.players
}
func (game Game) GetPlayer1() *Player {
return game.players[0]
}
func (game Game) GetPlayer2() *Player {
return game.players[1]
}
func (game *Game) Handle() {
defer game.killGame()
ok := game.waitForWebsocketConnections()
if !ok {
return
}
err := game.notifyPlayersAboutGameStart()
if err != nil {
return
}
gameState := PlayerToMove
game.currentTurnPlayer = game.GetPlayer1()
var receivedMove types.Move
for {
switch gameState {
case PlayerToMove:
receivedMove, err = game.currentTurnPlayer.ReadMove()
if err != nil {
log.Println("Error while reading message:", err)
return
}
log.Println("Player ", game.currentTurnPlayer, " moved:\n", receivedMove)
gameState = CheckMove
case CheckMove:
valid, reason := game.board.CheckMove(receivedMove)
if valid {
gameState = CheckPlayerChange
} else {
log.Println("invalid move because " + reason)
invalidMoveMessage, err := api.GetInvalidMoveMessage(receivedMove, reason)
if err != nil {
log.Println("Error marshalling 'colorDetermined' message for player 1", err)
return
}
game.currentTurnPlayer.writeMessage(invalidMoveMessage)
gameState = PlayerToMove
}
case CheckPlayerChange:
if game.currentTurnPlayer.Uuid == game.players[0].Uuid {
game.currentTurnPlayer = game.players[1]
} else {
game.currentTurnPlayer = game.players[0]
}
err = game.broadcastMove(receivedMove)
if err != nil {
log.Println("Error broadcasting move ", err)
return
}
gameState = PlayerToMove
}
log.Println("GameState = ", gameState)
if gameState == PlayerToMove {
log.Println("with player ", game.currentTurnPlayer, " to move")
}
}
}
func (game *Game) AddPlayersToGame(player *Player) {
game.players = append(game.players, player)
}
func (game *Game) killGame() {
log.Println("Game should be killed")
}
func (game *Game) waitForWebsocketConnections() bool {
timer := time.NewTimer(5 * time.Second)
numberOfConnections := 0
waitingForPlayers := make(chan bool)
go game.GetPlayer1().WaitForWebsocketConnection(waitingForPlayers)
go game.GetPlayer2().WaitForWebsocketConnection(waitingForPlayers)
for numberOfConnections < 2 {
select {
case <-waitingForPlayers:
numberOfConnections++
case <-timer.C:
return false
}
}
return true
}
func (game Game) notifyPlayersAboutGameStart() error {
colorDeterminedPlayer1, err := api.GetColorDeterminedMessage(types.White)
if err != nil {
log.Println("Error marshalling 'colorDetermined' message for player 1", err)
return err
}
colorDeterminedPlayer2, err := api.GetColorDeterminedMessage(types.Black)
if err != nil {
log.Println("Error marshalling 'colorDetermined' message for player 2", err)
return err
}
game.GetPlayer1().writeMessage(colorDeterminedPlayer1)
game.GetPlayer2().writeMessage(colorDeterminedPlayer2)
return nil
}
func (game Game) broadcastMove(move types.Move) error {
err := game.GetPlayer1().SendMove(move)
if err != nil {
return err
}
err = game.GetPlayer2().SendMove(move)
if err != nil {
return err
}
return nil
}