1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
|
package game
import (
"errors"
"fmt"
"math/rand"
"slices"
"strings"
)
type PileOfCards interface {
Size() int
IsEmpty() bool
Contains(*Card) bool
Cards() []*Card
FilterCards(func(*Card) bool) []*Card
AddCards(cards []*Card)
AddCard(card *Card)
RemoveCard(card *Card)
RandomCard() *Card
MoveCard(card *Card, into PileOfCards)
MoveInto(into PileOfCards)
ToList() string
String() string
}
type PileOfCardsBase struct {
cards []*Card
}
func NewPileOfCards() *PileOfCardsBase {
return &PileOfCardsBase{[]*Card{}}
}
// Stringify to a []-bracket enclosed comma-seperated list of card names.
func (poc *PileOfCardsBase) String() string {
cardNames := make([]string, 0, len(poc.Cards()))
for _, card := range poc.Cards() {
cardNames = append(cardNames, card.Path())
}
return fmt.Sprintf("[%s]", strings.Join(cardNames, ", "))
}
var ErrInvalidPocString = errors.New("invalid PileOfCards format")
// Initialise a PileOfCard from a string.
// Return InvalidPocString on error.
func (poc *PileOfCardsBase) FromString(in string) error {
if in[0] != '[' || in[len(in)-1] != ']' {
return ErrInvalidPocString
}
in = in[1 : len(in)-1]
for cardName := range strings.SplitSeq(in, ", ") {
if card, err := NewCardSafe(cardName); err != nil {
return err
} else {
poc.AddCard(card)
}
}
return nil
}
func (poc *PileOfCardsBase) Size() int {
return len(poc.cards)
}
func (poc *PileOfCardsBase) IsEmpty() bool {
return poc.Size() == 0
}
func (poc *PileOfCardsBase) Contains(card *Card) bool {
return slices.Contains(poc.cards, card)
}
func (poc *PileOfCardsBase) Cards() []*Card {
return poc.cards
}
func (poc *PileOfCardsBase) FilterCards(f func(*Card) bool) []*Card {
cards := []*Card{}
for _, c := range poc.Cards() {
if f(c) {
cards = append(cards, c)
}
}
return cards
}
func (poc *PileOfCardsBase) AddPoc(toAdd PileOfCards) {
poc.AddCards(toAdd.Cards())
}
func (poc *PileOfCardsBase) AddCards(cards []*Card) {
for _, card := range cards {
poc.AddCard(card)
}
}
func (poc *PileOfCardsBase) AddCard(card *Card) {
// Tokens can not be part of any pile of cards
if !card.IsToken() {
poc.cards = append(poc.cards, card)
}
}
func (poc *PileOfCardsBase) RemoveCard(card *Card) {
ncards := poc.Size()
for i, c := range poc.cards {
if c != card {
continue
}
poc.cards[i] = poc.cards[ncards-1]
poc.cards = poc.cards[:ncards-1]
return
}
}
func (poc *PileOfCardsBase) RandomCard() *Card {
availCards := poc.Cards()
var pick int
if n := len(availCards); n > 1 {
pick = rand.Intn(n - 1)
} else {
pick = 0
}
return availCards[pick]
}
func (poc *PileOfCardsBase) MoveCard(c *Card, into PileOfCards) {
poc.RemoveCard(c)
into.AddCard(c)
}
func (poc *PileOfCardsBase) MoveInto(into PileOfCards) {
into.AddCards(poc.cards)
poc.cards = []*Card{}
}
func (poc *PileOfCardsBase) ToList() (list string) {
m := make(map[string]int)
for _, card := range poc.cards {
path := card.Path()
m[path]++
}
for path, amount := range m {
list += fmt.Sprintf("%d %s\n", amount, path)
}
return list[:len(list)-1]
}
func NewRandomPackFromPool(pool PileOfCards, packSize int) PileOfCards {
pack := NewPileOfCards()
for range packSize {
card := pool.Cards()[rand.Intn(len(pool.Cards())-1)]
pool.MoveCard(card, pack)
}
return pack
}
|