Add RNG seed parameter to NewDeck
This commit is contained in:
parent
2c10757229
commit
96f4a21031
|
@ -1,5 +1,6 @@
|
|||
0.1.1:
|
||||
- Add Copy, Sort and Reverse methods to Cards
|
||||
- Add RNG seed parameter to NewDeck
|
||||
|
||||
0.1.0:
|
||||
- Initial release
|
||||
|
|
56
cards.go
56
cards.go
|
@ -5,6 +5,62 @@ import "sort"
|
|||
// Cards is a slice of Cards.
|
||||
type Cards []Card
|
||||
|
||||
// StandardCards is a slice of standard cards.
|
||||
var StandardCards = Cards{
|
||||
NewCard(FaceAce, SuitHearts),
|
||||
NewCard(Face2, SuitHearts),
|
||||
NewCard(Face3, SuitHearts),
|
||||
NewCard(Face4, SuitHearts),
|
||||
NewCard(Face5, SuitHearts),
|
||||
NewCard(Face6, SuitHearts),
|
||||
NewCard(Face7, SuitHearts),
|
||||
NewCard(Face8, SuitHearts),
|
||||
NewCard(Face9, SuitHearts),
|
||||
NewCard(Face10, SuitHearts),
|
||||
NewCard(FaceJack, SuitHearts),
|
||||
NewCard(FaceQueen, SuitHearts),
|
||||
NewCard(FaceKing, SuitHearts),
|
||||
NewCard(FaceAce, SuitDiamonds),
|
||||
NewCard(Face2, SuitDiamonds),
|
||||
NewCard(Face3, SuitDiamonds),
|
||||
NewCard(Face4, SuitDiamonds),
|
||||
NewCard(Face5, SuitDiamonds),
|
||||
NewCard(Face6, SuitDiamonds),
|
||||
NewCard(Face7, SuitDiamonds),
|
||||
NewCard(Face8, SuitDiamonds),
|
||||
NewCard(Face9, SuitDiamonds),
|
||||
NewCard(Face10, SuitDiamonds),
|
||||
NewCard(FaceJack, SuitDiamonds),
|
||||
NewCard(FaceQueen, SuitDiamonds),
|
||||
NewCard(FaceKing, SuitDiamonds),
|
||||
NewCard(FaceAce, SuitClubs),
|
||||
NewCard(Face2, SuitClubs),
|
||||
NewCard(Face3, SuitClubs),
|
||||
NewCard(Face4, SuitClubs),
|
||||
NewCard(Face5, SuitClubs),
|
||||
NewCard(Face6, SuitClubs),
|
||||
NewCard(Face7, SuitClubs),
|
||||
NewCard(Face8, SuitClubs),
|
||||
NewCard(Face9, SuitClubs),
|
||||
NewCard(Face10, SuitClubs),
|
||||
NewCard(FaceJack, SuitClubs),
|
||||
NewCard(FaceQueen, SuitClubs),
|
||||
NewCard(FaceKing, SuitClubs),
|
||||
NewCard(FaceAce, SuitSpades),
|
||||
NewCard(Face2, SuitSpades),
|
||||
NewCard(Face3, SuitSpades),
|
||||
NewCard(Face4, SuitSpades),
|
||||
NewCard(Face5, SuitSpades),
|
||||
NewCard(Face6, SuitSpades),
|
||||
NewCard(Face7, SuitSpades),
|
||||
NewCard(Face8, SuitSpades),
|
||||
NewCard(Face9, SuitSpades),
|
||||
NewCard(Face10, SuitSpades),
|
||||
NewCard(FaceJack, SuitSpades),
|
||||
NewCard(FaceQueen, SuitSpades),
|
||||
NewCard(FaceKing, SuitSpades),
|
||||
}
|
||||
|
||||
func (c Cards) Len() int {
|
||||
return len(c)
|
||||
}
|
||||
|
|
62
deck.go
62
deck.go
|
@ -1,68 +1,42 @@
|
|||
package cards
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ErrNotEnoughCards is the error returned when there aren't enough cards in
|
||||
// the deck to complete an action.
|
||||
var ErrNotEnoughCards = errors.New("not enough cards in deck")
|
||||
|
||||
// Deck defines a playing card deck containing any number of cards.
|
||||
type Deck struct {
|
||||
Cards Cards
|
||||
|
||||
r *rand.Rand
|
||||
}
|
||||
|
||||
// StandardDeck initializes a standard deck of 52 cards.
|
||||
func StandardDeck() *Deck {
|
||||
var d Deck
|
||||
|
||||
for _, suit := range StandardSuits {
|
||||
for _, face := range StandardFaces {
|
||||
d.Cards = append(d.Cards, NewCard(face, suit))
|
||||
}
|
||||
// NewDeck initializes a deck of the supplied cards. A seed value of 0 is
|
||||
// replaced with the current time in nanoseconds.
|
||||
func NewDeck(c Cards, seed int64) *Deck {
|
||||
if seed == 0 {
|
||||
seed = time.Now().UnixNano()
|
||||
}
|
||||
|
||||
return &d
|
||||
return &Deck{Cards: c.Copy(), r: rand.New(rand.NewSource(seed))}
|
||||
}
|
||||
|
||||
// Shuffle randomizes the deck.
|
||||
func (d *Deck) Shuffle(times int) error {
|
||||
if len(d.Cards) == 0 {
|
||||
return ErrNotEnoughCards
|
||||
func (d *Deck) Shuffle() {
|
||||
for i := range d.Cards {
|
||||
j := d.r.Intn(i + 1)
|
||||
d.Cards[i], d.Cards[j] = d.Cards[j], d.Cards[i]
|
||||
}
|
||||
|
||||
var old, shuffled Cards
|
||||
for shuf := times; shuf > 0; shuf-- {
|
||||
old = d.Cards
|
||||
shuffled = nil
|
||||
|
||||
for i := len(old); i > 0; i-- {
|
||||
nBig, e := rand.Int(rand.Reader, big.NewInt(int64(i)))
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
n := int(nBig.Int64())
|
||||
|
||||
shuffled = append(shuffled, old[n])
|
||||
old = old.Remove(n)
|
||||
}
|
||||
|
||||
d.Cards = shuffled
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Draw removes cards from the deck and returns them as a slice.
|
||||
func (d *Deck) Draw(count int) (cards Cards, err error) {
|
||||
func (d *Deck) Draw(count int) (cards Cards, ok bool) {
|
||||
if count > len(d.Cards) {
|
||||
return nil, ErrNotEnoughCards
|
||||
return nil, false
|
||||
}
|
||||
|
||||
hand := d.Cards[0:count]
|
||||
cards = d.Cards[0:count].Copy()
|
||||
d.Cards = d.Cards[count:]
|
||||
return hand, nil
|
||||
return cards, true
|
||||
}
|
||||
|
|
52
deck_test.go
52
deck_test.go
|
@ -4,8 +4,10 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
var deckTestCase = []int{1, 2, 13}
|
||||
|
||||
func TestDeck(t *testing.T) {
|
||||
d := StandardDeck()
|
||||
d := NewDeck(StandardCards, 0)
|
||||
|
||||
if len(d.Cards) != 52 {
|
||||
t.Errorf("expected 52 cards, got %d", len(d.Cards))
|
||||
|
@ -25,32 +27,38 @@ func TestDeck(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
var discard Cards
|
||||
for i := 0; i < 52; i++ {
|
||||
c, err := d.Draw(1)
|
||||
if err != nil || len(c) == 0 {
|
||||
t.Errorf("failed to draw card: %s", err)
|
||||
for _, draw := range deckTestCase {
|
||||
d = NewDeck(StandardCards, 0)
|
||||
var discard Cards
|
||||
|
||||
l := len(d.Cards) / draw
|
||||
for i := 0; i < l; i++ {
|
||||
c, ok := d.Draw(draw)
|
||||
if !ok {
|
||||
t.Errorf("failed to draw %d iteration %d", draw, i)
|
||||
} else if len(c) != draw {
|
||||
t.Errorf("failed to draw %d iteration %d: expected %d cards, got %d", draw, i, draw, len(c))
|
||||
}
|
||||
|
||||
discard = append(discard, c...)
|
||||
}
|
||||
|
||||
discard = append(discard, c[0])
|
||||
}
|
||||
if len(d.Cards) != 0 {
|
||||
t.Errorf("failed to draw %d: expected 0 cards after drawing, got %d", draw, len(d.Cards))
|
||||
}
|
||||
|
||||
if len(d.Cards) != 0 {
|
||||
t.Errorf("expected 0 cards after drawing, got %d", len(d.Cards))
|
||||
}
|
||||
|
||||
for _, suit := range StandardSuits {
|
||||
for _, face := range StandardFaces {
|
||||
found := 0
|
||||
for _, c := range discard {
|
||||
if c.Equal(NewCard(face, suit)) {
|
||||
found++
|
||||
for _, suit := range StandardSuits {
|
||||
for _, face := range StandardFaces {
|
||||
found := 0
|
||||
for _, c := range discard {
|
||||
if c.Equal(NewCard(face, suit)) {
|
||||
found++
|
||||
}
|
||||
}
|
||||
if found != 1 {
|
||||
t.Errorf("failed to draw %d: discard: expected 1 %s, got %d", draw, NewCard(face, suit), found)
|
||||
}
|
||||
}
|
||||
if found != 1 {
|
||||
t.Errorf("failed to draw 52 cards: expected 1 %s, got %d", NewCard(face, suit), found)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue