package chess import ( "log" "mchess_server/api" "mchess_server/types" "time" "github.com/google/uuid" ) type Game struct { id uuid.UUID board Board players []*Player currentTurnPlayer *Player gameState int } const ( PlayerToMove = iota CheckMove CheckPlayerChange ) func NewGame() *Game { var game = Game{ id: uuid.New(), board: newBoard(), gameState: PlayerToMove, } game.currentTurnPlayer = game.GetPlayer1() 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) Prepare() { ok := game.waitForWebsocketConnections() if !ok { return } err := game.notifyPlayersAboutGameStart() if err != nil { return } } func (game *Game) Handle() { defer game.killGame() var receivedMove types.Move for { switch game.gameState { case PlayerToMove: log.Println("with player ", game.currentTurnPlayer, " to move") receivedMove, err := game.currentTurnPlayer.ReadMove() if err != nil { log.Println("Error while reading message:", err) return } log.Println("Player ", game.currentTurnPlayer, " moved:\n", receivedMove) game.gameState = CheckMove case CheckMove: valid, ruleViolation := game.board.CheckAndPlay(receivedMove) if valid { game.gameState = CheckPlayerChange } else { invalidMoveMessage, err := api.GetInvalidMoveMessage(receivedMove, ruleViolation.String()) if err != nil { log.Println("Error marshalling 'colorDetermined' message for player 1", err) return } game.currentTurnPlayer.writeMessage(invalidMoveMessage) game.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 } game.gameState = PlayerToMove } log.Println("GameState = ", game.gameState) } } 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().SendMoveAndPosition(move, game.board.PGN()) if err != nil { return err } err = game.GetPlayer2().SendMoveAndPosition(move, game.board.PGN()) if err != nil { return err } return nil }