212 lines
4.6 KiB
Go
212 lines
4.6 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/gorilla/websocket"
|
|
"gitlab.com/tslocum/joker"
|
|
cribbage "gitlab.com/tslocum/joker-cribbage"
|
|
)
|
|
|
|
func connect(address string) {
|
|
setStatusText("Connecting...")
|
|
|
|
interrupt := make(chan struct{})
|
|
// TODO use interrupt
|
|
|
|
c, _, err := websocket.DefaultDialer.Dial(address, nil)
|
|
if err != nil {
|
|
log.Fatal("dial:", err)
|
|
}
|
|
defer c.Close()
|
|
|
|
done := make(chan struct{})
|
|
|
|
go handleRead(c, done)
|
|
go handleWrite(c)
|
|
|
|
setStatusText("Waiting for opponent...")
|
|
|
|
select {
|
|
case <-done:
|
|
return
|
|
case <-interrupt:
|
|
// Cleanly close the connection by sending a close message and then
|
|
// waiting (with timeout) for the server to close the connection.
|
|
err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
|
|
if err != nil {
|
|
return
|
|
}
|
|
select {
|
|
case <-done:
|
|
case <-time.After(time.Second):
|
|
}
|
|
return
|
|
}
|
|
}
|
|
|
|
func handleRead(c *websocket.Conn, done chan struct{}) {
|
|
defer close(done)
|
|
|
|
var lastPhase int
|
|
for {
|
|
messageType, message, err := c.ReadMessage()
|
|
if err != nil {
|
|
log.Fatal("read err", err)
|
|
return
|
|
}
|
|
|
|
if debug {
|
|
statusMessage(fmt.Sprintf("recv: %s\n", message))
|
|
}
|
|
|
|
if messageType == websocket.PingMessage || messageType == websocket.PongMessage {
|
|
continue
|
|
}
|
|
|
|
g := &gameState{}
|
|
err = json.Unmarshal(message, g)
|
|
if err != nil {
|
|
statusMessage(string(message))
|
|
continue
|
|
}
|
|
|
|
if g.Turn == 0 {
|
|
c := &gameCommand{}
|
|
err = json.Unmarshal(message, c)
|
|
if err != nil {
|
|
// TODO currently skipping, should show error
|
|
continue
|
|
}
|
|
|
|
if c.Command == CommandMessage {
|
|
statusMessage(fmt.Sprintf("<%s> %s", "Opponent", c.Value))
|
|
}
|
|
}
|
|
|
|
currentGameState = g
|
|
|
|
if g.Player > 0 {
|
|
playerHand := g.Hand1
|
|
oppHand := g.Hand2
|
|
if g.Player == 2 {
|
|
playerHand = g.Hand2
|
|
oppHand = g.Hand1
|
|
}
|
|
|
|
playerCrib := g.Crib
|
|
var oppCrib joker.Cards
|
|
if g.Dealer != g.Player {
|
|
playerCrib = joker.Cards{}
|
|
oppCrib = g.Crib
|
|
}
|
|
|
|
if currentGameState.Status == "" {
|
|
if currentGameState.Phase == PhasePick {
|
|
if len(playerHand) > 4 {
|
|
if g.Dealer == g.Player {
|
|
currentGameState.Status = "Throw for your crib"
|
|
} else {
|
|
currentGameState.Status = "Throw for your opponent's crib"
|
|
}
|
|
} else {
|
|
currentGameState.Status = "Waiting..."
|
|
}
|
|
} else if currentGameState.Phase == PhasePeg && currentGameState.Turn != currentGameState.Player {
|
|
currentGameState.Status = "Waiting..."
|
|
}
|
|
}
|
|
setStatusText(currentGameState.Status)
|
|
|
|
starterWidget.Card = currentGameState.Starter
|
|
|
|
if currentGameState.Phase == PhasePick {
|
|
mainHandStack.SetMaxSelection(2)
|
|
} else if currentGameState.Phase == PhasePeg && currentGameState.Turn == currentGameState.Player {
|
|
var canPeg bool
|
|
for i := range playerHand {
|
|
if cribbage.Sum(currentGameState.ThrowPile.Cards())+cribbage.Value(playerHand[i]) <= 31 {
|
|
canPeg = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if canPeg {
|
|
mainHandStack.SetMaxSelection(1)
|
|
} else {
|
|
mainHandStack.SetMaxSelection(-1)
|
|
}
|
|
} else {
|
|
mainHandStack.SetMaxSelection(-1)
|
|
}
|
|
|
|
if currentGameState.Phase == PhasePick {
|
|
if g.Dealer == g.Player {
|
|
mainCribStack.SetCards(playerCrib)
|
|
oppCribStack.SetCards(joker.Cards{})
|
|
} else {
|
|
oppCribStack.SetCards(oppCrib)
|
|
mainCribStack.SetCards(joker.Cards{})
|
|
}
|
|
mainHandStack.SetCards(playerHand)
|
|
throwStack.SetCards(joker.Cards{})
|
|
throwStack.Text = ""
|
|
} else if currentGameState.Phase == PhaseScore {
|
|
mainHandStack.SetCards(playerHand)
|
|
mainCribStack.SetCards(playerCrib)
|
|
throwStack.SetCards(oppHand)
|
|
oppCribStack.SetCards(oppCrib)
|
|
throwStack.Text = ""
|
|
} else { // Peg
|
|
throwStack.SetCards(currentGameState.ThrowPile.Cards())
|
|
mainHandStack.SetCards(playerHand)
|
|
|
|
mainCribStack.SetCards(playerCrib)
|
|
oppCribStack.SetCards(joker.Cards{})
|
|
|
|
var throwValue int
|
|
for i := range currentGameState.ThrowPile {
|
|
throwValue += cribbage.Value(currentGameState.ThrowPile[i].Card)
|
|
}
|
|
throwStack.Text = strconv.Itoa(throwValue)
|
|
}
|
|
} else {
|
|
setStatusText("Waiting for opponent...")
|
|
}
|
|
|
|
if currentGameState.Phase != lastPhase {
|
|
setupThrowGrid()
|
|
lastPhase = currentGameState.Phase
|
|
}
|
|
|
|
updateGameText()
|
|
|
|
if debug {
|
|
statusMessage(fmt.Sprintf("read: %+v\n", g))
|
|
}
|
|
|
|
app.Draw()
|
|
}
|
|
}
|
|
|
|
func handleWrite(c *websocket.Conn) {
|
|
for msg := range writeBuffer {
|
|
if debug {
|
|
statusMessage(fmt.Sprintf("write: %+v\n", msg))
|
|
}
|
|
|
|
w, err := c.NextWriter(websocket.TextMessage)
|
|
if err != nil {
|
|
c.Close()
|
|
return
|
|
}
|
|
|
|
w.Write([]byte(msg))
|
|
|
|
w.Close()
|
|
}
|
|
}
|