package game import ( "fmt" "strings" "thehouseoficarus/internal/casino" ) // A baccarat felt: the three main wagers as betting boxes, the optional side // bets and house settings in labelled boxes, and the punto banco drawing // table across the bottom. Reuses the shared felt canvas and palette. func renderBaccaratRulesFelt(cfg casino.TableConfig, mode string, unicode bool) string { b := cfg.Baccarat.Normalize() c := newCrapsCanvas(26) // Title block: variant, scoring, naturals. c.box(0, 0, 76, 4) c.center(1, 75, 1, baccaratVariantTitle(b), crapsGold) c.center(1, 75, 2, "ACE 1 | 2-9 FACE | 10/J/Q/K 0 — HIGHEST LAST DIGIT WINS", crapsInk) c.center(1, 75, 3, "AN INITIAL 8 OR 9 ON EITHER HAND STOPS ALL DRAWING", crapsMuted) // Three betting boxes: PLAYER | TIE | BANKER. spots := [3][2]int{{0, 25}, {25, 50}, {50, 76}} for _, x := range spots { c.box(x[0], 4, x[1], 8) } c.center(1, 24, 5, "PLAYER", crapsGold) c.center(26, 49, 5, "TIE", crapsGold) c.center(51, 75, 5, "BANKER", crapsGold) c.center(1, 24, 6, "PAYS 1:1", crapsInk) c.center(26, 49, 6, "PAYS "+ratioText(b.TiePayout), crapsInk) c.center(51, 75, 6, bankerPayoutText(b), crapsInk) c.center(1, 24, 7, "", crapsMuted) c.center(26, 49, 7, "PLAYER & BANKER PUSH", crapsMuted) c.center(51, 75, 7, bankerNoteText(b), crapsMuted) // Side bets and house settings. boxY := [2][2]int{{8, 15}, {8, 15}} xs := [2][2]int{{0, 38}, {38, 76}} for i := range boxY { c.box(xs[i][0], boxY[i][0], xs[i][1], boxY[i][1]) } c.center(1, 37, 9, "SIDE BETS", crapsGold) c.center(39, 75, 9, "HOUSE", crapsGold) side := [][2]string{ {"PLAYER PAIR", optionalText(b.PairBets, "11:1")}, {"BANKER PAIR", optionalText(b.PairBets, "11:1")}, {"DRAGON 7", optionalText(b.Dragon7, "40:1")}, {"PANDA 8", optionalText(b.Panda8, "25:1")}, {"SUPER 6", optionalText(b.Super6Bet, "12:1")}, } house := [][2]string{ {"DECKS", fmt.Sprintf("%d", b.Decks)}, {"SHUFFLE AT", fmt.Sprintf("%g%% REMAINING", b.ShuffleAt*100)}, {"BET LIMITS", betLimitsText(cfg.MinBet, cfg.MaxBet)}, {"SEATS", fmt.Sprintf("%d", cfg.MaxPlayers)}, {"BETTING WINDOW", fmt.Sprintf("%d TICKS", cfg.BettingTicks)}, } for j, row := range side { c.bjRule(0, 38, 10+j, row[0], row[1]) } for j, row := range house { c.bjRule(38, 76, 10+j, row[0], row[1]) } // Drawing table across the bottom: one row per hand total, with the // player rule and each banker situation in its own column. c.box(0, 15, 76, 25) c.center(1, 75, 16, "DRAWING — AUTOMATIC PUNTO BANCO", crapsGold) c.text(3, 17, "HAND", crapsGold) c.text(9, 17, "PLAYER", crapsGold) c.text(18, 17, "BANKER (PLAYER STANDS)", crapsGold) c.text(44, 17, "BANKER (PLAYER DRAWS)", crapsGold) c.box(1, 18, 75, 18) drawRows := [][4]string{ {"0-2", "draw", "draw", "draw"}, {"3", "draw", "draw", "draw unless vs 8"}, {"4", "draw", "draw", "draw vs 2-7"}, {"5", "draw", "draw", "draw vs 4-7"}, {"6", "stand", "stand", "draw vs 6-7"}, {"7", "stand", "stand", "stand"}, } for i, row := range drawRows { y := 19 + i c.text(3, y, row[0], crapsInk) c.text(9, y, row[1], crapsInk) c.text(18, y, row[2], crapsInk) c.text(44, y, row[3], crapsInk) } return c.render(mode, unicode) } func baccaratVariantTitle(b casino.BaccaratConfig) string { switch b.Variant { case casino.BaccaratSuper6: return "SUPER 6 BACCARAT — NO COMMISSION" case casino.BaccaratEZ: return "EZ BACCARAT — NO COMMISSION" default: return "PUNTO BANCO — COMMISSION" } } func bankerPayoutText(b casino.BaccaratConfig) string { switch b.Variant { case casino.BaccaratSuper6, casino.BaccaratEZ, casino.BaccaratCommission: return "PAYS 1:1" default: return "PAYS " + ratioText(b.BankerPayout) } } func bankerNoteText(b casino.BaccaratConfig) string { switch b.Variant { case casino.BaccaratSuper6: return "WINNING 6 PAYS 1:2" case casino.BaccaratEZ: return "3-CARD 7 PUSHES" default: return fmt.Sprintf("%s%% COMMISSION", strings.TrimRight(strings.TrimRight(fmt.Sprintf("%.6g", (1-b.BankerPayout)*100), "0"), ".")) } } func optionalText(enabled bool, payout string) string { if enabled { return payout } return "NOT OFFERED" }