jack/game.go

920 lines
23 KiB
Go

package main
import (
"encoding/json"
"fmt"
"log"
"math/rand"
"reflect"
"sort"
"strconv"
"strings"
"sync"
"gitlab.com/tslocum/joker"
. "gitlab.com/tslocum/joker"
cribbage "gitlab.com/tslocum/joker-cribbage"
)
const (
PhaseEnd = -1
PhaseSetup = 0
PhasePick = 1
PhasePeg = 2
PhaseScore = 3
)
const (
PegPhaseNormal = 0
PegPhaseSolo = 1
PegPhaseFinal = 2
)
const WinningScore = 121
const shuffleCount = 7
type Game struct {
CommandQueue chan GameCommand `json:"-"`
Deck *Deck `json:"-"`
Phase int `json:"phase"`
Dealer int `json:"dealer"`
Turn int `json:"turn"`
Starter Card `json:"starter"`
Player1 *Client `json:"-"`
Player2 *Client `json:"-"`
Hand1 Cards `json:"hand1"`
Hand2 Cards `json:"hand2"`
Crib Cards `json:"crib"`
ThrownCrib1 int
ThrownCrib2 int
Score1 int `json:"score1"`
Score2 int `json:"score2"`
ThrowPile PlayerCards `json:"throwpile"`
DiscardPile PlayerCards `json:"-"`
PegPhase int `json:"-"`
sync.RWMutex `json:"-"`
}
func NewGame(player1 *Client, player2 *Client) *Game {
game := new(Game)
game.Initialize()
game.addPlayer(1, player1)
game.addPlayer(2, player2)
game.Deal()
return game
}
func (g *Game) Initialize() {
g.CommandQueue = make(chan GameCommand, 10)
g.Dealer = rand.Intn(2) + 1
if g.Dealer == 1 {
g.Turn = 2
} else {
g.Turn = 1
}
g.Reset()
}
func (g *Game) Reset() {
g.Hand1 = Cards{}
g.Hand2 = Cards{}
g.Crib = Cards{}
g.Starter = Card{}
g.ThrowPile = PlayerCards{}
g.DiscardPile = PlayerCards{}
g.ThrownCrib1 = 0
g.ThrownCrib2 = 0
g.Deck = NewDeck(StandardCards, 0)
for i := 0; i < shuffleCount; i++ {
g.Deck.Shuffle()
}
g.PegPhase = PegPhaseNormal
g.Phase = PhaseSetup
}
func (g *Game) addPlayer(player int, client *Client) {
client.game = g
client.gameplayer = player
client.gameready = true
if player == 1 {
g.Player1 = client
} else {
g.Player2 = client
}
}
func (g *Game) Deal() {
if g.Phase != PhaseSetup {
return
}
var dealtcards joker.Cards
var ok bool
g.Phase = PhasePick
g.ResetGo()
g.ResetReady()
for i := 0; i < 12; i++ {
dealtcards, ok = g.Deck.Draw(1)
if !ok {
log.Fatalf("failed to deal: not enough cards")
}
if i%2 == 0 {
g.Hand1 = append(g.Hand1, dealtcards[0])
} else {
g.Hand2 = append(g.Hand2, dealtcards[0])
}
}
sort.Sort(g.Hand1)
sort.Sort(g.Hand2)
}
func (g *Game) Cut(cut int) bool {
if g.Phase != PhasePick || g.Crib.Len() < 4 || g.Starter.Value() > 0 {
return false
}
g.logDebug("Cutting @", cut)
g.Starter = g.Deck.Cards[cut]
g.Phase = PhasePeg
for msgplayer := 1; msgplayer <= 2; msgplayer++ {
if g.getClient(msgplayer).ConnType == ClientTelnet {
g.getClient(msgplayer).write("Starter: " + g.Starter.String())
} else {
//g.update(msgplayer)
// TODO updateAll is called
}
}
if g.Starter.Identifier() == "j" {
g.award(g.Dealer, 2, cribbage.Peg, "Nibs")
}
return true
}
func (g *Game) exportJSON(player int) (string, error) {
gamestate := make(map[string]string)
gamereflected := reflect.ValueOf(g).Elem()
for i := 0; i < gamereflected.NumField(); i++ {
fieldname := gamereflected.Type().Field(i).Name
fieldtag := gamereflected.Type().Field(i).Tag.Get("json")
if fieldtag == "" || fieldtag == "-" {
continue
} else if g.Phase != PhaseScore && ((fieldname == "Hand1" && player != 1) || (fieldname == "Hand2" && player != 2)) {
hand := gamereflected.Field(i).Interface().(joker.Cards)
handprinted := ""
for j := 0; j < hand.Len(); j++ {
if j > 0 {
handprinted += ","
}
handprinted += "\"??\""
}
gamestate[fieldtag] = fmt.Sprintf("[%s]", handprinted)
} else if g.Phase != PhaseScore && fieldname == "Crib" {
hand := gamereflected.Field(i).Interface().(joker.Cards)
handprinted := ""
for j := 0; j < hand.Len(); j++ {
if j > 0 {
handprinted += ","
}
handprinted += "\"??\""
}
gamestate[fieldtag] = fmt.Sprintf("[%s]", handprinted)
} else {
jsonvalue, err := json.Marshal(gamereflected.Field(i).Interface())
if err != nil {
return "", err
}
gamestate[fieldtag] = string(jsonvalue)
}
}
if player > 0 {
gamestate["player"] = strconv.Itoa(player)
jsonvalue, err := json.Marshal(g.getClient(player).getStatus())
if err != nil {
return "", err
}
gamestate["status"] = string(jsonvalue)
}
throwPileSum := cribbage.Sum(g.ThrowPile.Cards())
gamestate["throwpilesum"] = strconv.Itoa(throwPileSum)
throwpilescore, _ := cribbage.Score(cribbage.Peg, g.ThrowPile.Cards(), g.Starter)
if g.Phase == PhasePeg && g.PegPhase == PegPhaseFinal && g.PeggingFinished() && throwPileSum != 31 {
throwpilescore++
}
gamestate["throwpilescore"] = strconv.Itoa(throwpilescore)
gamestatelines := []string{}
for statefield, statevalue := range gamestate {
gamestatelines = append(gamestatelines, fmt.Sprintf("\"%s\": %s", statefield, statevalue))
}
return fmt.Sprintf("{%s}", strings.Join(gamestatelines, ",")), nil
}
func (g *Game) Peg(player int) int {
if g.Phase != PhasePeg || g.Turn != player {
log.Println("Error, not players turn or other invalid state")
return -1
}
pegscore, _ := cribbage.Score(cribbage.Peg, g.ThrowPile.Cards(), g.Starter)
if pegscore > 0 {
g.award(g.Turn, pegscore, cribbage.Peg, "")
}
return pegscore
}
func (g *Game) award(player int, score int, scoretype cribbage.ScoringType, reason string) int {
if g.Phase != PhaseEnd {
points := "point"
if score != 1 {
points = "points"
}
st := "scored"
if scoretype == cribbage.Peg {
st = "pegged"
}
if reason != "" {
reason = " - " + reason
}
for msgplayer := 1; msgplayer <= 2; msgplayer++ {
g.getClient(msgplayer).write(fmt.Sprintf("%s %s %d %s%s", g.getName(msgplayer, player), st, score, points, reason))
}
if player == 1 {
g.Score1 += score
} else {
g.Score2 += score
}
if g.getScore(player) >= WinningScore {
g.end(player, "Won!")
}
}
return g.getScore(player)
}
func (g *Game) scoreHands() (int, int, int) {
if g.Phase != PhasePeg || g.Hand1.Len() > 0 || g.Hand2.Len() > 0 {
log.Println("Error, not pegging phase or player still has cards")
return -1, -1, -1
}
// TODO: Store player in card data or separate slice
g.Phase = PhaseScore
for _, card := range g.ThrowPile {
if card.Player == 1 {
g.Hand1 = append(g.Hand1, card.Card)
} else {
g.Hand2 = append(g.Hand2, card.Card)
}
}
for _, card := range g.DiscardPile {
if card.Player == 1 {
g.Hand1 = append(g.Hand1, card.Card)
} else {
g.Hand2 = append(g.Hand2, card.Card)
}
}
sort.Sort(g.Hand1)
sort.Sort(g.Hand2)
opponentHandScore, _ := cribbage.Score(cribbage.ShowHand, *g.getHand(g.getOpponent(g.Dealer)), g.Starter)
dealerHandScore, _ := cribbage.Score(cribbage.ShowHand, *g.getHand(g.Dealer), g.Starter)
dealerCribScore, _ := cribbage.Score(cribbage.Peg, g.Crib, g.Starter)
// Awarding order is important
opponentscore := g.award(g.getOpponent(g.Dealer), opponentHandScore, cribbage.ShowHand, "Hand")
dealerscore := g.award(g.Dealer, dealerHandScore, cribbage.ShowHand, "Hand")
dealercribscore := g.award(g.Dealer, dealerCribScore, cribbage.ShowHand, "Crib")
var yourscore string
var theirscore string
dealerscoreprinted := fmt.Sprintf("%d (%d hand + %d crib)", dealerHandScore+dealerCribScore, dealerHandScore, dealerCribScore)
opponentscoreprinted := fmt.Sprintf("%d", opponentHandScore)
for msgplayer := 1; msgplayer <= 2; msgplayer++ {
if g.Dealer == msgplayer {
yourscore = dealerscoreprinted
theirscore = opponentscoreprinted
} else {
yourscore = opponentscoreprinted
theirscore = dealerscoreprinted
}
g.getClient(msgplayer).gameready = false
g.getClient(msgplayer).setStatus("You scored " + yourscore + " - Your opponent scored " + theirscore)
log.Println(msgplayer, "You scored "+yourscore+" - Your opponent scored "+theirscore)
}
return opponentscore, dealerscore, dealercribscore
}
func (g *Game) end(player int, reason string) {
g.CommandQueue <- GameCommand{Player: player, Command: CommandEnd, Value: reason}
}
func (g *Game) Throw(player int, cardidentifier string) bool {
if g.Phase == PhaseScore {
return false
} else if g.Phase == PhasePick {
// TODO Store players of thrown cards or check number of cards still left in thrower hand
if (player == 1 && g.ThrownCrib1 == 2) || (player == 2 && g.ThrownCrib2 == 2) {
log.Println("Error, already thrown")
return false
}
} else if g.Phase == PhasePeg && (g.Turn != player || g.PegPhase == PegPhaseFinal) {
log.Println("Error, not players turn")
return false
}
card, ok := Parse(cleanIdentifier(cardidentifier))
if !ok {
log.Println("Attempted to throw invalid card:", player, cardidentifier)
return false
}
playerHand := g.getHand(player)
opponentHand := g.getHand(g.getOpponent(player))
if !playerHand.Contains(card) {
log.Println("Attempted to throw card not in hand:", player, cardidentifier, playerHand)
return false
}
if g.Phase == PhasePeg {
if cribbage.Sum(g.ThrowPile.Cards())+cribbage.Value(card) > 31 {
g.getClient(player).write("Error: Illegal throw, would exceed 31")
return false
}
}
*playerHand = (*playerHand).Remove(card)
if g.Phase == PhasePick {
if player == 1 {
g.ThrownCrib1++
} else {
g.ThrownCrib2++
}
g.Crib = append(g.Crib, card)
sort.Sort(g.Crib)
/*if len(g.Crib.Cards) == 4 && player == g.Dealer {
g.updateOpponent(player)
}*/
// TODO: Temporary before cut UI
if len(g.Crib) == 4 {
g.Cut(rand.Intn(32) + 4)
}
} else if g.Phase == PhasePeg {
g.ThrowPile = append(g.ThrowPile, PlayerCard{card, player})
g.Peg(player)
if cribbage.Sum(g.ThrowPile.Cards()) == 31 {
log.Println("=31 move to solo")
g.PegPhase = PegPhaseSolo
g.pegTurn(player)
} else if cribbage.Sum(g.ThrowPile.Cards())+cribbage.Value(opponentHand.Low()) > 31 {
if opponentHand.Len() > 0 && !g.getClient(g.getOpponent(player)).gamego {
log.Println("Setting Go - Player", g.getOpponent(player))
g.getClient(g.getOpponent(player)).gamego = true
g.getClient(g.getOpponent(player)).setStatus("Go")
g.getClient(g.getOpponent(player)).gameready = false
g.NextTurn()
} else if g.PeggingFinished() {
log.Println(">31 pegging finished move to solo")
g.PegPhase = PegPhaseSolo
g.pegTurn(player)
}
} else if opponentHand.Len() == 0 && playerHand.Len() == 0 {
log.Println("no cards left all move to solo")
g.PegPhase = PegPhaseSolo
g.pegTurn(player)
} else if opponentHand.Len() == 0 {
log.Println("no cards left opponent move to solo")
g.PegPhase = PegPhaseSolo
g.pegTurn(player)
} else {
g.NextTurn()
}
}
return true
}
func (g *Game) PeggingFinished() bool {
return (g.getHand(1).Len() == 0 || cribbage.Sum(g.ThrowPile.Cards())+cribbage.Value(g.getHand(1).Low()) > 31) &&
(g.getHand(2).Len() == 0 || cribbage.Sum(g.ThrowPile.Cards())+cribbage.Value(g.getHand(2).Low()) > 31)
}
func (g *Game) ResetGo() {
if g.Phase > 0 {
g.logDebug("Reset go")
g.Player1.gamego = false
g.Player2.gamego = false
}
}
func (g *Game) ResetReady() {
if g.Phase > 0 {
g.Player1.gameready = true
g.Player1.setStatus("")
g.Player2.gameready = true
g.Player2.setStatus("")
}
}
func (g *Game) Ready(player int) {
g.getClient(player).gameready = true
g.getClient(player).setStatus("Waiting on opponent...")
}
func (g *Game) AllReady() bool {
return g.Player1.gameready && g.Player2.gameready
}
func (g *Game) NextTurn() {
g.logDebug("Turn...")
if g.Turn == 1 {
g.Turn = 2
} else {
g.Turn = 1
}
}
func (g *Game) NextHand() {
g.Turn = g.Dealer
g.Dealer = g.getOpponent(g.Dealer)
g.Reset()
g.Deal()
}
func (g *Game) getClient(player int) *Client {
if player == 1 {
return g.Player1
} else {
return g.Player2
}
}
func (g *Game) getOpponent(player int) int {
if player == 1 {
return 2
} else {
return 1
}
}
func (g *Game) getName(player int, clientplayer int) string {
if player == clientplayer {
return "You"
} else {
return "Your opponent"
}
}
func (g *Game) getScore(player int) int {
if player == 1 {
return g.Score1
} else {
return g.Score2
}
}
func (g *Game) getHand(player int) *Cards {
if player == 1 {
return &g.Hand1
} else {
return &g.Hand2
}
}
func (g *Game) update(player int) {
g.sendGameState(player)
}
func (g *Game) updateOpponent(player int) {
if player == 1 {
g.update(2)
} else {
g.update(1)
}
}
func (g *Game) updateAll() {
g.update(1)
g.update(2)
}
func (g *Game) printScoring() {
for player := 1; player <= 2; player++ {
var gameprinted []string
opponentscore, opponentscoreresults := cribbage.Score(cribbage.ShowHand, *g.getHand(g.getOpponent(player)), g.Starter)
playerscore, dealerscoreresults := cribbage.Score(cribbage.ShowHand, *g.getHand(player), g.Starter)
cribscore, cribscoreresults := cribbage.Score(cribbage.ShowCrib, g.Crib, g.Starter)
if g.Dealer == player {
gameprinted = append(gameprinted, fmt.Sprintf("Your hands scored %d (%d hand, %d crib) - Your opponent's hand scored %d", playerscore, cribscore, opponentscore))
} else {
gameprinted = append(gameprinted, fmt.Sprintf("Your hand scored %d - Your opponent's hands scored %d (%d hand, %d crib)", playerscore, opponentscore, cribscore))
}
gameprinted = append(gameprinted, "Starter "+g.Starter.String())
gameprinted = append(gameprinted, fmt.Sprintf("Player (%2d) %s", opponentscore, g.getHand(player)))
if g.Dealer == player {
gameprinted = append(gameprinted, fmt.Sprintf("Player c. (%2d) %s", cribscore, g.Crib))
gameprinted = append(gameprinted, fmt.Sprintf("Opponent (%2d) %s", opponentscore, g.getHand(g.getOpponent(player))))
for _, result := range dealerscoreresults {
gameprinted = append(gameprinted, fmt.Sprintf("Your hand scored %s", result))
}
for _, result := range cribscoreresults {
gameprinted = append(gameprinted, fmt.Sprintf("Your crib scored %s", result))
}
for _, result := range opponentscoreresults {
gameprinted = append(gameprinted, fmt.Sprintf("Your opponent's hand scored %s", result))
}
} else {
gameprinted = append(gameprinted, fmt.Sprintf("Opponent c. (%2d) %s", cribscore, g.Crib))
gameprinted = append(gameprinted, fmt.Sprintf("Opponent (%2d) %s", opponentscore, g.getHand(g.getOpponent(player))))
for _, result := range opponentscoreresults {
gameprinted = append(gameprinted, fmt.Sprintf("Your hand scored %s", result))
}
for _, result := range dealerscoreresults {
gameprinted = append(gameprinted, fmt.Sprintf("Your opponent's hand scored %s", result))
}
for _, result := range cribscoreresults {
gameprinted = append(gameprinted, fmt.Sprintf("Your opponent's crib scored %s", result))
}
}
for _, msg := range gameprinted {
g.getClient(player).write(msg)
}
}
}
func (g *Game) printGame(player int) string {
lightprint := false
gameprinted := []string{}
if g.Phase == PhasePeg {
gameprinted = append(gameprinted, "Pegging: "+g.ThrowPile.String()+" ("+strconv.Itoa(cribbage.Sum(g.ThrowPile.Cards()))+")")
if g.Turn == player {
gameprinted = append(gameprinted, fmt.Sprintf("Please throw a card. (Enter 1-%d)", g.getHand(player).Len()))
} else if g.getHand(player).Len() > 0 && cribbage.Sum(g.ThrowPile.Cards())+cribbage.Value(g.getHand(player).Low()) > 31 {
lightprint = true
gameprinted = append(gameprinted, "Go - Waiting on opponent...")
} else {
lightprint = true
gameprinted = append(gameprinted, "Waiting on opponent...")
}
}
gameprintedstr := ""
if g.Phase == PhasePick {
cardsthrown := 0
if player == 1 {
cardsthrown = g.ThrownCrib1
} else {
cardsthrown = g.ThrownCrib2
}
if cardsthrown < 2 {
if cardsthrown == 0 {
gameprintedstr += "Please throw two cards for "
} else {
gameprintedstr += "Please throw one additional card for "
}
if g.Dealer == player {
gameprintedstr += "your"
} else {
gameprintedstr += "your opponent's"
}
gameprintedstr += fmt.Sprintf(" crib. (Enter 1-%d, throw multiple cards by separating card#'s with a space)", g.getHand(player).Len())
} else if len(g.Crib) < 4 {
lightprint = true
gameprintedstr += "Waiting on opponent..."
} else if g.Starter.Value() == 0 {
lightprint = true
if g.Dealer != player {
gameprintedstr += "Please cut the deck. (Enter 4-36 or c/cut for a random cut)"
} else {
gameprintedstr += "Waiting on opponent..."
}
}
gameprinted = append(gameprinted, gameprintedstr)
gameprintedstr = ""
}
if !lightprint {
if len(gameprinted) > 0 {
gameprinted = append(gameprinted, "")
}
gameprinted = append(gameprinted, fmt.Sprintf("Score: (%s) %d / %d (%s)", g.getName(1, player), g.getScore(1), g.getScore(2), g.getName(2, player)))
gameprinted = append(gameprinted, "Your cards: "+g.getHand(player).String())
}
return strings.Join(gameprinted, "\n")
}
func (g *Game) printAll() {
log.Println("Printing game state...")
var phaseprinted string
switch g.Phase {
case PhaseSetup:
phaseprinted = "Setup"
break
case PhasePick:
phaseprinted = "Pick"
break
case PhasePeg:
phaseprinted = "Peg"
switch g.Phase {
case PegPhaseNormal:
phaseprinted += " Normal"
break
case PegPhaseSolo:
phaseprinted += " Solo"
break
case PegPhaseFinal:
phaseprinted += " Final"
break
}
break
case PhaseScore:
phaseprinted = "Score"
break
case PhaseEnd:
phaseprinted = "End"
}
log.Printf("[%s] Dealer: %d - Turn: %d", phaseprinted, g.Dealer, g.Turn)
if g.Phase > 0 {
log.Printf("Player 1 ready: %t - Player 2 ready: %t", g.Player1.gameready, g.Player2.gameready)
}
var starter Card
if g.Starter.Value() > 0 {
starter = g.Starter
}
hand1Score, hand1ScoreResults := cribbage.Score(cribbage.ShowHand, g.Hand1, starter)
log.Println("Hand 1 [", hand1Score, "]", g.Hand1.String(), hand1ScoreResults)
cribScore, cribScoreResults := cribbage.Score(cribbage.ShowCrib, g.Crib, starter)
log.Println("Crib [", cribScore, "]", g.Crib.String(), cribScoreResults)
hand2Score, hand2ScoreResults := cribbage.Score(cribbage.ShowHand, g.Hand2, starter)
log.Println("Hand 2 [", hand2Score, "]", g.Hand2.String(), hand2ScoreResults)
if g.Starter.Value() > 0 {
log.Println("Starter:", g.Starter.String())
}
if g.ThrowPile.Len() > 0 {
pegScore, pegResults := cribbage.Score(cribbage.Peg, g.ThrowPile.Cards(), starter)
log.Println("Pegging: [", pegScore, "]", g.ThrowPile.Cards().String(), pegResults)
}
if g.DiscardPile.Len() > 0 {
log.Println("Discard:", g.DiscardPile.String())
}
}
func (g *Game) sendGameState(player int) {
client := g.getClient(player)
if client.ConnType == ClientWebsocket {
gamestate, err := g.exportJSON(player)
if err != nil {
log.Fatal("failed to marshal game state:", err)
}
client.write(string(gamestate))
} else {
client.write(g.printGame(player))
}
}
func (g *Game) pegTurn(player int) {
if g.Phase != PhasePeg {
return
}
g.logDebug("PEG CONTINUE")
if cribbage.Sum(g.ThrowPile.Cards())+cribbage.Value(g.getHand(player).Low()) > 31 && g.PegPhase == PegPhaseNormal {
g.logDebug("PEG NEXT TURN")
if g.PeggingFinished() {
g.ResetGo()
g.PegPhase = PegPhaseSolo
g.getClient(g.getOpponent(player)).gameready = false
g.getClient(g.getOpponent(player)).setStatus("Go - Pegging finished")
}
g.NextTurn()
} else if g.PeggingFinished() {
if g.PegPhase == PegPhaseSolo {
g.logDebug("ENTERING FINAL PEG")
g.PegPhase = PegPhaseFinal
finalpeg, _ := cribbage.Score(cribbage.Peg, g.ThrowPile.Cards(), g.Starter)
if cribbage.Sum(g.ThrowPile.Cards()) != 31 {
finalpeg++
g.award(g.Turn, 1, cribbage.Peg, "Last card")
}
g.getClient(g.Turn).gameready = false
g.getClient(g.Turn).setStatus("You pegged " + strconv.Itoa(finalpeg) + " point")
if finalpeg != 1 {
g.getClient(g.Turn).gamestatus += "s"
}
g.getClient(g.getOpponent(g.Turn)).gameready = false
g.getClient(g.getOpponent(g.Turn)).setStatus("Your opponent pegged " + strconv.Itoa(finalpeg) + " point")
if finalpeg != 1 {
g.getClient(g.getOpponent(g.Turn)).gamestatus += "s"
}
g.NextTurn()
} else if g.PegPhase == PegPhaseFinal {
g.logDebug("FINAL PEG")
g.PegPhase = PegPhaseNormal
if g.Hand1.Len() == 0 && g.Hand2.Len() == 0 {
if cribbage.Sum(g.ThrowPile.Cards()) != 31 {
g.award(g.Turn, 1, cribbage.Peg, "Last card")
}
g.scoreHands()
g.printScoring()
g.NextTurn()
} else {
g.DiscardPile = append(g.DiscardPile, g.ThrowPile...)
g.ThrowPile = PlayerCards{}
}
}
}
}
func (g *Game) processGameCommand(command GameCommand) {
g.Lock()
defer g.Unlock()
if command.Command == CommandEnd {
g.Phase = PhaseEnd
g.updateAll()
return
}
command_args := strings.Fields(command.Value)
if command.Command == CommandRaw {
if g.Phase == PhasePick && g.Crib.Len() == 4 && g.Starter.Value() == 0 {
command.Command = CommandCut
} else {
command.Command = CommandThrow
}
}
if g.Phase == PhasePick && command.Command == CommandCut {
if len(command_args) > 0 {
cut, err := strconv.Atoi(command_args[0])
if err == nil && cut >= 4 && cut <= 36 {
g.Cut(cut - 1)
}
}
g.Cut(rand.Intn(32) + 4)
} else if command.Command == CommandContinue {
if g.getClient(command.Player).gameready {
return
}
g.Ready(command.Player)
if g.AllReady() {
g.Player1.setStatus("")
g.Player2.setStatus("")
g.logDebug("ALL READY")
if g.Phase == PhasePeg {
g.pegTurn(command.Player)
} else if g.Phase == PhaseScore {
g.NextHand()
g.update(g.getOpponent(command.Player))
}
}
} else if command.Command == CommandThrow {
if g.Phase == PhasePick || g.Phase == PhasePeg {
cards := []string{}
lastindex := 0
for i, cardarg := range command_args {
cardindex, err := strconv.Atoi(cardarg)
if err == nil {
if cardindex == lastindex {
break
}
if cardindex >= 1 && g.getHand(command.Player).Len() >= cardindex {
cards = append(cards, (*g.getHand(command.Player))[(cardindex-1)].Identifier())
lastindex = cardindex
}
} else {
cards = append(cards, cardarg)
}
if i > 1 {
break
}
}
for _, card := range cards {
g.Throw(command.Player, card)
}
}
} else if command.Command == CommandMessage {
data, err := json.Marshal(command)
if err != nil {
log.Fatal(err)
}
g.getClient(g.getOpponent(command.Player)).write(string(data))
}
g.updateAll()
}
func (g *Game) playGame() {
log.Println("Starting new game")
g.updateAll()
for command := range g.CommandQueue {
g.logDebug("Received GameCommand", command.ToStr())
g.processGameCommand(command)
if g.Phase == PhaseEnd {
break
}
}
}
func (g *Game) logDebug(args ...interface{}) {
log.Println("phase:", g.Phase,
"turn:", g.Turn,
"dealer:", g.Dealer, args)
}
func cleanIdentifier(cardidentifier string) string {
return strings.ToLower(strings.Trim(cardidentifier, trimNewlinesAndSpace))
}