168 lines
3.6 KiB
Go
168 lines
3.6 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 (r *Round) DrawFromDeck() Card {
|
|
newCard := r.d[0]
|
|
r.d = r.d[1:]
|
|
return newCard
|
|
}
|
|
|
|
func (r *Round) PeekFromDiscard() Card {
|
|
return r.discard[len(r.discard)-1]
|
|
}
|
|
|
|
func (r *Round) DrawFromDiscard() Card {
|
|
newCard := r.discard[len(r.discard)-1]
|
|
r.discard = r.discard[0 : len(r.discard)-1]
|
|
|
|
return newCard
|
|
}
|
|
|
|
func (r *Round) AddToHand(player int, c Card) {
|
|
r.hands[player] = append(r.hands[player], c)
|
|
}
|
|
|
|
func (r *Round) Discard(player, idx int) {
|
|
unwantedCard := r.hands[player][idx]
|
|
|
|
// Slice tricks: Copy end card into this slot and reslice bounds
|
|
|
|
r.hands[player][idx] = r.hands[player][len(r.hands[player])-1]
|
|
r.hands[player] = r.hands[player][0 : len(r.hands[player])-1]
|
|
|
|
r.discard = append(r.discard, unwantedCard) // On top = available for next player
|
|
}
|
|
|
|
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- Summary: %v\n", currentPlayer, r.hands[currentPlayer], currentBestGrouping, FormatHandGroupings(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)
|
|
|
|
if roundEndsWhenPlayerIs == p && score != 0 {
|
|
fmt.Printf("Expected player %d to have won, but they didn't?\n", p)
|
|
panic("???")
|
|
}
|
|
|
|
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
|
|
}
|