353 lines
7.8 KiB
Go
353 lines
7.8 KiB
Go
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)
|
|
}
|
|
}
|