This repository has been archived on 2021-10-15. You can view files and clone it, but cannot push or open issues or pull requests.
2020-coding-projects/uno/server/main.go
2020-05-05 22:35:48 +02:00

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)
}
}