aboutsummaryrefslogtreecommitdiff
path: root/go/game/pileOfCards.go
blob: 88a3c750c6e091aa6ed1b27bc75d99b33c30851a (plain)
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
package game

import (
	"errors"
	"fmt"
	"math/rand"
	"strings"

	"golang.org/x/exp/slices"
)

type PileOfCards interface {
	Size() int
	IsEmpty() bool
	Contains(*Card) bool
	Cards() []*Card
	AddCards(cards []*Card)
	AddCard(card *Card)
	RemoveCard(card *Card)
	MoveCard(card *Card, into PileOfCards)
	MoveInto(into PileOfCards)
	ToList() 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 InvalidPocString = 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 InvalidPocString
	}

	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) 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) 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
}