package main import ( "flag" "log" "net/http" "github.com/google/uuid" "github.com/gorilla/websocket" ) var games = make(map[string]*Game, 0) var players = make(map[string]*Player, 0) var addr = flag.String("addr", ":8000", "http service address") func (p *Player) send(messageType string, data map[string]interface{}) { dataObject := DataObject{ Type: messageType, Data: data, } p.Connection.WriteJSON(dataObject) } func (g *Game) send(messageType string, data map[string]interface{}) { for _, player := range g.Players { log.Println("sending message", player) player.send(messageType, data) } } func (g *Game) GetNextPlayer() *Player { index := g.CurrentPlayerIndex if g.DirectionClockwise { index++ } else { index-- } if index < 0 { index += len(g.Players) } else if index >= len(g.Players) { index -= len(g.Players) } return g.Players[index] } func (g *Game) nextTurn(block bool) { count := 1 if block { count++ } if g.DirectionClockwise { g.CurrentPlayerIndex += count } else { g.CurrentPlayerIndex -= count } if g.CurrentPlayerIndex < 0 { g.CurrentPlayerIndex += len(g.Players) } else if g.CurrentPlayerIndex >= len(g.Players) { g.CurrentPlayerIndex -= len(g.Players) } g.send("game.nextTurn", map[string]interface{}{ "playerID": g.Players[g.CurrentPlayerIndex].ID, }) } func gameInitHandler(player *Player, data map[string]interface{}) { game := Game{ //ID: uuid.New().String(), ID: "1234", MaxPlayers: 4, DirectionClockwise: true, AvailableCards: GetDefaultDeck(), } game.Players = append(game.Players, player) game.PlayingStack.Cards = append(game.PlayingStack.Cards, GetRandomCard(game.AvailableCards)) game.CurrentPlayerIndex = 0 games[game.ID] = &game InitPlayer(&game, player) player.send("game.init.result", map[string]interface{}{ "gameID": game.ID, "hand": player.Hand, "playerID": player.ID, "activePlayerID": game.Players[game.CurrentPlayerIndex].ID, "playingStack": game.PlayingStack.Cards, }) } func joinGameHandler(player *Player, data map[string]interface{}) { gameID, ok := data["gameID"] if !ok { log.Println("not found game id") return } game, ok := games[gameID.(string)] if !ok { log.Println("game not found") return } InitPlayer(game, player) game.send("game.joined", map[string]interface{}{ "playerID": player.ID, "playerName": player.Name, "cardCount": len(player.Hand), }) players := make([]struct { PlayerID string `json:"playerID"` PlayerName string `json:"playerName"` CardCount int `json:"cardCount"` }, len(game.Players)) for index, p := range game.Players { players[index] = struct { PlayerID string `json:"playerID"` PlayerName string `json:"playerName"` CardCount int `json:"cardCount"` }{ PlayerID: p.ID, PlayerName: p.Name, CardCount: len(p.Hand), } } game.Players = append(game.Players, player) log.Println(game) player.send("game.join.result", map[string]interface{}{ "hand": player.Hand, "playerID": player.ID, "activePlayerID": game.Players[game.CurrentPlayerIndex].ID, "players": players, "playingStack": game.PlayingStack.Cards, }) } func playCardHandler(player *Player, data map[string]interface{}) { log.Println("card") if player.Game == nil { return } log.Println("color") if player.Game.Players[player.Game.CurrentPlayerIndex].ID != player.ID { return } if player.Game.ChoosingColor { return } color, ok := data["color"] if !ok { return } value, ok := data["value"] if !ok { return } card, ok := FindCard(player.Game.AvailableCards, color.(string), value.(string)) if !ok { return } handIndex := FindOnHand(player, card) if handIndex == -1 { return } topCard := player.Game.PlayingStack.Cards[len(player.Game.PlayingStack.Cards)-1] log.Println(topCard) if card.Color != "BLACK" && topCard.Value != card.Value && topCard.Color != card.Color { return } player.Game.PlayingStack.Cards = append(player.Game.PlayingStack.Cards, card) player.Hand = RemoveFromHand(player, handIndex) if card.Value == "RETURN" { player.Game.DirectionClockwise = !player.Game.DirectionClockwise } if card.Value == "DRAW2" { DrawNextPlayer(player.Game, 2) } if card.Value == "DRAW4" { DrawNextPlayer(player.Game, 4) } chooseColor := card.Value == "CHOOSE" || card.Value == "DRAW4" if !chooseColor { block := card.Value == "BLOCK" || card.Value == "DRAW2" player.Game.nextTurn(block) } log.Println(card) player.Game.send("card.played", map[string]interface{}{ "playerID": player.ID, "card": &card, }) player.send("player.hand", map[string]interface{}{ "cards": player.Hand, }) if chooseColor { player.Game.ChoosingColor = true player.send("color.choose", map[string]interface{}{}) } if !chooseColor { player.Game.send("turn.completed", map[string]interface{}{ "activePlayerID": player.Game.Players[player.Game.CurrentPlayerIndex].ID, "directionClockwise": player.Game.DirectionClockwise, }) } } func chooseColorHandler(player *Player, data map[string]interface{}) { if player.Game == nil { return } if player.Game.Players[player.Game.CurrentPlayerIndex].ID != player.ID { return } if !player.Game.ChoosingColor { return } color := data["color"] if color != "GREEN" && color != "BLUE" && color != "RED" && color != "YELLOW" { return } topCard := player.Game.PlayingStack.Cards[len(player.Game.PlayingStack.Cards)-1] topCard.Color = color.(string) player.Game.ChoosingColor = false player.Game.send("card.color", map[string]interface{}{ "color": color, }) player.Game.nextTurn(topCard.Value == "DRAW4") player.Game.send("turn.completed", map[string]interface{}{ "activePlayerID": player.Game.Players[player.Game.CurrentPlayerIndex].ID, "directionClockwise": player.Game.DirectionClockwise, }) } func drawCardHandler(player *Player, data map[string]interface{}) { if player.Game == nil { return } if player.Game.Players[player.Game.CurrentPlayerIndex].ID != player.ID { return } player.Hand = append(player.Hand, GetRandomCard(player.Game.AvailableCards)) player.Game.nextTurn(false) log.Println(player.Hand) player.Game.send("card.drawn", map[string]interface{}{ "playerID": player.ID, "count": 1, }) player.send("player.hand", map[string]interface{}{ "cards": player.Hand, }) player.Game.send("turn.completed", map[string]interface{}{ "activePlayerID": player.Game.Players[player.Game.CurrentPlayerIndex].ID, "directionClockwise": player.Game.DirectionClockwise, }) } func playerLogoutHandler(player *Player) { delete(players, player.ID) } func ws(w http.ResponseWriter, r *http.Request) { upgrader := websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true }, } conn, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Println(err) return } player := Player{ ID: uuid.New().String(), Name: "Test Player", Connection: conn, } players[player.ID] = &player for { var data DataObject err := conn.ReadJSON(&data) if err != nil { if websocket.IsCloseError(err, 1001) { log.Println("closed connection") playerLogoutHandler(&player) } log.Printf("Failed to read message %v", err) conn.Close() return } log.Println(data) switch data.Type { case "game.init": gameInitHandler(&player, data.Data) log.Println("Initializing game") case "game.join": joinGameHandler(&player, data.Data) case "card.play": playCardHandler(&player, data.Data) case "card.color": chooseColorHandler(&player, data.Data) case "card.draw": drawCardHandler(&player, data.Data) } } } func main() { flag.Parse() http.HandleFunc("/", ws) log.Println("listening") err := http.ListenAndServe(*addr, nil) if err != nil { log.Fatal("listen and serve", err) } }