diff options
Diffstat (limited to 'internal/game')
| -rw-r--r-- | internal/game/casino_look_test.go | 47 | ||||
| -rw-r--r-- | internal/game/casino_rules_list_test.go | 8 | ||||
| -rw-r--r-- | internal/game/cmd_look.go | 6 | ||||
| -rw-r--r-- | internal/game/craps_test.go | 2 | ||||
| -rw-r--r-- | internal/game/craps_variants_test.go | 12 | ||||
| -rw-r--r-- | internal/game/look_room.go | 6 | ||||
| -rw-r--r-- | internal/game/render_craps.go | 238 | ||||
| -rw-r--r-- | internal/game/render_craps_test.go | 19 |
8 files changed, 260 insertions, 78 deletions
diff --git a/internal/game/casino_look_test.go b/internal/game/casino_look_test.go index 4c464f1..cdb0b59 100644 --- a/internal/game/casino_look_test.go +++ b/internal/game/casino_look_test.go @@ -88,3 +88,50 @@ func TestLookStandingShowsFixtureOnly(t *testing.T) { t.Fatalf("standing look missing the play hint: %q", text) } } + +// TestLookCasinoRoomSingleBlankBeforeExits pins the room-look spacing: the +// casino fixture listing and the exit section are separated by one blank +// line, whether or not the mini-map supplies trailing rows of its own. +func TestLookCasinoRoomSingleBlankBeforeExits(t *testing.T) { + for _, mapOpt := range []string{"off", "right"} { + t.Run(mapOpt, func(t *testing.T) { + h := newHarness(t) + h.seedAccount("alice") + h.seedCharacter("alice", "alice") + sess, conn := h.connect("alice") + sess.Player.Options = map[string]any{"tiny_map": mapOpt} + + room := "id: 4\nname: Bank Craps Pit\ndescription: A sweeping green felt table curves beneath warm brass lamps. Ivory dice rest beside a polished stick.\nexits:\n north:\n room: 1\ncasino_tables:\n - id: bank_craps\n game: craps\n craps:\n variant: bank\n" + path := filepath.Join(h.dir, "rooms", "4.yaml") + if err := os.WriteFile(path, []byte(room), 0644); err != nil { + t.Fatal(err) + } + h.g.World.AddRoomPath(4, path) + sess.Player.RoomID = 4 + h.hub.EnterRoom(sess, 4) + + h.g.executeLook(sess, nil, "look") + lines := strings.Split(lookOutput(t, conn), "\n") + play, exits := -1, -1 + for i, line := range lines { + if strings.Contains(line, "play craps") { + play = i + } + if strings.TrimSpace(line) == "Exits:" { + exits = i + } + } + if play < 0 || exits < 0 || exits <= play { + t.Fatalf("could not locate table/exits: %q", lines) + } + for i := play; i < exits; i++ { + if strings.TrimSpace(lines[i]) != "" { + continue + } + if i+1 < exits && strings.TrimSpace(lines[i+1]) == "" { + t.Fatalf("consecutive blank lines before Exits: %q", lines) + } + } + }) + } +} diff --git a/internal/game/casino_rules_list_test.go b/internal/game/casino_rules_list_test.go index e83c277..f0c72d2 100644 --- a/internal/game/casino_rules_list_test.go +++ b/internal/game/casino_rules_list_test.go @@ -129,13 +129,17 @@ func TestListFollowsGameState(t *testing.T) { } } - // Establish a point: place/odds appear, bonus bets close. + // Establish a point: place/odds appear, bonus bets close. The roll is + // deliberately delayed, so advance the shared clock until it resolves. g.Casino.Action(1, "bank", "alice", "roll") + for i := 0; i < 5; i++ { + g.Casino.Tick() + } conn.data = nil g.executeList(sess, nil, "list") text = stripANSI(string(conn.data)) targets = listTargets(text) - if !targets["place 6"] || !targets["odds pass"] { + if !targets["place 6/8"] || !targets["odds pass / come"] { t.Fatalf("point list missing place/odds: %q", text) } if targets["fire"] { diff --git a/internal/game/cmd_look.go b/internal/game/cmd_look.go index 70bc2c2..38cc83c 100644 --- a/internal/game/cmd_look.go +++ b/internal/game/cmd_look.go @@ -56,7 +56,11 @@ func (g *Game) doLook(sess *net.Session) { } } - g.showRoomExits(sess, p, room) + // When the minimap is taller than the room content it already renders + // empty content rows below the last line, so the exit section must not + // add another gap on top of them: that is what read as two blank lines. + addExitGap := !(mapOn && len(mapLines) > len(content)) + g.showRoomExits(sess, p, room, addExitGap) g.showRoomPlayers(sess, p, room) // Seated at a table: look keeps its room-first order, then appends the // live game state and the current hint menu. diff --git a/internal/game/craps_test.go b/internal/game/craps_test.go index fd2e4b9..27610bd 100644 --- a/internal/game/craps_test.go +++ b/internal/game/craps_test.go @@ -43,7 +43,7 @@ func TestCrapsCommandsAndRendering(t *testing.T) { for _, unicode := range []bool{false, true} { art := renderCrapsSnapshot(snap, mode, unicode) plain := plainRoulette(art) - for _, word := range []string{"PASS LINE", "DON'T COME", "FIELD", "FIRE", "ALL SMALL", "Shooter alice", "Total: 7", "POINT 6"} { + for _, word := range []string{"PASS LINE", "DON'T COME", "FIELD", "FIRE", "ALL SMALL", "Total: 7", "POINT 6"} { if !strings.Contains(plain, word) { t.Fatal("missing", word) } diff --git a/internal/game/craps_variants_test.go b/internal/game/craps_variants_test.go index 42f3529..46f5be6 100644 --- a/internal/game/craps_variants_test.go +++ b/internal/game/craps_variants_test.go @@ -41,7 +41,7 @@ func TestCrapsVariantRendering(t *testing.T) { if v == "die_rich" && !strings.Contains(plain, "Total: 4") { t.Fatal("single die absent") } - if mode == "xterm256" && (v == "die_rich" || v == "diceless") { + if mode == "xterm256" && v == "diceless" { bg := 0 if style == "light" { bg = 15 @@ -50,14 +50,20 @@ func TestCrapsVariantRendering(t *testing.T) { t.Fatal(v, "style") } } + if mode == "xterm256" && v == "die_rich" && !strings.Contains(text, color.BgCode(mode, 15)) { + t.Fatal(v, "die should use a white background") + } } } } } for n := 1; n <= 6; n++ { - text := renderCrapsDice([2]int{n, 0}, "none", false, "dark") + text := renderCrapsDice([2]int{n, 0}, "none", false) if strings.Count(text, "+-------+") != 2 { - t.Fatal("must render exactly one die", text) + t.Fatal("single die needs a top and bottom outline", text) + } + if got := strings.Count(strings.ReplaceAll(text, "Total:", ""), "o"); got != n { + t.Fatalf("single die %d rendered %d pips", n, got) } } } diff --git a/internal/game/look_room.go b/internal/game/look_room.go index 3208f40..a09d66d 100644 --- a/internal/game/look_room.go +++ b/internal/game/look_room.go @@ -134,11 +134,13 @@ func (g *Game) formatExitLines(sess *net.Session, room *world.Room) []string { return out } -func (g *Game) showRoomExits(sess *net.Session, p *player.Player, room *world.Room) { +func (g *Game) showRoomExits(sess *net.Session, p *player.Player, room *world.Room, gap bool) { if len(room.Exits) == 0 { return } - sess.WriteLine("") + if gap { + sess.WriteLine("") + } if p.OptionBool("exits") { lines := g.formatExitLines(sess, room) if len(lines) > 0 { diff --git a/internal/game/render_craps.go b/internal/game/render_craps.go index 80f05ee..7ec015a 100644 --- a/internal/game/render_craps.go +++ b/internal/game/render_craps.go @@ -20,6 +20,8 @@ const ( crapsMarked crapsPuckOn crapsPuckOff + crapsFire + crapsAts ) var crapsPaint = []color.ColorSpec{ @@ -30,6 +32,8 @@ var crapsPaint = []color.ColorSpec{ {Fg: 0, Bg: 220, Bold: true}, {Fg: 0, Bg: 15, Bold: true}, {Fg: 15, Bg: 0, Bold: true}, + {Fg: 229, Bg: 124, Bold: true}, // fire tracker: yellow on red + {Fg: 229, Bg: 24, Bold: true}, // ATS tracker: yellow on blue } type crapsCell struct { @@ -39,6 +43,21 @@ type crapsCell struct { } type crapsCanvas struct{ cells [][]crapsCell } +// fill paints one rectangular region with an ink without touching glyphs or +// box edges, so a whole tracker section can share one background colour. +func (c *crapsCanvas) fill(x1, y1, x2, y2, ink int) { + for y := y1; y <= y2; y++ { + if y < 0 || y >= len(c.cells) { + continue + } + for x := x1; x <= x2; x++ { + if x >= 0 && x < len(c.cells[y]) { + c.cells[y][x].ink = ink + } + } + } +} + // crapsCanvasWidth is the fixed felt width every craps render uses. const crapsCanvasWidth = 77 @@ -138,14 +157,33 @@ func crapsHas(ns []int, n int) bool { func crapsDie(n int) string { return string([]rune{'⚀', '⚁', '⚂', '⚃', '⚄', '⚅'}[n-1]) } + +// crapsDrawPuck paints the point puck: OFF on the layout, ON in the point's +// number box. It is shared by the bank and variant felts. +func crapsDrawPuck(c *crapsCanvas, x, y int, on, unicode bool) { + ink, word := crapsPuckOff, "OFF" + if on { + ink, word = crapsPuckOn, "ON " + } + a, b, d := "+---+", "|"+word+"|", "+---+" + if unicode { + a, b, d = "╭───╮", "│"+word+"│", "╰───╯" + } + c.text(x, y, a, ink) + c.text(x, y+1, b, ink) + c.text(x, y+2, d, ink) +} func renderCrapsTrackers(s *casino.CrapsSnapshot, mode string, unicode bool) string { c := newCrapsCanvas(12) + // Section backgrounds first: fire red, ATS blue, yellow lettering on top. + c.fill(0, 0, 76, 5, crapsFire) + c.fill(0, 5, 76, 11, crapsAts) c.box(0, 0, 76, 2) c.box(0, 5, 38, 8) c.box(38, 5, 76, 8) - c.text(3, 1, "FIRE", crapsGold) + c.text(3, 1, "FIRE", crapsFire) for i, n := range []int{4, 5, 6, 8, 9, 10} { - ink, mark := crapsMuted, " " + ink, mark := crapsFire, " " if crapsHas(s.Made, n) { ink, mark = crapsMarked, "*" } @@ -155,29 +193,29 @@ func renderCrapsTrackers(s *casino.CrapsSnapshot, mode string, unicode bool) str for i, payout := range []string{"24:1", "249:1", "999:1"} { lo, hi := bounds[i], bounds[i+1] c.box(lo, 2, hi, 5) - c.center(lo+1, hi-1, 3, fmt.Sprintf("%d DISTINCT POINTS", i+4), crapsGold) - c.center(lo+1, hi-1, 4, payout, crapsInk) + c.center(lo+1, hi-1, 3, fmt.Sprintf("%d DISTINCT POINTS", i+4), crapsFire) + c.center(lo+1, hi-1, 4, payout, crapsFire) } - c.text(2, 6, "ALL SMALL", crapsGold) - c.text(40, 6, "TALL", crapsGold) + c.text(2, 6, "ALL SMALL", crapsAts) + c.text(40, 6, "TALL", crapsAts) for i, n := range []int{2, 3, 4, 5, 6, 8, 9, 10, 11, 12} { x := 12 + i*5 if i >= 5 { x = 48 + (i-5)*5 } - ink, mark := crapsMuted, " " + ink, mark := crapsAts, " " if crapsHas(s.Seen, n) { ink, mark = crapsMarked, "*" } c.text(x, 6, fmt.Sprintf("%2d%s ", n, mark), ink) } - c.center(1, 37, 7, "* = rolled", crapsMuted) - c.center(39, 75, 7, "* = rolled", crapsMuted) + c.center(1, 37, 7, "* = rolled", crapsAts) + c.center(39, 75, 7, "* = rolled", crapsAts) for i, row := range [][2]string{{"SMALL", "34:1"}, {"ALL", "175:1"}, {"TALL", "34:1"}} { lo, hi := bounds[i], bounds[i+1] c.box(lo, 8, hi, 11) - c.center(lo+1, hi-1, 9, row[0], crapsGold) - c.center(lo+1, hi-1, 10, row[1], crapsInk) + c.center(lo+1, hi-1, 9, row[0], crapsAts) + c.center(lo+1, hi-1, 10, row[1], crapsAts) } return c.render(mode, unicode) } @@ -187,31 +225,18 @@ func renderCrapsFelt(s *casino.CrapsSnapshot, mode string, unicode bool) string c.center(1, 13, 4, "DON'T COME", crapsInk) c.center(1, 13, 5, "BAR 12", crapsMuted) nums := []int{4, 5, 6, 8, 9, 10} - labels := []string{"4", "5", "SIX", "8", "NINE", "10"} + numLabels := []string{"4", "5", "SIX", "8", "NINE", "10"} pays := []string{"9:5", "7:5", "7:6", "7:6", "7:5", "9:5"} - puck := func(x int, on bool) { - ink, word := crapsPuckOff, "OFF" - if on { - ink, word = crapsPuckOn, "ON " - } - a, b, d := "+---+", "|"+word+"|", "+---+" - if unicode { - a, b, d = "╭───╮", "│"+word+"│", "╰───╯" - } - c.text(x, 1, a, ink) - c.text(x, 2, b, ink) - c.text(x, 3, d, ink) - } if s.Point == 0 { - puck(5, false) + crapsDrawPuck(c, 5, 1, false, unicode) } for i, n := range nums { x := 14 + i*6 c.box(x, 0, x+6, 6) - c.center(x+1, x+5, 4, labels[i], crapsGold) + c.center(x+1, x+5, 4, numLabels[i], crapsGold) c.center(x+1, x+5, 5, pays[i], crapsMuted) if s.Point == n { - puck(x+1, true) + crapsDrawPuck(c, x+1, 1, true, unicode) } } c.box(0, 6, 50, 10) @@ -224,7 +249,11 @@ func renderCrapsFelt(s *casino.CrapsSnapshot, mode string, unicode bool) string if twelve == 0 { twelve = 2 } - c.center(1, 49, 15, fmt.Sprintf("2 PAYS DOUBLE 12 PAYS %d:1", twelve), crapsGold) + twelvePay := "DOUBLE" + if twelve == 3 { + twelvePay = "TRIPLE" + } + c.center(1, 49, 15, fmt.Sprintf("2 PAYS DOUBLE 12 PAYS %s", twelvePay), crapsGold) c.box(0, 16, 50, 19) c.center(1, 49, 18, "DON'T PASS / BAR 12", crapsInk) c.box(0, 19, 50, 22) @@ -278,38 +307,132 @@ func renderCrapsFelt(s *casino.CrapsSnapshot, mode string, unicode bool) string c.center(64, 75, 24, "15:1 / 30:1", crapsMuted) return c.render(mode, unicode) } -func renderCrapsDice(dice [2]int, mode string, unicode bool, style string) string { + +// renderHighPointFelt draws High Point's number row, point puck and pass +// line, with the come-out special case printed on the felt. +func renderHighPointFelt(s *casino.CrapsSnapshot, mode string, unicode bool) string { + c := newCrapsCanvas(16) + c.box(0, 0, 76, 15) + c.center(1, 75, 1, "HIGH POINT CRAPS", crapsGold) + c.center(1, 75, 2, "COME-OUT 2 OR 3: IGNORED | 11 OR 12: WINS", crapsInk) + nums := []int{4, 5, 6, 8, 9, 10} + labels := []string{"4", "5", "SIX", "8", "NINE", "10"} + for i, n := range nums { + x := 2 + i*12 + c.box(x, 5, x+11, 10) + c.center(x+1, x+10, 9, labels[i], crapsGold) + if s.Point == n { + crapsDrawPuck(c, x+3, 6, true, unicode) + } + } + c.box(2, 12, 74, 14) + c.center(3, 73, 13, "PASS LINE", crapsGold) + return c.render(mode, unicode) +} + +// renderCraplessFelt gives every total a point box and shows the pass rail; +// crapless has no don't bets or bonuses. +func renderCraplessFelt(s *casino.CrapsSnapshot, mode string, unicode bool) string { + c := newCrapsCanvas(16) + c.box(0, 0, 76, 15) + c.center(1, 75, 1, "CRAPLESS CRAPS", crapsGold) + c.center(1, 75, 2, "COME-OUT 7 WINS | ALL OTHER TOTALS BECOME POINTS", crapsInk) + nums := []int{2, 3, 4, 5, 6, 8, 9, 10, 11, 12} + for i, n := range nums { + x := 3 + i*7 + c.box(x, 5, x+6, 10) + c.center(x+1, x+5, 9, fmt.Sprint(n), crapsGold) + if s.Point == n { + crapsDrawPuck(c, x+1, 6, true, unicode) + } + } + c.box(2, 12, 74, 14) + c.center(3, 73, 13, "PASS LINE", crapsGold) + return c.render(mode, unicode) +} + +// renderNewYorkFelt is the pass/don't-pass, buy/lay layout. +func renderNewYorkFelt(s *casino.CrapsSnapshot, mode string, unicode bool) string { + c := newCrapsCanvas(16) + c.box(0, 0, 76, 15) + c.center(1, 75, 1, "NEW YORK CRAPS", crapsGold) + c.center(1, 75, 2, "PASS | DON'T PASS (BAR 12) | FREE ODDS | BUY / LAY 4 5 6 8 9 10", crapsInk) + nums := []int{4, 5, 6, 8, 9, 10} + for i, n := range nums { + x := 3 + i*12 + c.box(x, 5, x+10, 10) + c.center(x+1, x+9, 9, fmt.Sprint(n), crapsGold) + if s.Point == n { + crapsDrawPuck(c, x+3, 6, true, unicode) + } + } + c.box(2, 12, 74, 14) + c.center(3, 73, 13, "PASS LINE / DON'T PASS", crapsGold) + return c.render(mode, unicode) +} + +// renderDieRichFelt shows the single-die come-out targets and the four point +// faces, with the pass line beneath them. +func renderDieRichFelt(s *casino.CrapsSnapshot, mode string, unicode bool) string { + c := newCrapsCanvas(15) + c.box(0, 0, 76, 14) + c.center(1, 75, 1, "DIE RICH CRAPS", crapsGold) + c.center(1, 75, 2, "ONE DIE | COME-OUT 6 WINS, 1 LOSES | 2-5 BECOME THE POINT", crapsInk) + nums := []int{2, 3, 4, 5} + for i, n := range nums { + x := 8 + i*16 + c.box(x, 5, x+12, 10) + c.center(x+1, x+11, 9, fmt.Sprint(n), crapsGold) + if s.Point == n { + crapsDrawPuck(c, x+4, 6, true, unicode) + } + } + c.box(2, 11, 74, 13) + c.center(3, 73, 12, "PASS LINE", crapsGold) + return c.render(mode, unicode) +} + +// renderCrapsDice paints each face as a white tile with black pips. The tile +// is five interior rows tall (three pip rows plus white padding top and +// bottom) inside a box outline, so the face reads as a square die. +func renderCrapsDice(dice [2]int, mode string, unicode bool) string { if dice[0] < 1 || dice[0] > 6 || dice[1] < 0 || dice[1] > 6 { return "" } patterns := [][3]string{{}, {" ", " o ", " "}, {"o ", " ", " o"}, {"o ", " o ", " o"}, {"o o", " ", "o o"}, {"o o", " o ", "o o"}, {"o o", "o o", "o o"}} - top, bottom, v, pip := "+-------+", "+-------+", "|", "o" + pip := "o" if unicode { - top, bottom, v, pip = "╭───────╮", "╰───────╯", "│", "●" + pip = "●" } - spec := color.ColorSpec{Fg: 15, Bg: 0, Bold: true} - if style == "light" { - spec = color.ColorSpec{Fg: 0, Bg: 15, Bold: true} + top, bottom, v := "+-------+", "+-------+", "|" + if unicode { + top, bottom, v = "╭───────╮", "╰───────╯", "│" } + spec := color.ColorSpec{Fg: 0, Bg: 15, Bold: true} var out strings.Builder - for row := 0; row < 5; row++ { + for row := 0; row < 7; row++ { out.WriteString(" ") for i, n := range dice { if n == 0 { continue } - line := top - if row == 4 { + var line string + switch row { + case 0: + line = top + case 6: line = bottom - } else if row > 0 { - line = v + " " + strings.ReplaceAll(patterns[n][row-1], "o", pip) + " " + v + case 1, 5: + line = v + " " + v + default: + line = v + " " + strings.ReplaceAll(patterns[n][row-2], "o", pip) + " " + v } out.WriteString(color.Render(mode, spec, line)) if i == 0 { out.WriteString(" ") } } - if row == 2 { + if row == 3 { out.WriteString(color.Render(mode, color.ColorSpec{Fg: 229, Bg: -1, Bold: true}, fmt.Sprintf(" Total: %d", dice[0]+dice[1]))) } out.WriteByte('\n') @@ -353,37 +476,30 @@ func renderCrapsSnapshot(s *casino.CrapsSnapshot, mode string, unicode bool, sty } else if variant == "simplified" { out.WriteString(renderSimplifiedCrapsFelt(mode, unicode)) } else { - height := 7 - if variant == "high_point" || variant == "die_rich" { - height = 6 - } - c := newCrapsCanvas(height) - c.box(0, 0, 76, height-1) - c.center(1, 75, 1, "HOUSE EDITION — rules teaches this edition", crapsGold) switch variant { + case "high_point": + out.WriteString(renderHighPointFelt(s, mode, unicode)) case "crapless": - c.center(1, 75, 3, "POINTS: 2 3 4 5 6 8 9 10 11 12 | PASS / COME / ODDS", crapsInk) - c.center(1, 75, 4, "PLACE / BUY / LAY / FIELD / HARD / HOP / PROPOSITIONS", crapsInk) - c.center(1, 75, 5, "NO DON'T BETS OR BONUSES", crapsMuted) + out.WriteString(renderCraplessFelt(s, mode, unicode)) case "new_york": - c.center(1, 75, 3, "PASS / DON'T PASS (BAR 12) / ODDS / BUY / LAY", crapsInk) - c.center(1, 75, 4, "BUY / LAY: 4 5 6 8 9 10 | 5% WIN-ONLY COMMISSION", crapsMuted) + out.WriteString(renderNewYorkFelt(s, mode, unicode)) + case "die_rich": + out.WriteString(renderDieRichFelt(s, mode, unicode)) default: - c.center(1, 75, 3, "PASS ONLY | WINS PAY 1:1 | NO ODDS OR BONUSES", crapsInk) + c := newCrapsCanvas(7) + c.box(0, 0, 76, 6) + c.center(1, 75, 3, "HOUSE EDITION — rules teaches this edition", crapsGold) + out.WriteString(c.render(mode, unicode)) } - out.WriteString(c.render(mode, unicode)) } out.WriteByte('\n') if variant == "diceless" { out.WriteString(renderCrapsCards(s.Dice, mode, unicode, style)) } else { - out.WriteString(renderCrapsDice(s.Dice, mode, unicode, style)) + out.WriteString(renderCrapsDice(s.Dice, mode, unicode)) } - if len(s.Queue) > 0 { - out.WriteString(title(" Shooter ") + subtle(s.Queue[0]) + "\n") - if len(s.Queue) > 1 { - out.WriteString(subtle(" On deck "+strings.Join(s.Queue[1:], " > ")) + "\n") - } + if len(s.Queue) > 1 { + out.WriteString(subtle(" On deck "+strings.Join(s.Queue[1:], " > ")) + "\n") } hint := "" if s.Phase != "waiting" && s.Phase != "" { diff --git a/internal/game/render_craps_test.go b/internal/game/render_craps_test.go index 9d75630..b3cc1d8 100644 --- a/internal/game/render_craps_test.go +++ b/internal/game/render_craps_test.go @@ -45,7 +45,7 @@ func TestCrapsHalfTableGeometryAndPuck(t *testing.T) { if strings.Count(art, want) != 1 { t.Fatalf("missing/duplicate puck %d: %s", point, art) } - if !strings.Contains(art, "12 PAYS 3:1") { + if !strings.Contains(art, "12 PAYS TRIPLE") { t.Fatal("field variant invisible") } for _, bet := range []string{"DON'T COME", "C O M E", "FIELD", "DON'T PASS", "PASS LINE", "HARD 4", "HARD 6", "HARD 8", "HARD 10", "SEVEN", "CRAPS", "ELEVEN", "ACES", "ACE 3", "BOXCARS", "HORN", "HOP"} { @@ -58,7 +58,7 @@ func TestCrapsHalfTableGeometryAndPuck(t *testing.T) { t.Log("\n" + renderCrapsSnapshot(&casino.CrapsSnapshot{Point: 6, Field12: 3, Dice: [2]int{3, 3}, Queue: []string{"Alice", "Bob"}, Made: []int{4, 5}, Seen: []int{2, 4, 5, 6, 9}, Phase: "betting", ShootIn: 10, DealerIn: 70}, "none", true)) } func TestCrapsTrackersAndDiceStyles(t *testing.T) { - s := &casino.CrapsSnapshot{Made: []int{4, 6}, Seen: []int{2, 12}} + s := &casino.CrapsSnapshot{Point: 6, Made: []int{4, 6}, Seen: []int{2, 12}} art := renderCrapsTrackers(s, "xterm256", true) plain := plainRoulette(art) for _, token := range []string{"[ 4*]", "[ 5 ]", "[ 6*]", " 2*", "12*"} { @@ -69,6 +69,9 @@ func TestCrapsTrackersAndDiceStyles(t *testing.T) { if strings.Count(art, color.BgCode("xterm256", 220)) != 4 { t.Fatal("wrong number of filled tracker tokens") } + if !strings.Contains(art, color.BgCode("xterm256", 124)) || !strings.Contains(art, color.BgCode("xterm256", 24)) { + t.Fatal("fire/ATS tracker backgrounds are not red/blue") + } if !strings.Contains(renderCrapsFelt(s, "xterm256", true), color.BgCode("xterm256", 22)) { t.Fatal("felt not dark green") } @@ -80,16 +83,16 @@ func TestCrapsTrackersAndDiceStyles(t *testing.T) { light := g.renderCasinoSnapshot(sess, s) p.Options["card_style"] = "dark" dark := g.renderCasinoSnapshot(sess, s) - if light == dark { - t.Fatal("card_style not wired to craps") + if light != dark { + t.Fatal("craps dice are intentionally style-independent") } for a := 1; a <= 6; a++ { for b := 1; b <= 6; b++ { for _, unicode := range []bool{false, true} { - lit := renderCrapsDice([2]int{a, b}, "xterm256", unicode, "light") - dim := renderCrapsDice([2]int{a, b}, "xterm256", unicode, "dark") - if !strings.Contains(lit, color.BgCode("xterm256", 15)) || !strings.Contains(dim, color.BgCode("xterm256", 0)) { - t.Fatal("incorrect dice background") + lit := renderCrapsDice([2]int{a, b}, "xterm256", unicode) + dim := renderCrapsDice([2]int{a, b}, "xterm256", unicode) + if !strings.Contains(lit, color.BgCode("xterm256", 15)) || !strings.Contains(dim, color.BgCode("xterm256", 15)) { + t.Fatal("craps dice should always use a white background") } pip := "o" if unicode { |
