Cribbage.World terminal-based client
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

212 lines
4.6 KiB

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