aboutsummaryrefslogtreecommitdiff
path: root/internal/casino/craps_review_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/casino/craps_review_test.go')
-rw-r--r--internal/casino/craps_review_test.go119
1 files changed, 118 insertions, 1 deletions
diff --git a/internal/casino/craps_review_test.go b/internal/casino/craps_review_test.go
index 04f72b2..3a518fc 100644
--- a/internal/casino/craps_review_test.go
+++ b/internal/casino/craps_review_test.go
@@ -1,6 +1,123 @@
package casino
-import "testing"
+import (
+ "strings"
+ "testing"
+)
+
+func TestCrapsPointPromptOnlyForPassBettors(t *testing.T) {
+ tb := crapsFixture()
+ tb.join("alice") // shooter
+ tb.join("bob")
+ w := &testWallet{chips: 1000}
+ tb.bet("alice", "pass", 10, w)
+ tb.bet("bob", "field", 10, w)
+ events := tb.resolveRoll(2, 2) // establishes point 4
+ publicPoint := false
+ var privateTo []string
+ for _, e := range events {
+ if e.Public && strings.Contains(e.Message, "POINT 4") {
+ publicPoint = true
+ if strings.Contains(e.Message, "Make your point") {
+ t.Fatalf("public point event still urges the whole room: %q", e.Message)
+ }
+ }
+ if e.PrivateTo != "" && strings.Contains(e.Message, "Make your point") {
+ privateTo = append(privateTo, e.PrivateTo)
+ }
+ }
+ if !publicPoint {
+ t.Fatal("no public point event")
+ }
+ if len(privateTo) != 1 || privateTo[0] != "alice" {
+ t.Fatalf("Make your point targeted %v, want [alice]", privateTo)
+ }
+}
+
+func TestCrapsVigOnlyOnWinsRoundedDown(t *testing.T) {
+ buy := &crapsBet{kind: "buy", number: 4, stake: Wager{Total: 20}}
+ if got := crapsReturn(buy, 2, 1, 0, false); got != 59 {
+ t.Fatalf("winning buy = %d, want 59", got)
+ }
+ if got := crapsReturn(buy, -1, 1, 0, false); got != 0 {
+ t.Fatalf("losing buy returned %d, want 0", got)
+ }
+ // A directly-constructed odd stake proves the vig rounds down, not up:
+ // 5% of 21 is 1.05, so the house keeps 1 credit, not 2.
+ odd := &crapsBet{kind: "buy", number: 4, stake: Wager{Total: 21}}
+ if got := crapsReturn(odd, 2, 1, 0, false); got != 62 { // 21 + 42 - 1
+ t.Fatalf("buy vig rounded up: %d, want 62", got)
+ }
+}
+
+func TestCrapsVigUnitsRoundUp(t *testing.T) {
+ for _, tc := range []struct {
+ kind string
+ n int
+ want int
+ }{
+ {"buy", 4, 20}, {"buy", 6, 20},
+ {"lay", 4, 40}, {"lay", 5, 30}, {"lay", 6, 24},
+ {"lay", 2, 120}, {"lay", 3, 60}, {"lay", 12, 120},
+ } {
+ if got := crapsVigUnit(tc.kind, tc.n); got != tc.want {
+ t.Fatalf("%s %d unit = %d, want %d", tc.kind, tc.n, got, tc.want)
+ }
+ }
+ for _, tc := range []struct {
+ spot string
+ amount int
+ want int
+ }{
+ {"buy 6", 3, 20}, {"buy 6", 5, 20}, {"buy 6", 20, 20},
+ {"buy 4", 3, 20}, {"buy 4", 21, 40},
+ {"lay 6", 30, 48}, {"lay 6", 24, 24},
+ } {
+ tb := crapsFixture()
+ tb.point = 6
+ tb.join("a")
+ w := &testWallet{chips: 1000}
+ events := tb.bet("a", tc.spot, tc.amount, w)
+ bets := tb.players.get("a").bets
+ if len(bets) != 1 {
+ t.Fatalf("%s %d was rejected", tc.spot, tc.amount)
+ }
+ if got := bets[0].stake.Total; got != tc.want {
+ t.Fatalf("%s %d rounded to %d, want %d", tc.spot, tc.amount, got, tc.want)
+ }
+ if tc.amount != tc.want {
+ notice := false
+ for _, e := range events {
+ if e.PrivateTo == "a" && strings.Contains(e.PrivateMessage, "Rounded up") {
+ notice = true
+ }
+ }
+ if !notice {
+ t.Fatalf("%s %d rounded without a notice", tc.spot, tc.amount)
+ }
+ }
+ }
+}
+
+func TestCrapsBusyHoldsAcrossPendingRoll(t *testing.T) {
+ tb := crapsFixture()
+ tb.join("alice")
+ tb.bet("alice", "pass", 10, &testWallet{chips: 100})
+ if tb.busy("alice") || tb.busy("bob") {
+ t.Fatal("table busy before a roll")
+ }
+ tb.action("alice", "roll")
+ if !tb.busy("alice") {
+ t.Fatal("shooter not busy while the dice are in the air")
+ }
+ if tb.busy("bob") {
+ t.Fatal("non-shooter marked busy")
+ }
+ tb.advance(crapsManualRollTicks)
+ if tb.busy("alice") {
+ t.Fatal("still busy after the roll resolved")
+ }
+}
func TestCrapsTakenDownRollDoesNotCarryIntoNewBet(t *testing.T) {
tb := crapsFixture()