Browse Source

Add Copy, Sort and Reverse methods to Cards

master
Trevor Slocum 3 years ago
parent
commit
2c10757229
  1. 3
      CHANGELOG
  2. 77
      card.go
  3. 80
      card_face.go
  4. 72
      card_suit.go
  5. 33
      cards.go
  6. 67
      cards_test.go
  7. 6
      deck.go

3
CHANGELOG

@ -1,2 +1,5 @@
0.1.1:
- Add Copy, Sort and Reverse methods to Cards
0.1.0:
- Initial release

77
card.go

@ -7,6 +7,9 @@ import (
"strings"
)
// Invalid is the text shown when a valid face or suit is not found.
const Invalid = "?"
// Card defines a playing card with a face and suit.
type Card struct {
Face CardFace
@ -20,76 +23,56 @@ func NewCard(face CardFace, suit CardSuit) Card {
// Value returns the numeric value of a card.
func (c Card) Value() int {
return (c.Face.Value * 100) + c.Suit.Value
return (int(c.Face) * 100) + int(c.Suit)
}
// Equal returns whether both cards have the same face and suit.
func (c Card) Equal(b Card) bool {
return c.EqualFace(b) && c.EqualSuit(b)
}
// EqualFace returns whether both cards have the same face.
func (c Card) EqualFace(b Card) bool {
return c.Face.Value == b.Face.Value
}
// EqualSuit returns whether both cards have the same suit.
func (c Card) EqualSuit(b Card) bool {
return c.Suit.Value == b.Suit.Value
}
// GreaterFace returns whether Card c has greater face value than Card b.
func (c Card) GreaterFace(b Card) bool {
return c.Face.Value > b.Face.Value
}
// LessFace returns whether Card c has less face value than Card b.
func (c Card) LessFace(b Card) bool {
return c.Face.Value < b.Face.Value
return b.Face == c.Face && b.Suit == c.Suit
}
// String returns a human-readable string representation of a Card.
func (c Card) String() string {
var cardFace string
if c.Face.Value == 14 {
cardFace = "! "
} else {
cardFace = fmt.Sprintf("%c", c.Face.Name[0])
if c.Face.Value == 10 {
cardFace += "0"
} else {
cardFace += " "
}
}
return fmt.Sprintf("[%s %s %c]", cardFace, c.Suit.Symbol, c.Suit.Name[0])
}
// Identifier returns a 2-3 character machine-readable representation of a card.
// Identifier returns a machine-readable representation of a card.
func (c Card) Identifier() string {
if c.Face.Value == 0 || c.Suit.Value == 0 {
if c.Suit.Name() == Invalid || c.Suit.Name() == Invalid {
return "??"
}
var faceidentifier string
if c.Face.Value == FaceJoker.Value {
if c.Face == FaceJoker {
faceidentifier = "!"
} else if c.Face.Value == Face10.Value {
faceidentifier = c.Face.Name
} else if c.Face == Face10 {
faceidentifier = c.Face.Name()
} else {
faceidentifier = string(c.Face.Name[0])
faceidentifier = string(c.Face.Name()[0])
}
var suitidentifier string
if c.Suit.Value == SuitJoker.Value {
if c.Suit == SuitJoker {
suitidentifier = "!"
} else {
suitidentifier = c.Suit.Name[0:1]
suitidentifier = c.Suit.Name()[0:1]
}
return strings.ToUpper(faceidentifier + suitidentifier)
}
// String returns a human-readable representation of a Card.
func (c Card) String() string {
var cardFace string
if c.Face == 14 {
cardFace = "! "
} else {
cardFace = c.Face.Name()[0:1]
if c.Face == 10 {
cardFace += "0"
} else {
cardFace += " "
}
}
return fmt.Sprintf("[%s %s %c]", cardFace, c.Suit.Symbol(), c.Suit.Name()[0])
}
// MarshalJSON marshals a Card.
func (c Card) MarshalJSON() ([]byte, error) {
return json.Marshal(c.Identifier())

80
card_face.go

@ -1,27 +1,24 @@
package cards
// CardFace defines a card face name and numeric value.
type CardFace struct {
Name string
Value int
}
// CardFace defines a card face.
type CardFace int
// Card faces:
var (
FaceAce = CardFace{"Ace", 1}
Face2 = CardFace{"2", 2}
Face3 = CardFace{"3", 3}
Face4 = CardFace{"4", 4}
Face5 = CardFace{"5", 5}
Face6 = CardFace{"6", 6}
Face7 = CardFace{"7", 7}
Face8 = CardFace{"8", 8}
Face9 = CardFace{"9", 9}
Face10 = CardFace{"10", 10}
FaceJack = CardFace{"Jack", 11}
FaceQueen = CardFace{"Queen", 12}
FaceKing = CardFace{"King", 13}
FaceJoker = CardFace{"Joker", 14}
// Card faces
const (
FaceAce CardFace = 1
Face2 CardFace = 2
Face3 CardFace = 3
Face4 CardFace = 4
Face5 CardFace = 5
Face6 CardFace = 6
Face7 CardFace = 7
Face8 CardFace = 8
Face9 CardFace = 9
Face10 CardFace = 10
FaceJack CardFace = 11
FaceQueen CardFace = 12
FaceKing CardFace = 13
FaceJoker CardFace = 14
)
// StandardFaces is a slice of all faces except Jokers.
@ -58,3 +55,44 @@ var AllFaces = []CardFace{
FaceKing,
FaceJoker,
}
// Name returns the card face name.
func (f CardFace) Name() string {
switch f {
case FaceAce:
return "Ace"
case Face2:
return "2"
case Face3:
return "3"
case Face4:
return "4"
case Face5:
return "5"
case Face6:
return "6"
case Face7:
return "7"
case Face8:
return "8"
case Face9:
return "9"
case Face10:
return "10"
case FaceJack:
return "Jack"
case FaceQueen:
return "Queen"
case FaceKing:
return "King"
case FaceJoker:
return "Joker"
default:
return Invalid
}
}
// String returns the card face name.
func (f CardFace) String() string {
return f.Name()
}

72
card_suit.go

@ -1,19 +1,15 @@
package cards
// CardSuit defines a card suit name, symbol and numeric value.
type CardSuit struct {
Name string
Symbol string
Value int
}
// CardSuit defines a card suit.
type CardSuit int
// Card suits:
var (
SuitHearts = CardSuit{"Hearts", "♥", 1}
SuitDiamonds = CardSuit{"Diamonds", "♦", 2}
SuitClubs = CardSuit{"Clubs", "♣", 3}
SuitSpades = CardSuit{"Spades", "♠", 4}
SuitJoker = CardSuit{"Joker", "!", 5}
// Card suits
const (
SuitHearts CardSuit = 1
SuitDiamonds CardSuit = 2
SuitClubs CardSuit = 3
SuitSpades CardSuit = 4
SuitJoker CardSuit = 5
)
// StandardSuits is a slice of all card suits except Jokers.
@ -32,3 +28,53 @@ var AllSuits = []CardSuit{
SuitSpades,
SuitJoker,
}
// Card symbols
const (
SymbolHearts = "♥"
SymbolDiamonds = "♦"
SymbolClubs = "♣"
SymbolSpades = "♠"
SymbolJoker = "!"
)
// Symbol returns the card suit symbol.
func (s CardSuit) Symbol() string {
switch s {
case SuitHearts:
return SymbolHearts
case SuitDiamonds:
return SymbolDiamonds
case SuitClubs:
return SymbolClubs
case SuitSpades:
return SymbolSpades
case SuitJoker:
return SymbolJoker
default:
return Invalid
}
}
// Name returns the card suit name.
func (s CardSuit) Name() string {
switch s {
case SuitHearts:
return "Hearts"
case SuitDiamonds:
return "Diamonds"
case SuitClubs:
return "Clubs"
case SuitSpades:
return "Spades"
case SuitJoker:
return "Joker"
default:
return Invalid
}
}
// String returns the card suit name.
func (s CardSuit) String() string {
return s.Name()
}

33
cards.go

@ -1,5 +1,7 @@
package cards
import "sort"
// Cards is a slice of Cards.
type Cards []Card
@ -15,7 +17,32 @@ func (c Cards) Less(i, j int) bool {
return c[i].Value() < c[j].Value()
}
// Remove returns a slice of Cards excluding the specified card.
func (c Cards) Remove(i int64) Cards {
return append(c[:i], c[i+1:]...)
// Copy returns a copy of the supplied cards.
func (c Cards) Copy() Cards {
cc := make(Cards, len(c))
copy(cc, c)
return cc
}
// Sort returns the supplied cards in order.
func (c Cards) Sort() Cards {
cc := c.Copy()
sort.Sort(cc)
return cc
}
// Reverse returns the supplied cards in reverse order.
func (c Cards) Reverse() Cards {
l := len(c)
cc := make(Cards, l)
for i := 0; i < l; i++ {
cc[i] = c[l-i-1]
}
return cc
}
// Remove returns the supplied cards excluding the card at the specified index.
func (c Cards) Remove(i int) Cards {
cc := c.Copy()
return append(cc[:i], cc[i+1:]...)
}

67
cards_test.go

@ -0,0 +1,67 @@
package cards
import (
"reflect"
"testing"
)
type cardsTestCase struct {
Cards Cards
Reversed Cards
RemovedFirst Cards
RemovedLast Cards
Sorted Cards
}
var cardsTestCases = []*cardsTestCase{
{
Cards: Cards{NewCard(FaceAce, SuitHearts), NewCard(Face4, SuitDiamonds), NewCard(Face2, SuitClubs), NewCard(Face3, SuitSpades)},
Reversed: Cards{NewCard(Face3, SuitSpades), NewCard(Face2, SuitClubs), NewCard(Face4, SuitDiamonds), NewCard(FaceAce, SuitHearts)},
RemovedFirst: Cards{NewCard(Face4, SuitDiamonds), NewCard(Face2, SuitClubs), NewCard(Face3, SuitSpades)},
RemovedLast: Cards{NewCard(FaceAce, SuitHearts), NewCard(Face4, SuitDiamonds), NewCard(Face2, SuitClubs)},
Sorted: Cards{NewCard(FaceAce, SuitHearts), NewCard(Face2, SuitClubs), NewCard(Face3, SuitSpades), NewCard(Face4, SuitDiamonds)},
},
{
Cards: Cards{NewCard(Face2, SuitClubs), NewCard(Face4, SuitSpades)},
Reversed: Cards{NewCard(Face4, SuitSpades), NewCard(Face2, SuitClubs)},
RemovedFirst: Cards{NewCard(Face4, SuitSpades)},
RemovedLast: Cards{NewCard(Face2, SuitClubs)},
Sorted: Cards{NewCard(Face2, SuitClubs), NewCard(Face4, SuitSpades)},
},
{
Cards: Cards{NewCard(FaceQueen, SuitHearts)},
Reversed: Cards{NewCard(FaceQueen, SuitHearts)},
RemovedFirst: Cards{},
RemovedLast: Cards{},
Sorted: Cards{NewCard(FaceQueen, SuitHearts)},
},
}
func TestCards(t *testing.T) {
for _, c := range cardsTestCases {
copied := c.Cards.Copy()
if !reflect.DeepEqual(copied, c.Cards) {
t.Errorf("failed to copy cards: expected %s, got %s", c.Cards, copied)
}
reversed := c.Cards.Reverse()
if !reflect.DeepEqual(reversed, c.Reversed) {
t.Errorf("failed to reverse cards: expected %s, got %s", c.Reversed, reversed)
}
removedFirst := c.Cards.Remove(0)
if !reflect.DeepEqual(removedFirst, c.RemovedFirst) {
t.Errorf("failed to remove first card: expected %s, got %s", c.RemovedFirst, removedFirst)
}
removedLast := c.Cards.Remove(len(c.Cards) - 1)
if !reflect.DeepEqual(removedLast, c.RemovedLast) {
t.Errorf("failed to remove first card: expected %s, got %s", c.RemovedLast, removedLast)
}
sorted := c.Cards.Sort()
if !reflect.DeepEqual(sorted, c.Sorted) {
t.Errorf("failed to sort cards: expected %s, got %s", c.Sorted, sorted)
}
}
}

6
deck.go

@ -44,10 +44,10 @@ func (d *Deck) Shuffle(times int) error {
if e != nil {
panic(e)
}
j := nBig.Int64()
n := int(nBig.Int64())
shuffled = append(shuffled, old[j])
old = old.Remove(j)
shuffled = append(shuffled, old[n])
old = old.Remove(n)
}
d.Cards = shuffled

Loading…
Cancel
Save