forked from go/golangs_learn
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.
172 lines
3.0 KiB
172 lines
3.0 KiB
3 years ago
|
package cribbage
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"math/rand"
|
||
|
|
||
|
"gioui.org/example/outlay/fan/playing"
|
||
|
)
|
||
|
|
||
|
type Phase uint8
|
||
|
|
||
|
const (
|
||
|
BetweenHands Phase = iota
|
||
|
Dealing
|
||
|
Sacrifice
|
||
|
Cut
|
||
|
CircularCount
|
||
|
CountHands
|
||
|
CountCrib
|
||
|
)
|
||
|
|
||
|
func (p Phase) String() string {
|
||
|
switch p {
|
||
|
case BetweenHands:
|
||
|
return "between"
|
||
|
case Dealing:
|
||
|
return "dealing"
|
||
|
case Sacrifice:
|
||
|
return "sacrifice"
|
||
|
case Cut:
|
||
|
return "cut"
|
||
|
case CircularCount:
|
||
|
return "circular count"
|
||
|
case CountHands:
|
||
|
return "count hands"
|
||
|
case CountCrib:
|
||
|
return "count crib"
|
||
|
default:
|
||
|
return "unknown"
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type Game struct {
|
||
|
Phase
|
||
|
Deck []playing.Card
|
||
|
CutCard *playing.Card
|
||
|
Dealer int
|
||
|
Crib []playing.Card
|
||
|
Players []Player
|
||
|
}
|
||
|
|
||
|
type Player struct {
|
||
|
Hand, Table []playing.Card
|
||
|
}
|
||
|
|
||
|
func (p Player) String() string {
|
||
|
return fmt.Sprintf("[Hand: %s, Table: %s]", p.Hand, p.Table)
|
||
|
}
|
||
|
|
||
|
func (g Game) String() string {
|
||
|
return fmt.Sprintf("[Phase: %v\nDealer: %v\nCrib: %v\nCut: %v\nPlayers: %v\nDeck: %v]\n", g.Phase, g.Dealer, g.Crib, g.CutCard, g.Players, g.Deck)
|
||
|
}
|
||
|
|
||
|
const MinHand = 4
|
||
|
|
||
|
func NewGame(players int) Game {
|
||
|
var g Game
|
||
|
g.Players = make([]Player, players)
|
||
|
g.Dealer = g.NumPlayers() - 1
|
||
|
for i := 0; i < 4; i++ {
|
||
|
for j := 0; j < 13; j++ {
|
||
|
g.Deck = append(g.Deck, playing.Card{
|
||
|
Suit: playing.Suit(i),
|
||
|
Rank: playing.Rank(j),
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
g.Phase = Dealing
|
||
|
return g
|
||
|
}
|
||
|
|
||
|
func (g Game) NumPlayers() int {
|
||
|
return len(g.Players)
|
||
|
}
|
||
|
|
||
|
func (g Game) Right(player int) int {
|
||
|
return (player + g.NumPlayers() - 1) % g.NumPlayers()
|
||
|
}
|
||
|
|
||
|
func (g Game) Left(player int) int {
|
||
|
return (player + 1) % g.NumPlayers()
|
||
|
}
|
||
|
|
||
|
func (g *Game) CutAt(depth int) {
|
||
|
g.CutCard = &g.Deck[depth]
|
||
|
g.Phase = CircularCount
|
||
|
}
|
||
|
|
||
|
func DrainInto(src, dest *[]playing.Card) {
|
||
|
for _, c := range *src {
|
||
|
*dest = append(*dest, c)
|
||
|
}
|
||
|
*src = (*src)[:0]
|
||
|
}
|
||
|
|
||
|
func (g *Game) Reset() {
|
||
|
for i := range g.Players {
|
||
|
DrainInto(&(g.Players[i].Hand), &g.Deck)
|
||
|
DrainInto(&(g.Players[i].Table), &g.Deck)
|
||
|
}
|
||
|
DrainInto(&(g.Crib), &g.Deck)
|
||
|
g.Phase = Dealing
|
||
|
g.CutCard = nil
|
||
|
}
|
||
|
|
||
|
func (g *Game) DealCardTo(dest *[]playing.Card) {
|
||
|
card := g.Deck[0]
|
||
|
g.Deck = g.Deck[1:]
|
||
|
*dest = append(*dest, card)
|
||
|
}
|
||
|
|
||
|
func (g *Game) DealRound() {
|
||
|
g.Dealer = g.Left(g.Dealer)
|
||
|
g.Reset()
|
||
|
g.Shuffle()
|
||
|
for i := 0; i < g.CardsToDealPerPlayer(); i++ {
|
||
|
for i := range g.Players {
|
||
|
g.DealCardTo(&(g.Players[i].Hand))
|
||
|
}
|
||
|
}
|
||
|
for i := 0; i < g.CardsDealtToCrib(); i++ {
|
||
|
g.DealCardTo(&g.Crib)
|
||
|
}
|
||
|
g.Phase = Sacrifice
|
||
|
}
|
||
|
|
||
|
func (g Game) CardsToDealPerPlayer() int {
|
||
|
switch g.NumPlayers() {
|
||
|
case 2:
|
||
|
return 6
|
||
|
case 3:
|
||
|
return 5
|
||
|
case 4:
|
||
|
return 5
|
||
|
default:
|
||
|
return 0
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (g Game) CardsDealtToCrib() int {
|
||
|
if g.NumPlayers() == 3 {
|
||
|
return 1
|
||
|
}
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
func (g *Game) Shuffle() {
|
||
|
rand.Shuffle(len(g.Deck), func(i, j int) {
|
||
|
g.Deck[i], g.Deck[j] = g.Deck[j], g.Deck[i]
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func (g *Game) Sacrifice(player, card int) {
|
||
|
hand := g.Players[player].Hand
|
||
|
if len(hand) <= MinHand {
|
||
|
return
|
||
|
}
|
||
|
c := hand[card]
|
||
|
g.Players[player].Hand = append(hand[:card], hand[card+1:]...)
|
||
|
g.Crib = append(g.Crib, c)
|
||
|
}
|