155 lines
3.1 KiB
Go
155 lines
3.1 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand"
|
|
)
|
|
|
|
func PlayGame(numPlayers int, entropy *rand.Rand) {
|
|
|
|
currentPlayer := 0
|
|
|
|
runningScores := make([]int, numPlayers)
|
|
|
|
for round := 3; round < 14; round++ {
|
|
|
|
r := NewRound(round, numPlayers, entropy)
|
|
nextPlayer, roundScores := r.Play(currentPlayer)
|
|
|
|
currentPlayer = nextPlayer
|
|
|
|
for p := 0; p < numPlayers; p++ {
|
|
runningScores[p] += roundScores[p]
|
|
}
|
|
|
|
fmt.Printf("The round has ended\n")
|
|
fmt.Printf("Running total scores: %v\n", runningScores)
|
|
}
|
|
|
|
fmt.Printf("The game has ended\n")
|
|
}
|
|
|
|
type Round struct {
|
|
d []Card
|
|
discard []Card
|
|
round int
|
|
numPlayers int
|
|
hands [][]Card
|
|
}
|
|
|
|
func NewRound(round, numPlayers int, entropy *rand.Rand) *Round {
|
|
|
|
r := Round{
|
|
round: round,
|
|
numPlayers: numPlayers,
|
|
}
|
|
|
|
r.d = Deck()
|
|
Shuffle(r.d, entropy)
|
|
|
|
r.discard = []Card{}
|
|
|
|
fmt.Printf("# Round %d\n\n", r.round)
|
|
|
|
// Deal starting cards
|
|
|
|
r.hands = make([][]Card, numPlayers)
|
|
for p := 0; p < numPlayers; p++ {
|
|
r.hands[p] = r.d[0:round] // Deal from the bottom (0)
|
|
r.d = r.d[round:]
|
|
|
|
fmt.Printf("P%d starting hand: %v\n", p, r.hands[p])
|
|
}
|
|
|
|
// Deal one into the discard pile
|
|
|
|
r.discard = append(r.discard, r.d[0])
|
|
r.d = r.d[1:]
|
|
|
|
// Done
|
|
|
|
return &r
|
|
}
|
|
|
|
func FormatHandGroupings(hand []Card, groupings [][]int) string {
|
|
tmp := forkHand(hand)
|
|
|
|
cgroups := [][]Card{}
|
|
for _, group := range groupings {
|
|
cgroup := []Card{}
|
|
for _, cidx := range group {
|
|
cgroup = append(cgroup, hand[cidx])
|
|
|
|
tmp[cidx] = Card(-1)
|
|
}
|
|
cgroups = append(cgroups, cgroup)
|
|
}
|
|
|
|
leftover := []Card{}
|
|
for _, cv := range tmp {
|
|
if cv != Card(-1) {
|
|
leftover = append(leftover, cv)
|
|
}
|
|
}
|
|
|
|
return fmt.Sprintf("[ %v leftover %v ]", cgroups, leftover)
|
|
}
|
|
|
|
func (r *Round) Play(startingPlayer int) (nextPlayer int, roundScores []int) {
|
|
|
|
currentPlayer := startingPlayer
|
|
|
|
fmt.Printf("Discard stack: %v\n", r.discard)
|
|
|
|
fmt.Printf("Deck has %d cards remaining\n", len(r.d))
|
|
|
|
roundEndsWhenPlayerIs := -1
|
|
|
|
for {
|
|
if roundEndsWhenPlayerIs == currentPlayer {
|
|
break
|
|
}
|
|
|
|
// Play the strategy for the current player
|
|
r.PlayDefaultStrategy(currentPlayer)
|
|
|
|
// Check, one more time, if we have a winning hand
|
|
|
|
currentBestGrouping, currentScore := FindBestGrouping(r.hands[currentPlayer], r.round)
|
|
if currentScore == 0 {
|
|
|
|
// Declare victory
|
|
fmt.Printf("P%d declares victory\n- Hand: %v\n- Groupings: %v\n", currentPlayer, r.hands[currentPlayer], currentBestGrouping)
|
|
|
|
if roundEndsWhenPlayerIs == -1 {
|
|
roundEndsWhenPlayerIs = currentPlayer
|
|
} // Otherwise, the round is already ending anyway
|
|
}
|
|
|
|
// Move to the next player
|
|
currentPlayer = (currentPlayer + 1) % r.numPlayers
|
|
}
|
|
|
|
// The round has ended
|
|
// Figure out what each player scored
|
|
|
|
roundScores = make([]int, r.numPlayers)
|
|
|
|
for p := 0; p < r.numPlayers; p++ {
|
|
|
|
gr, score := FindBestGrouping(r.hands[p], r.round)
|
|
|
|
fmt.Printf("P%d has %v (score: %d)\n", p, FormatHandGroupings(r.hands[p], gr) /*r.hands[p], gr,*/, score)
|
|
|
|
roundScores[p] = score
|
|
}
|
|
|
|
// Check stack alignment
|
|
if len(r.discard)+len(r.d)+(r.numPlayers*len(r.hands[0])) != DeckSize {
|
|
panic("Cards on the floor")
|
|
}
|
|
|
|
// Done
|
|
return currentPlayer, roundScores
|
|
}
|