refactor formatting, reuse helper functions
This commit is contained in:
parent
7896dc9f6b
commit
670e557966
29
format.go
Normal file
29
format.go
Normal file
@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
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] = NewMasked()
|
||||
}
|
||||
cgroups = append(cgroups, cgroup)
|
||||
}
|
||||
|
||||
leftover := []Card{}
|
||||
for _, cv := range tmp {
|
||||
if !cv.Masked() {
|
||||
leftover = append(leftover, cv)
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("[ %v leftover %v ]", cgroups, leftover)
|
||||
}
|
12
format_test.go
Normal file
12
format_test.go
Normal file
@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestFormatHandGrouping(t *testing.T) {
|
||||
str := FormatHandGroupings([]Card{5, 10, 15, 20}, [][]int{[]int{0, 1}, []int{2}})
|
||||
assert.EqualValues(t, "[ [[ 1♠ 2♠] [ 3♠]] leftover [ 4♠] ]", str)
|
||||
}
|
51
game.go
51
game.go
@ -71,28 +71,36 @@ func NewRound(round, numPlayers int, entropy *rand.Rand) *Round {
|
||||
return &r
|
||||
}
|
||||
|
||||
func FormatHandGroupings(hand []Card, groupings [][]int) string {
|
||||
tmp := forkHand(hand)
|
||||
func (r *Round) DrawFromDeck() Card {
|
||||
newCard := r.d[0]
|
||||
r.d = r.d[1:]
|
||||
return newCard
|
||||
}
|
||||
|
||||
cgroups := [][]Card{}
|
||||
for _, group := range groupings {
|
||||
cgroup := []Card{}
|
||||
for _, cidx := range group {
|
||||
cgroup = append(cgroup, hand[cidx])
|
||||
func (r *Round) PeekFromDiscard() Card {
|
||||
return r.discard[len(r.discard)-1]
|
||||
}
|
||||
|
||||
tmp[cidx] = Card(-1)
|
||||
}
|
||||
cgroups = append(cgroups, cgroup)
|
||||
}
|
||||
func (r *Round) DrawFromDiscard() Card {
|
||||
newCard := r.discard[len(r.discard)-1]
|
||||
r.discard = r.discard[0 : len(r.discard)-1]
|
||||
|
||||
leftover := []Card{}
|
||||
for _, cv := range tmp {
|
||||
if cv != Card(-1) {
|
||||
leftover = append(leftover, cv)
|
||||
}
|
||||
}
|
||||
return newCard
|
||||
}
|
||||
|
||||
return fmt.Sprintf("[ %v leftover %v ]", cgroups, leftover)
|
||||
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) {
|
||||
@ -119,7 +127,7 @@ func (r *Round) Play(startingPlayer int) (nextPlayer int, roundScores []int) {
|
||||
if currentScore == 0 {
|
||||
|
||||
// Declare victory
|
||||
fmt.Printf("P%d declares victory\n- Hand: %v\n- Groupings: %v\n", currentPlayer, r.hands[currentPlayer], currentBestGrouping)
|
||||
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
|
||||
@ -141,6 +149,11 @@ func (r *Round) Play(startingPlayer int) (nextPlayer int, roundScores []int) {
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
25
game_test.go
25
game_test.go
@ -17,3 +17,28 @@ func TestPlayRound(t *testing.T) {
|
||||
assert.EqualValues(t, 0, nextPlayer)
|
||||
assert.EqualValues(t, []int{0, 28, 6, 6}, scores)
|
||||
}
|
||||
|
||||
func TestDrawDiscard(t *testing.T) {
|
||||
|
||||
entropy := rand.New(rand.NewSource(0xdeadbeef))
|
||||
|
||||
rr := NewRound(5, 4, entropy)
|
||||
|
||||
assert.EqualValues(t, []Card{50, 47, 24, 25, 22}, rr.hands[0])
|
||||
|
||||
c := rr.DrawFromDeck()
|
||||
assert.EqualValues(t, Card(15), c)
|
||||
|
||||
rr.AddToHand(0, c)
|
||||
assert.EqualValues(t, []Card{50, 47, 24, 25, 22, 15}, rr.hands[0])
|
||||
|
||||
rr.Discard(0, 2)
|
||||
assert.EqualValues(t, []Card{50, 47, 15, 25, 22}, rr.hands[0])
|
||||
|
||||
assert.EqualValues(t, Card(24), rr.PeekFromDiscard())
|
||||
|
||||
c = rr.DrawFromDiscard()
|
||||
rr.AddToHand(0, c)
|
||||
assert.EqualValues(t, []Card{50, 47, 15, 25, 22, 24}, rr.hands[0])
|
||||
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ func MakeMultiGroups(hand []Card, wildface int) [][][]int {
|
||||
// If that uses up all cards, then early-exit
|
||||
anyUnpaired := false
|
||||
for cidx := 0; cidx < len(cloneHand); cidx++ {
|
||||
if cloneHand[cidx] != Card(-1) {
|
||||
if !cloneHand[cidx].Masked() {
|
||||
anyUnpaired = true
|
||||
break
|
||||
}
|
||||
|
40
strategy.go
40
strategy.go
@ -19,7 +19,7 @@ func (r *Round) PlayDefaultStrategy(currentPlayer int) {
|
||||
for cidx := 0; cidx < r.round; cidx++ {
|
||||
// Pick up the last discard card, and discard card@cidx
|
||||
theoretically := forkHand(r.hands[currentPlayer])
|
||||
theoretically[cidx] = r.discard[len(r.discard)-1]
|
||||
theoretically[cidx] = r.PeekFromDiscard()
|
||||
_, score := FindBestGrouping(theoretically, r.round)
|
||||
|
||||
if score < bestDiscardBasedScore {
|
||||
@ -27,6 +27,10 @@ func (r *Round) PlayDefaultStrategy(currentPlayer int) {
|
||||
bestDiscardBasedIdx = cidx
|
||||
bestDiscardBasedScore = score
|
||||
}
|
||||
|
||||
if score == 0 {
|
||||
break // Early exit
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -42,16 +46,15 @@ func (r *Round) PlayDefaultStrategy(currentPlayer int) {
|
||||
fmt.Printf("P%d discards %v immediately\n", currentPlayer, r.discard[len(r.discard)-1])
|
||||
|
||||
} else {
|
||||
// Take the discard card and discard cidx
|
||||
newCard := r.discard[len(r.discard)-1]
|
||||
r.discard = r.discard[0 : len(r.discard)-1]
|
||||
// Take the discard card
|
||||
newCard := r.DrawFromDiscard()
|
||||
|
||||
unwantedCard := r.hands[currentPlayer][bestDiscardBasedIdx]
|
||||
r.hands[currentPlayer][bestDiscardBasedIdx] = newCard
|
||||
r.AddToHand(currentPlayer, newCard)
|
||||
|
||||
r.discard = append(r.discard, unwantedCard) // On top = available for next player
|
||||
// Discard cidx
|
||||
|
||||
fmt.Printf("P%d discards %v (position %d)\n", currentPlayer, unwantedCard, bestDiscardBasedIdx)
|
||||
fmt.Printf("P%d discards %v (position %d)\n", currentPlayer, r.hands[currentPlayer][bestDiscardBasedIdx], bestDiscardBasedIdx)
|
||||
r.Discard(currentPlayer, bestDiscardBasedIdx)
|
||||
|
||||
}
|
||||
|
||||
@ -60,9 +63,8 @@ func (r *Round) PlayDefaultStrategy(currentPlayer int) {
|
||||
// score
|
||||
// Take from the deck
|
||||
|
||||
newCard := r.d[0]
|
||||
r.d = r.d[1:]
|
||||
r.hands[currentPlayer] = append(r.hands[currentPlayer], newCard)
|
||||
newCard := r.DrawFromDeck()
|
||||
r.AddToHand(currentPlayer, newCard)
|
||||
|
||||
fmt.Printf("P%d taking %v from the deck\n", currentPlayer, newCard)
|
||||
|
||||
@ -73,7 +75,7 @@ func (r *Round) PlayDefaultStrategy(currentPlayer int) {
|
||||
for cidx := 0; cidx < r.round+1; cidx++ {
|
||||
// Assume we discard that card,
|
||||
theoretically := forkHand(r.hands[currentPlayer])
|
||||
theoretically[cidx] = Card(-1) // Never matches + worth 0 points
|
||||
theoretically[cidx] = NewMasked() // Never matches + worth 0 points
|
||||
_, score := FindBestGrouping(theoretically, r.round)
|
||||
|
||||
if score < bestRandomBasedScore {
|
||||
@ -82,19 +84,15 @@ func (r *Round) PlayDefaultStrategy(currentPlayer int) {
|
||||
bestRandomBasedScore = score
|
||||
}
|
||||
|
||||
if score == 0 {
|
||||
break // Early exit
|
||||
}
|
||||
}
|
||||
|
||||
// Discard our chosen card
|
||||
// Slice tricks: Copy end card into this slot and reslice bounds
|
||||
|
||||
unwantedCard := r.hands[currentPlayer][bestRandomBasedIdx]
|
||||
|
||||
fmt.Printf("P%d discards %v (position %d)\n", currentPlayer, unwantedCard, bestRandomBasedIdx)
|
||||
|
||||
r.hands[currentPlayer][bestRandomBasedIdx] = r.hands[currentPlayer][len(r.hands[currentPlayer])-1]
|
||||
r.hands[currentPlayer] = r.hands[currentPlayer][0 : len(r.hands[currentPlayer])-1]
|
||||
|
||||
r.discard = append(r.discard, unwantedCard) // On top = available for next player
|
||||
fmt.Printf("P%d discards %v (position %d)\n", currentPlayer, r.hands[currentPlayer][bestRandomBasedIdx], bestRandomBasedIdx)
|
||||
r.Discard(currentPlayer, bestRandomBasedIdx)
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user