You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
543 lines
15 KiB
543 lines
15 KiB
package cribbage |
|
|
|
import ( |
|
"testing" |
|
|
|
. "code.rocketnine.space/tslocum/joker" |
|
) |
|
|
|
var ( |
|
testHandA = Cards{ |
|
Card{Face2, SuitSpades}, |
|
Card{Face3, SuitSpades}, |
|
Card{Face4, SuitSpades}, |
|
Card{Face5, SuitSpades}} |
|
testHandB = Cards{ |
|
Card{FaceJack, SuitHearts}, |
|
Card{Face5, SuitDiamonds}, |
|
Card{Face5, SuitClubs}, |
|
Card{Face5, SuitSpades}} |
|
testHandC = Cards{ |
|
Card{Face3, SuitHearts}, |
|
Card{Face3, SuitDiamonds}, |
|
Card{Face3, SuitClubs}, |
|
Card{Face3, SuitSpades}} |
|
testHandD = Cards{ |
|
Card{Face5, SuitHearts}, |
|
Card{Face5, SuitDiamonds}, |
|
Card{Face5, SuitClubs}, |
|
Card{Face5, SuitSpades}} |
|
testHandE = Cards{ |
|
Card{Face7, SuitHearts}, |
|
Card{Face8, SuitHearts}, |
|
Card{Face9, SuitHearts}, |
|
Card{Face10, SuitHearts}} |
|
testHandF = Cards{ |
|
Card{Face3, SuitHearts}, |
|
Card{Face6, SuitHearts}, |
|
Card{Face5, SuitHearts}, |
|
Card{Face4, SuitHearts}} |
|
testHandG = Cards{ |
|
Card{Face6, SuitHearts}, |
|
Card{Face5, SuitHearts}, |
|
Card{Face4, SuitHearts}} |
|
testHandH = Cards{ |
|
Card{FaceAce, SuitHearts}, |
|
Card{Face3, SuitHearts}, |
|
Card{Face2, SuitHearts}, |
|
Card{Face4, SuitHearts}} |
|
testHandI = Cards{ |
|
Card{FaceAce, SuitHearts}, |
|
Card{Face3, SuitHearts}, |
|
Card{FaceAce, SuitClubs}, |
|
Card{Face2, SuitHearts}, |
|
Card{Face4, SuitHearts}, |
|
Card{Face7, SuitHearts}} |
|
testHandJ = Cards{ |
|
Card{Face7, SuitHearts}, |
|
Card{Face3, SuitHearts}, |
|
Card{Face2, SuitHearts}, |
|
Card{Face4, SuitHearts}} |
|
testHandK = Cards{ |
|
Card{Face5, SuitHearts}, |
|
Card{Face5, SuitDiamonds}, |
|
Card{Face5, SuitClubs}, |
|
Card{FaceJack, SuitSpades}} |
|
testHandL = Cards{ |
|
Card{Face2, SuitHearts}, |
|
Card{Face2, SuitDiamonds}, |
|
Card{Face7, SuitClubs}, |
|
Card{Face7, SuitSpades}} |
|
testHandM = Cards{ |
|
Card{Face5, SuitHearts}, |
|
Card{Face5, SuitDiamonds}, |
|
Card{Face5, SuitClubs}, |
|
Card{FaceKing, SuitSpades}} |
|
) |
|
|
|
type expectedPegScore struct { |
|
Hand Cards |
|
|
|
Result []ScoreResult |
|
} |
|
|
|
var expectedPegScores = []expectedPegScore{ |
|
{testHandA, []ScoreResult{ |
|
{Type: ScoreRun, Points: 4, Cards: Cards{ |
|
Card{Face2, SuitSpades}, |
|
Card{Face3, SuitSpades}, |
|
Card{Face4, SuitSpades}, |
|
Card{Face5, SuitSpades}}}}}, |
|
{testHandB, []ScoreResult{ |
|
{Type: ScorePair, Points: 6, Cards: Cards{ |
|
Card{Face5, SuitDiamonds}, |
|
Card{Face5, SuitClubs}, |
|
Card{Face5, SuitSpades}}}}}, |
|
{testHandC, []ScoreResult{ |
|
{Type: ScorePair, Points: 12, Cards: Cards{ |
|
Card{Face3, SuitHearts}, |
|
Card{Face3, SuitDiamonds}, |
|
Card{Face3, SuitClubs}, |
|
Card{Face3, SuitSpades}}}}}, |
|
{testHandF, []ScoreResult{ |
|
{Type: ScoreRun, Points: 4, Cards: Cards{ |
|
Card{Face3, SuitHearts}, |
|
Card{Face4, SuitHearts}, |
|
Card{Face5, SuitHearts}, |
|
Card{Face6, SuitHearts}}}}}, |
|
{testHandG, []ScoreResult{ |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face4, SuitHearts}, |
|
Card{Face5, SuitHearts}, |
|
Card{Face6, SuitHearts}}}, |
|
{Type: ScoreRun, Points: 3, Cards: Cards{ |
|
Card{Face4, SuitHearts}, |
|
Card{Face5, SuitHearts}, |
|
Card{Face6, SuitHearts}}}}}, |
|
{testHandH, []ScoreResult{ |
|
{Type: ScoreRun, Points: 4, Cards: Cards{ |
|
Card{FaceAce, SuitHearts}, |
|
Card{Face2, SuitHearts}, |
|
Card{Face3, SuitHearts}, |
|
Card{Face4, SuitHearts}}}}}, |
|
{testHandI, []ScoreResult{}}, |
|
{testHandJ, []ScoreResult{ |
|
{Type: ScoreRun, Points: 3}}}, |
|
{testHandK, []ScoreResult{}}, |
|
{testHandL, []ScoreResult{ |
|
{Type: ScorePair, Points: 2, Cards: Cards{ |
|
Card{Face7, SuitClubs}, |
|
Card{Face7, SuitSpades}}}}}, |
|
{testHandM, []ScoreResult{}}, |
|
} |
|
|
|
type expectedShowScore struct { |
|
Starter Card |
|
Hand Cards |
|
|
|
HandResult []ScoreResult |
|
CribResult []ScoreResult |
|
} |
|
|
|
var expectedShowScores = []expectedShowScore{ |
|
{Card{FaceAce, SuitSpades}, |
|
testHandA, []ScoreResult{ |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{FaceAce, SuitSpades}, |
|
Card{Face2, SuitSpades}, |
|
Card{Face3, SuitSpades}, |
|
Card{Face4, SuitSpades}, |
|
Card{Face5, SuitSpades}}}, |
|
{Type: ScoreRun, Points: 5, Cards: Cards{ |
|
Card{FaceAce, SuitSpades}, |
|
Card{Face2, SuitSpades}, |
|
Card{Face3, SuitSpades}, |
|
Card{Face4, SuitSpades}, |
|
Card{Face5, SuitSpades}}}, |
|
{Type: ScoreFlush, Points: 5, Cards: Cards{ |
|
Card{FaceAce, SuitSpades}, |
|
Card{Face2, SuitSpades}, |
|
Card{Face3, SuitSpades}, |
|
Card{Face4, SuitSpades}, |
|
Card{Face5, SuitSpades}}}, |
|
}, []ScoreResult{ |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{FaceAce, SuitSpades}, |
|
Card{Face2, SuitSpades}, |
|
Card{Face3, SuitSpades}, |
|
Card{Face4, SuitSpades}, |
|
Card{Face5, SuitSpades}}}, |
|
{Type: ScoreRun, Points: 5, Cards: Cards{ |
|
Card{FaceAce, SuitSpades}, |
|
Card{Face2, SuitSpades}, |
|
Card{Face3, SuitSpades}, |
|
Card{Face4, SuitSpades}, |
|
Card{Face5, SuitSpades}}}, |
|
{Type: ScoreFlush, Points: 5, Cards: Cards{ |
|
Card{FaceAce, SuitSpades}, |
|
Card{Face2, SuitSpades}, |
|
Card{Face3, SuitSpades}, |
|
Card{Face4, SuitSpades}, |
|
Card{Face5, SuitSpades}}}, |
|
}}, |
|
|
|
{Card{FaceKing, SuitClubs}, |
|
testHandA, []ScoreResult{ |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitSpades}, |
|
Card{FaceKing, SuitClubs}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face2, SuitSpades}, |
|
Card{Face3, SuitSpades}, |
|
Card{FaceKing, SuitClubs}}}, |
|
{Type: ScoreRun, Points: 4, Cards: Cards{ |
|
Card{Face2, SuitSpades}, |
|
Card{Face3, SuitSpades}, |
|
Card{Face4, SuitSpades}, |
|
Card{Face5, SuitSpades}}}, |
|
{Type: ScoreFlush, Points: 4, Cards: Cards{ |
|
Card{Face2, SuitSpades}, |
|
Card{Face3, SuitSpades}, |
|
Card{Face4, SuitSpades}, |
|
Card{Face5, SuitSpades}}}, |
|
}, []ScoreResult{ |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitSpades}, |
|
Card{FaceKing, SuitClubs}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face2, SuitSpades}, |
|
Card{Face3, SuitSpades}, |
|
Card{FaceKing, SuitClubs}}}, |
|
{Type: ScoreRun, Points: 4, Cards: Cards{ |
|
Card{Face2, SuitSpades}, |
|
Card{Face3, SuitSpades}, |
|
Card{Face4, SuitSpades}, |
|
Card{Face5, SuitSpades}}}, |
|
}}, |
|
|
|
{Card{Face8, SuitClubs}, |
|
testHandE, []ScoreResult{ |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face7, SuitHearts}, |
|
Card{Face8, SuitHearts}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face7, SuitHearts}, |
|
Card{Face8, SuitClubs}}}, |
|
{Type: ScorePair, Points: 2, Cards: Cards{ |
|
Card{Face8, SuitHearts}, |
|
Card{Face8, SuitClubs}}}, |
|
{Type: ScoreRun, Points: 4, Cards: Cards{ |
|
Card{Face7, SuitHearts}, |
|
Card{Face8, SuitHearts}, |
|
Card{Face9, SuitHearts}, |
|
Card{Face10, SuitHearts}}}, |
|
{Type: ScoreRun, Points: 4, Cards: Cards{ |
|
Card{Face7, SuitHearts}, |
|
Card{Face8, SuitClubs}, |
|
Card{Face9, SuitHearts}, |
|
Card{Face10, SuitHearts}}}, |
|
{Type: ScoreFlush, Points: 4, Cards: Cards{ |
|
Card{Face7, SuitHearts}, |
|
Card{Face8, SuitHearts}, |
|
Card{Face9, SuitHearts}, |
|
Card{Face10, SuitHearts}}}, |
|
}, []ScoreResult{ |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face7, SuitHearts}, |
|
Card{Face8, SuitHearts}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face7, SuitHearts}, |
|
Card{Face8, SuitClubs}}}, |
|
{Type: ScorePair, Points: 2, Cards: Cards{ |
|
Card{Face8, SuitHearts}, |
|
Card{Face8, SuitClubs}}}, |
|
{Type: ScoreRun, Points: 4, Cards: Cards{ |
|
Card{Face7, SuitHearts}, |
|
Card{Face8, SuitHearts}, |
|
Card{Face9, SuitHearts}, |
|
Card{Face10, SuitHearts}}}, |
|
{Type: ScoreRun, Points: 4, Cards: Cards{ |
|
Card{Face7, SuitHearts}, |
|
Card{Face8, SuitClubs}, |
|
Card{Face9, SuitHearts}, |
|
Card{Face10, SuitHearts}}}, |
|
}}, |
|
|
|
{Card{Face5, SuitSpades}, |
|
testHandK, []ScoreResult{ |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitHearts}, |
|
Card{FaceJack, SuitSpades}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitDiamonds}, |
|
Card{FaceJack, SuitSpades}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitClubs}, |
|
Card{FaceJack, SuitSpades}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitSpades}, |
|
Card{FaceJack, SuitSpades}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitHearts}, |
|
Card{Face5, SuitDiamonds}, |
|
Card{Face5, SuitClubs}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitHearts}, |
|
Card{Face5, SuitDiamonds}, |
|
Card{Face5, SuitSpades}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitHearts}, |
|
Card{Face5, SuitClubs}, |
|
Card{Face5, SuitSpades}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitDiamonds}, |
|
Card{Face5, SuitClubs}, |
|
Card{Face5, SuitSpades}}}, |
|
{Type: ScorePair, Points: 12, Cards: Cards{ |
|
Card{Face5, SuitHearts}, |
|
Card{Face5, SuitDiamonds}, |
|
Card{Face5, SuitClubs}, |
|
Card{Face5, SuitSpades}}}, |
|
{Type: ScoreNobs, Points: 1, Cards: Cards{ |
|
Card{FaceJack, SuitSpades}}}, |
|
}, []ScoreResult{ |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitHearts}, |
|
Card{FaceJack, SuitSpades}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitDiamonds}, |
|
Card{FaceJack, SuitSpades}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitClubs}, |
|
Card{FaceJack, SuitSpades}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitSpades}, |
|
Card{FaceJack, SuitSpades}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitHearts}, |
|
Card{Face5, SuitDiamonds}, |
|
Card{Face5, SuitClubs}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitHearts}, |
|
Card{Face5, SuitDiamonds}, |
|
Card{Face5, SuitSpades}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitHearts}, |
|
Card{Face5, SuitClubs}, |
|
Card{Face5, SuitSpades}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitDiamonds}, |
|
Card{Face5, SuitClubs}, |
|
Card{Face5, SuitSpades}}}, |
|
{Type: ScorePair, Points: 12, Cards: Cards{ |
|
Card{Face5, SuitHearts}, |
|
Card{Face5, SuitDiamonds}, |
|
Card{Face5, SuitClubs}, |
|
Card{Face5, SuitSpades}}}, |
|
{Type: ScoreNobs, Points: 1, Cards: Cards{ |
|
Card{FaceJack, SuitSpades}}}, |
|
}}, |
|
|
|
{Card{Face5, SuitSpades}, |
|
testHandM, []ScoreResult{ |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitHearts}, |
|
Card{FaceKing, SuitSpades}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitDiamonds}, |
|
Card{FaceKing, SuitSpades}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitClubs}, |
|
Card{FaceKing, SuitSpades}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitSpades}, |
|
Card{FaceKing, SuitSpades}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitHearts}, |
|
Card{Face5, SuitDiamonds}, |
|
Card{Face5, SuitClubs}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitHearts}, |
|
Card{Face5, SuitDiamonds}, |
|
Card{Face5, SuitSpades}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitHearts}, |
|
Card{Face5, SuitClubs}, |
|
Card{Face5, SuitSpades}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitDiamonds}, |
|
Card{Face5, SuitClubs}, |
|
Card{Face5, SuitSpades}}}, |
|
{Type: ScorePair, Points: 12, Cards: Cards{ |
|
Card{Face5, SuitHearts}, |
|
Card{Face5, SuitDiamonds}, |
|
Card{Face5, SuitClubs}, |
|
Card{Face5, SuitSpades}}}, |
|
}, []ScoreResult{ |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitHearts}, |
|
Card{FaceKing, SuitSpades}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitDiamonds}, |
|
Card{FaceKing, SuitSpades}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitClubs}, |
|
Card{FaceKing, SuitSpades}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitSpades}, |
|
Card{FaceKing, SuitSpades}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitHearts}, |
|
Card{Face5, SuitDiamonds}, |
|
Card{Face5, SuitClubs}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitHearts}, |
|
Card{Face5, SuitDiamonds}, |
|
Card{Face5, SuitSpades}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitHearts}, |
|
Card{Face5, SuitClubs}, |
|
Card{Face5, SuitSpades}}}, |
|
{Type: Score15, Points: 2, Cards: Cards{ |
|
Card{Face5, SuitDiamonds}, |
|
Card{Face5, SuitClubs}, |
|
Card{Face5, SuitSpades}}}, |
|
{Type: ScorePair, Points: 12, Cards: Cards{ |
|
Card{Face5, SuitHearts}, |
|
Card{Face5, SuitDiamonds}, |
|
Card{Face5, SuitClubs}, |
|
Card{Face5, SuitSpades}}}, |
|
}}, |
|
} |
|
|
|
func TestScorePeg(t *testing.T) { |
|
t.Parallel() |
|
|
|
for i, expected := range expectedPegScores { |
|
if Sum(expected.Hand) > 31 { |
|
t.Errorf("case %d: invalid peg hand sum: got %d, want <=31: %s", i, Sum(expected.Hand), expected.Hand) |
|
} |
|
|
|
pegPoints, pegResult := Score(Peg, expected.Hand, Card{}) |
|
|
|
if !resultsEqual(pegResult, expected.Result) { |
|
t.Fatalf("case %d: incorrect peg result: got %s, want %s: %s", i, pegResult, expected.Result, expected.Hand) |
|
} |
|
|
|
var expectedPoints int |
|
for _, r := range expected.Result { |
|
expectedPoints += r.Points |
|
} |
|
if pegPoints != expectedPoints { |
|
t.Fatalf("case %d: incorrect peg score: got %d, want %d: %s", i, pegPoints, expectedPoints, expected.Hand) |
|
} |
|
} |
|
} |
|
|
|
func TestScoreShowHand(t *testing.T) { |
|
t.Parallel() |
|
|
|
var expectedPoints int |
|
for i, expected := range expectedShowScores { |
|
handPoints, handResult := Score(ShowHand, expected.Hand, expected.Starter) |
|
|
|
if !resultsEqual(handResult, expected.HandResult) { |
|
t.Fatalf("case %d: incorrect hand result: got %s, want %s: %s - %s", i, handResult, expected.HandResult, expected.Starter, expected.Hand) |
|
} |
|
|
|
expectedPoints = 0 |
|
for _, r := range expected.HandResult { |
|
expectedPoints += r.Points |
|
} |
|
if handPoints != expectedPoints { |
|
t.Fatalf("case %d: incorrect hand score: got %d, want %d: %s - %s", i, handPoints, expectedPoints, expected.Starter, expected.Hand) |
|
} |
|
} |
|
} |
|
|
|
func TestScoreShowCrib(t *testing.T) { |
|
t.Parallel() |
|
|
|
var expectedPoints int |
|
for i, expected := range expectedShowScores { |
|
cribPoints, cribResult := Score(ShowCrib, expected.Hand, expected.Starter) |
|
|
|
if !resultsEqual(cribResult, expected.CribResult) { |
|
t.Fatalf("case %d: incorrect crib result: got %s, want %s: %s - %s", i, cribResult, expected.CribResult, expected.Starter, expected.Hand) |
|
} |
|
|
|
expectedPoints = 0 |
|
for _, r := range expected.CribResult { |
|
expectedPoints += r.Points |
|
} |
|
if cribPoints != expectedPoints { |
|
t.Fatalf("case %d: incorrect crib score: got %d, want %d: %s - %s", i, cribPoints, expectedPoints, expected.Starter, expected.Hand) |
|
} |
|
} |
|
} |
|
|
|
func BenchmarkScorePeg(b *testing.B) { |
|
var ( |
|
score int |
|
results ScoreResults |
|
) |
|
b.ResetTimer() |
|
for i := 0; i < b.N; i++ { |
|
for _, expected := range expectedPegScores { |
|
score, results = Score(Peg, expected.Hand, Card{}) |
|
} |
|
} |
|
_, _ = score, results |
|
} |
|
|
|
func BenchmarkScoreShowHand(b *testing.B) { |
|
var ( |
|
score int |
|
results ScoreResults |
|
) |
|
b.ResetTimer() |
|
for i := 0; i < b.N; i++ { |
|
for _, expected := range expectedShowScores { |
|
score, results = Score(ShowHand, expected.Hand, expected.Starter) |
|
} |
|
} |
|
_, _ = score, results |
|
} |
|
|
|
func BenchmarkScoreShowCrib(b *testing.B) { |
|
var ( |
|
score int |
|
results ScoreResults |
|
) |
|
b.ResetTimer() |
|
for i := 0; i < b.N; i++ { |
|
for _, expected := range expectedShowScores { |
|
score, results = Score(ShowCrib, expected.Hand, expected.Starter) |
|
} |
|
} |
|
_, _ = score, results |
|
} |
|
|
|
func resultsEqual(a []ScoreResult, b []ScoreResult) bool { |
|
if len(a) != len(b) { |
|
return false |
|
} |
|
|
|
for i := range a { |
|
if a[i].Type != b[i].Type { |
|
return false |
|
} else if a[i].Points != b[i].Points { |
|
return false |
|
} else if len(a[i].Cards) != len(b[i].Cards) { |
|
return false |
|
} |
|
|
|
for j := range a[i].Cards { |
|
if !a[i].Cards[j].Equal(b[i].Cards[j]) { |
|
return false |
|
} |
|
} |
|
} |
|
|
|
return true |
|
}
|
|
|