1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
|
package casino
import (
"fmt"
"strings"
)
// Variants are explicit house editions; regional games with the same names
// need not use these rules. Random sources never affect wallet/queue handling.
func (c CrapsConfig) variant() string {
if c.Variant == "" {
return "bank"
}
return c.Variant
}
// helpTopic names the help page the "rules" command opens: every house
//
// edition has its own page (Simplified Craps is a two-screen quick guide,
// not a link into the bank-craps manual), except diceless which plays full
// bank rules with cards instead of dice.
func (c CrapsConfig) helpTopic() string {
switch c.variant() {
case "simplified":
return "simplified craps"
case "high_point":
return "high point craps"
case "die_rich":
return "die rich craps"
case "new_york":
return "new york craps"
case "crapless":
return "crapless craps"
case "diceless":
return "diceless craps"
default:
return "craps"
}
}
func (c CrapsConfig) title() string {
switch c.variant() {
case "simplified":
return "Simplified Craps"
case "high_point":
return "High Point Craps"
case "crapless":
return "Crapless Craps"
case "new_york":
return "New York Craps"
case "die_rich":
return "Die Rich Craps"
case "diceless":
return "Diceless Craps"
default:
return "Bank Craps"
}
}
// Title is the human-readable edition name shown by the look command.
func (c CrapsConfig) Title() string { return c.title() }
func (c CrapsConfig) allows(kind string) bool {
switch c.variant() {
case "simplified", "high_point", "die_rich":
return kind == "pass"
case "new_york":
return kind == "pass" || kind == "dontpass" || kind == "buy" || kind == "lay" || kind == "odds"
case "crapless":
return kind != "dontpass" && kind != "dontcome" && kind != "fire" && kind != "small" && kind != "tall" && kind != "all"
default:
return true
}
}
func (c CrapsConfig) pointNumber(n int) bool {
switch c.variant() {
case "simplified":
return false
case "high_point":
return n >= 4 && n <= 10
case "die_rich":
return n >= 2 && n <= 5
case "crapless":
return n >= 2 && n <= 12 && n != 7
default:
return crapsNumber(n)
}
}
func (c CrapsConfig) number(n int) bool {
return crapsNumber(n) || (c.variant() == "crapless" && n >= 2 && n <= 12 && n != 7)
}
func crapsPlaceOdds(n int) (int, int) {
switch n {
case 2, 12:
return 11, 2
case 3, 11:
return 11, 4
case 4, 10:
return 9, 5
case 5, 9:
return 7, 5
default:
return 7, 6
}
}
func (c CrapsConfig) outcome(kind string, n, a, b, point int) (bool, int, int) {
s := a + b
switch c.variant() {
case "simplified":
switch s {
case 2:
return true, 3, 1
case 3, 4:
return true, 1, 1
case 10, 11:
return true, 2, 1
case 12:
return true, 5, 1
default:
return true, -1, 1
}
case "high_point":
if n == 0 {
if s == 2 || s == 3 {
return false, 0, 1
}
if s >= 11 {
return true, 1, 1
}
return false, 0, 1
}
if s > n {
return true, 1, 1
}
return true, -1, 1
case "die_rich":
if n == 0 {
if s == 6 {
return true, 1, 1
}
if s == 1 {
return true, -1, 1
}
return false, 0, 1
}
if s == n {
return true, 1, 1
}
if s == 1 {
return true, -1, 1
}
return false, 0, 1
case "crapless":
if (kind == "pass" || kind == "come") && n == 0 {
if s == 7 {
return true, 1, 1
}
return false, 0, 1
}
}
return crapsOutcome(kind, n, a, b, point, c.Field12)
}
// outcomeFor includes bonus progress without mutating it. Both previews and
// actual settlement call this before recording the new roll.
func (t *crapsTable) outcomeFor(bet *crapsBet, a, b int) (bool, int, int) {
s := a + b
switch bet.kind {
case "fire":
if t.point == 0 || s != 7 {
return false, 0, 1
}
x := crapsFireProfit(len(t.made))
if x == 0 {
x = -1
}
return true, x, 1
case "small", "tall", "all":
if s == 7 {
return true, -1, 1
}
lo, hi := 2, 12
if bet.kind == "small" {
hi = 6
}
if bet.kind == "tall" {
lo = 8
}
if !crapsBonusComplete(lo, hi, t.seen, s) {
return false, 0, 1
}
if bet.kind == "all" {
return true, 175, 1
}
return true, 34, 1
default:
return t.Config.Craps.outcome(bet.kind, bet.number, a, b, t.point)
}
}
func (c CrapsConfig) variantRulesText() string {
rules := ""
switch c.variant() {
case "simplified":
rules = "Pass only, one roll of two dice. Payouts: 2 pays 3:1; 3/4 pay 1:1; 10/11 pay 2:1; 12 pays 5:1. Totals 5/6/7/8/9 lose. Winning bets also return their stake. No point, odds, come, place, side bets or multi-roll wagers. The dice roll automatically 3 ticks after the first bet; there is no manual roll. House edge: 1/36 (approximately 2.78%). A loss passes the dice."
case "high_point":
rules = "Pass only, 1:1. Come-out 2/3 roll again, 11/12 win; 4-10 establish a point. The very next roll wins only if HIGHER than the point; equal/lower loses. Loss passes the dice."
case "die_rich":
rules = "Pass only, ONE six-sided die, 1:1. Come-out 6 wins, 1 loses; 2-5 establish a point. Repeat the point before 1 to win; other faces roll again. Any 1 passes the die. No free odds."
case "new_york":
rules = "House New York: bank pass/dontpass (bar 12), free odds, buy and lay only. No come, place, field, propositions, hardways or bonuses. Buy/lay use true odds with 5% commission on buy stake / lay profit, rounded down, wins only. Buy is off on come-out; lay works."
case "crapless":
rules = "Come-out 7 wins; ALL other totals become points, including 2/3/11/12. Pass/come only, no don't bets or bonuses. All bank side bets supported. Extra-number place: 2/12 pay 11:2; 3/11 pay 11:4. Buy and free odds: 2/12 pay 6:1; 3/11 pay 3:1. Lay pays inverse true odds. Default extra-number odds limit: 1x stake."
}
if c.variant() == "new_york" || c.variant() == "crapless" {
rules += "\nTrue odds on 4/10: 2:1; 5/9: 3:2; 6/8: 6:5. Lay and don't odds invert these ratios. Buy/lay commission: 5% buy STAKE / lay PROFIT, rounded down, on wins only; removals have no commission."
}
if c.variant() == "crapless" {
rules += fmt.Sprintf("\nPass/come pay 1:1 on their point before 7; 7 loses. Line bets only on come-out; come requires a table point.\nTargets: pass / come / odds pass / odds come <number> / place <number> / buy <number> / lay <number>.\nPlace 4/10 pays 9:5; 5/9 7:5; 6/8 7:6.\nfield: 2 pays 2:1, 12 pays %d:1, 3/4/9/10/11 pay 1:1; others lose.\nhard 4/10 pays 7:1; hard 6/8 pays 9:1; easy number or 7 loses.\nseven 4:1; craps 7:1; eleven / ace-deuce 15:1; aces / boxcars 30:1.\nhorn splits equally among 2/3/11/12; hop <a> <b> pays 15:1 easy / 30:1 double, unordered.\nPlace/buy/hardways and come odds are off on come-out; established come contracts and lay always work.\nNo Fire or ATS. Making a point retains the shooter; seven-out rotates.", c.Field12)
}
if c.variant() == "new_york" {
rules += "\nPass come-out 7/11 wins, 2/3/12 loses; 4/5/6/8/9/10 establish a point. Make it before 7 to win, all 1:1. Don't pass is opposite, except come-out 12 pushes. Line bets only on come-out. Making a point retains the shooter; seven-out rotates."
}
cadence := "Solo roll anytime; multiplayer waits 10 ticks, then dealer rolls after 60 ticks."
autoroll := "Bets stay open until the roll. autoroll repeats every 3 ticks, respecting the betting window."
betLine := "Bet: bet <n> on pass; the felt is authoritative for this edition."
stopLine := "stop cancels autoroll; manual stop waits for live bets."
if c.variant() == "simplified" {
betLine = "Bet: bet <amount> — always on pass; bare bet rebets your last wager."
cadence = "The dice roll automatically 3 ticks after the first bet."
autoroll = ""
stopLine = "stop waits for live bets."
}
lines := []string{c.title() + " — house rules", rules, betLine,
fmt.Sprintf("Free odds: %d (0 = 3-4-5x on ordinary points, don't 6x laid). No odds on Simplified, High Point or Die Rich.", c.Odds),
"Each wager obeys table limits and exact payout units. Wins return stake and remove the bet.",
"Pass/come contracts cannot be removed; optional bets/odds can: unbet.",
cadence, stopLine + " Disconnect forfeits; shutdown refunds."}
if autoroll != "" {
lines = append(lines[:7], append([]string{autoroll}, lines[7:]...)...)
}
return strings.Join(lines, "\n")
}
|