doubletwelve 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1481 @@
1
+ import { jsx as b, Fragment as re, jsxs as T } from "react/jsx-runtime";
2
+ import { useMemo as Se, useState as Y, useEffect as ye } from "react";
3
+ const me = {
4
+ "3x3": { rows: [20, 50, 80], cols: [20, 50, 80], size: "18%" },
5
+ "3x4": { rows: [24, 50, 76], cols: [22, 40, 60, 78], size: "12%" },
6
+ "4x3": { rows: [15, 38, 62, 85], cols: [20, 50, 80], size: "14%" }
7
+ };
8
+ function ze(e) {
9
+ const o = me[e.gridSize];
10
+ return {
11
+ top: e.top ?? `${o.rows[e.row]}%`,
12
+ left: e.left ?? `${o.cols[e.col]}%`,
13
+ width: o.size,
14
+ height: o.size
15
+ };
16
+ }
17
+ const $e = ({
18
+ row: e,
19
+ col: o,
20
+ gridSize: t,
21
+ color: n,
22
+ hollow: r,
23
+ top: l,
24
+ left: i
25
+ }) => {
26
+ const s = ze({ row: e, col: o, gridSize: t, top: l, left: i });
27
+ return /* @__PURE__ */ b(
28
+ "div",
29
+ {
30
+ "data-testid": "pip",
31
+ "data-row": e,
32
+ "data-col": o,
33
+ "data-grid": t,
34
+ style: {
35
+ position: "absolute",
36
+ backgroundColor: r ? "transparent" : n,
37
+ border: r ? "2px solid #888" : void 0,
38
+ borderRadius: "50%",
39
+ transform: "translate(-50%, -50%)",
40
+ boxShadow: r ? void 0 : "1px 2px 3px rgba(0,0,0,0.3)",
41
+ ...s
42
+ }
43
+ }
44
+ );
45
+ }, Me = {
46
+ 0: [],
47
+ 1: [{ row: 1, col: 1, gridSize: "3x3" }],
48
+ 2: [
49
+ { row: 0, col: 2, gridSize: "3x3" },
50
+ { row: 2, col: 0, gridSize: "3x3" }
51
+ ],
52
+ 3: [
53
+ { row: 0, col: 2, gridSize: "3x3" },
54
+ { row: 1, col: 1, gridSize: "3x3" },
55
+ { row: 2, col: 0, gridSize: "3x3" }
56
+ ],
57
+ 4: [
58
+ { row: 0, col: 0, gridSize: "3x3" },
59
+ { row: 0, col: 2, gridSize: "3x3" },
60
+ { row: 2, col: 0, gridSize: "3x3" },
61
+ { row: 2, col: 2, gridSize: "3x3" }
62
+ ],
63
+ 5: [
64
+ { row: 0, col: 0, gridSize: "3x3" },
65
+ { row: 0, col: 2, gridSize: "3x3" },
66
+ { row: 1, col: 1, gridSize: "3x3" },
67
+ { row: 2, col: 0, gridSize: "3x3" },
68
+ { row: 2, col: 2, gridSize: "3x3" }
69
+ ],
70
+ 6: [
71
+ { row: 0, col: 0, gridSize: "3x3" },
72
+ { row: 0, col: 2, gridSize: "3x3" },
73
+ { row: 1, col: 0, gridSize: "3x3" },
74
+ { row: 1, col: 2, gridSize: "3x3" },
75
+ { row: 2, col: 0, gridSize: "3x3" },
76
+ { row: 2, col: 2, gridSize: "3x3" }
77
+ ],
78
+ 7: [
79
+ { row: 0, col: 0, gridSize: "3x3" },
80
+ { row: 0, col: 2, gridSize: "3x3" },
81
+ { row: 1, col: 0, gridSize: "3x3" },
82
+ { row: 1, col: 1, gridSize: "3x3" },
83
+ { row: 1, col: 2, gridSize: "3x3" },
84
+ { row: 2, col: 0, gridSize: "3x3" },
85
+ { row: 2, col: 2, gridSize: "3x3" }
86
+ ],
87
+ 8: [
88
+ { row: 0, col: 0, gridSize: "3x3" },
89
+ { row: 0, col: 1, gridSize: "3x3" },
90
+ { row: 0, col: 2, gridSize: "3x3" },
91
+ { row: 1, col: 0, gridSize: "3x3" },
92
+ { row: 1, col: 2, gridSize: "3x3" },
93
+ { row: 2, col: 0, gridSize: "3x3" },
94
+ { row: 2, col: 1, gridSize: "3x3" },
95
+ { row: 2, col: 2, gridSize: "3x3" }
96
+ ],
97
+ 9: [
98
+ { row: 0, col: 0, gridSize: "3x3" },
99
+ { row: 0, col: 1, gridSize: "3x3" },
100
+ { row: 0, col: 2, gridSize: "3x3" },
101
+ { row: 1, col: 0, gridSize: "3x3" },
102
+ { row: 1, col: 1, gridSize: "3x3" },
103
+ { row: 1, col: 2, gridSize: "3x3" },
104
+ { row: 2, col: 0, gridSize: "3x3" },
105
+ { row: 2, col: 1, gridSize: "3x3" },
106
+ { row: 2, col: 2, gridSize: "3x3" }
107
+ ],
108
+ 10: [
109
+ { row: 0, col: 0, gridSize: "3x4" },
110
+ { row: 0, col: 1, gridSize: "3x4" },
111
+ { row: 0, col: 2, gridSize: "3x4" },
112
+ { row: 0, col: 3, gridSize: "3x4" },
113
+ { row: 1, col: 0, gridSize: "3x4" },
114
+ { row: 1, col: 3, gridSize: "3x4" },
115
+ { row: 2, col: 0, gridSize: "3x4" },
116
+ { row: 2, col: 1, gridSize: "3x4" },
117
+ { row: 2, col: 2, gridSize: "3x4" },
118
+ { row: 2, col: 3, gridSize: "3x4" }
119
+ ],
120
+ 11: [
121
+ { row: 0, col: 0, gridSize: "4x3" },
122
+ { row: 1, col: 0, gridSize: "4x3" },
123
+ { row: 2, col: 0, gridSize: "4x3" },
124
+ { row: 3, col: 0, gridSize: "4x3" },
125
+ { row: 0, col: 1, gridSize: "4x3" },
126
+ { row: 2, col: 1, gridSize: "4x3", top: "50%" },
127
+ { row: 3, col: 1, gridSize: "4x3" },
128
+ { row: 0, col: 2, gridSize: "4x3" },
129
+ { row: 1, col: 2, gridSize: "4x3" },
130
+ { row: 2, col: 2, gridSize: "4x3" },
131
+ { row: 3, col: 2, gridSize: "4x3" }
132
+ ],
133
+ 12: [
134
+ { row: 0, col: 0, gridSize: "4x3" },
135
+ { row: 1, col: 0, gridSize: "4x3" },
136
+ { row: 2, col: 0, gridSize: "4x3" },
137
+ { row: 3, col: 0, gridSize: "4x3" },
138
+ { row: 0, col: 1, gridSize: "4x3" },
139
+ { row: 1, col: 1, gridSize: "4x3" },
140
+ { row: 2, col: 1, gridSize: "4x3" },
141
+ { row: 3, col: 1, gridSize: "4x3" },
142
+ { row: 0, col: 2, gridSize: "4x3" },
143
+ { row: 1, col: 2, gridSize: "4x3" },
144
+ { row: 2, col: 2, gridSize: "4x3" },
145
+ { row: 3, col: 2, gridSize: "4x3" }
146
+ ]
147
+ };
148
+ function Ce(e) {
149
+ return Me[e] ?? [];
150
+ }
151
+ const X = {
152
+ 0: { color: "transparent" },
153
+ 1: { color: "#1a1a1a" },
154
+ 2: { color: "#8B1A1A" },
155
+ 3: { color: "#E6B800" },
156
+ 4: { color: "#e8e8e8", hollow: !0 },
157
+ 5: { color: "#2E8B57" },
158
+ 6: { color: "#2563EB" },
159
+ 7: { color: "#E8A87C" },
160
+ 8: { color: "#DC2626" },
161
+ 9: { color: "#1E3A8A" },
162
+ 10: { color: "#EA580C" },
163
+ 11: { color: "#166534" },
164
+ 12: { color: "#DC2626" }
165
+ }, no = X;
166
+ function ro(e) {
167
+ return { ...X, ...e };
168
+ }
169
+ function le(e, o) {
170
+ if (o !== void 0)
171
+ return o[e] ?? X[e] ?? { color: "#1a1a1a" };
172
+ }
173
+ function lo(e) {
174
+ return le(e, X);
175
+ }
176
+ const ke = (e, o, t) => {
177
+ const n = le(e, t);
178
+ return n ? { color: n.color, hollow: n.hollow } : { color: o };
179
+ }, De = ({
180
+ value: e,
181
+ pipColor: o,
182
+ pipColors: t
183
+ }) => {
184
+ const { color: n, hollow: r } = ke(e, o, t), l = Ce(e);
185
+ return /* @__PURE__ */ b(re, { children: l.map((i, s) => /* @__PURE__ */ b(
186
+ $e,
187
+ {
188
+ row: i.row,
189
+ col: i.col,
190
+ gridSize: i.gridSize,
191
+ color: n,
192
+ hollow: r,
193
+ top: i.top,
194
+ left: i.left
195
+ },
196
+ s
197
+ )) });
198
+ }, ee = ({
199
+ value: e,
200
+ pipColor: o,
201
+ pipColors: t
202
+ }) => /* @__PURE__ */ b(
203
+ "div",
204
+ {
205
+ style: {
206
+ width: "100%",
207
+ height: "100%",
208
+ position: "relative",
209
+ padding: "0",
210
+ overflow: "hidden"
211
+ },
212
+ children: /* @__PURE__ */ b(De, { value: e, pipColor: o, pipColors: t })
213
+ }
214
+ ), ie = ({
215
+ value1: e = 0,
216
+ value2: o = 0,
217
+ width: t = 100,
218
+ height: n = 200,
219
+ backgroundColor: r = "white",
220
+ pipColor: l = "black",
221
+ pipColors: i,
222
+ borderColor: s = "black",
223
+ rotation: a = 0
224
+ }) => {
225
+ const u = Math.min(Math.max(e, 0), 12), f = Math.min(Math.max(o, 0), 12);
226
+ return /* @__PURE__ */ T(
227
+ "div",
228
+ {
229
+ style: {
230
+ width: `${t}px`,
231
+ height: `${n}px`,
232
+ backgroundColor: r,
233
+ borderColor: s,
234
+ borderWidth: "1px",
235
+ borderStyle: "solid",
236
+ borderRadius: "10px",
237
+ transform: `rotate(${a}deg)`,
238
+ transformOrigin: "center center",
239
+ boxShadow: "0 1px 2px rgba(0,0,0,0.2)",
240
+ display: "flex",
241
+ flexDirection: "column",
242
+ overflow: "hidden"
243
+ },
244
+ children: [
245
+ /* @__PURE__ */ b(
246
+ "div",
247
+ {
248
+ style: {
249
+ flex: 1,
250
+ position: "relative",
251
+ borderBottomWidth: "1px",
252
+ borderBottomStyle: "solid",
253
+ borderBottomColor: s
254
+ },
255
+ children: /* @__PURE__ */ b(ee, { value: u, pipColor: l, pipColors: i })
256
+ }
257
+ ),
258
+ /* @__PURE__ */ b(
259
+ "div",
260
+ {
261
+ style: {
262
+ flex: 1,
263
+ position: "relative"
264
+ },
265
+ children: /* @__PURE__ */ b(ee, { value: f, pipColor: l, pipColors: i })
266
+ }
267
+ )
268
+ ]
269
+ }
270
+ );
271
+ }, D = 60, I = 120, Ie = [-45, 45];
272
+ function oe(e, o = D, t = I) {
273
+ return e ? o / 2 : t / 2;
274
+ }
275
+ function k(e, o, t = D, n = I) {
276
+ return oe(e, t, n) + oe(o, t, n);
277
+ }
278
+ function _(e) {
279
+ const o = e * Math.PI / 180;
280
+ return {
281
+ dirX: Math.cos(o),
282
+ dirY: Math.sin(o)
283
+ };
284
+ }
285
+ function N(e) {
286
+ const { dirX: o, dirY: t } = _(e);
287
+ return { perpX: -t, perpY: o };
288
+ }
289
+ function Te(e, o) {
290
+ const t = e.map((n) => ({ ...n }));
291
+ for (let n = 1; n < t.length; n++) {
292
+ const r = t[n], i = t[n - 1].value2, s = r.value1 === r.value2;
293
+ if (o === "linear" && !s) {
294
+ t[n] = { value1: r.value2, value2: r.value1 };
295
+ continue;
296
+ }
297
+ o === "offset" && !s && r.value1 !== i && r.value2 === i && (t[n] = { value1: r.value2, value2: r.value1 });
298
+ }
299
+ return t;
300
+ }
301
+ function j(e) {
302
+ const { dirX: o, dirY: t } = _(e);
303
+ return Math.abs(o) >= Math.abs(t) ? o >= 0 ? 1 : -1 : t >= 0 ? 1 : -1;
304
+ }
305
+ function se(e, o) {
306
+ return e === 0 ? o : e === o ? -o : o;
307
+ }
308
+ function Oe({
309
+ startX: e,
310
+ startY: o,
311
+ angle: t,
312
+ dominoes: n,
313
+ layoutStyle: r,
314
+ dominoWidth: l = D,
315
+ dominoHeight: i = I,
316
+ leadGap: s = i * 0.3,
317
+ outwardSign: a,
318
+ hubIndex: u
319
+ }) {
320
+ const f = [], { dirX: c, dirY: d } = _(t), { perpX: v, perpY: y } = N(t), x = Te([...n], r), w = a ?? j(t), z = r === "offset" && u != null, $ = [];
321
+ let m = e + c * s, p = o + d * s, h = 0, M = 0;
322
+ const O = l / 2, A = (g) => {
323
+ const S = (g - h) * O;
324
+ m += v * S, p += y * S, h = g;
325
+ };
326
+ for (let g = 0; g < x.length; g++) {
327
+ const S = x[g], E = S.value1 === S.value2, C = g > 0 && x[g - 1].value1 === x[g - 1].value2;
328
+ r === "linear" ? g > 0 && (E ? (m += c * k(C, !0, l, i), p += d * k(C, !0, l, i)) : C ? (m += c * k(!0, !1, l, i), p += d * k(!0, !1, l, i)) : (m += c * i, p += d * i)) : E ? g > 0 && (m += c * k(C, !0, l, i), p += d * k(C, !0, l, i)) : (g === 0 ? M = w : C ? (m += c * k(!0, !1, l, i), p += d * k(!0, !1, l, i)) : (m += c * (i / 2), p += d * (i / 2), M = se(M, w)), A(M)), $.push(h), f.push({
329
+ x: m,
330
+ y: p,
331
+ rotation: E ? t + 180 : t - 90,
332
+ isDouble: E,
333
+ value1: S.value1,
334
+ value2: S.value2
335
+ });
336
+ }
337
+ if (z && u != null) {
338
+ const g = -$[u] * O;
339
+ if (g !== 0)
340
+ for (let S = 0; S < f.length; S++)
341
+ f[S] = {
342
+ ...f[S],
343
+ x: f[S].x + v * g,
344
+ y: f[S].y + y * g
345
+ };
346
+ }
347
+ return f;
348
+ }
349
+ function te(e, o = D, t = I) {
350
+ const n = e.rotation * Math.PI / 180, r = Math.cos(n), l = Math.sin(n), i = o / 2, s = t / 2;
351
+ return [
352
+ [-i, -s],
353
+ [i, -s],
354
+ [i, s],
355
+ [-i, s]
356
+ ].map(([a, u]) => ({
357
+ x: e.x + a * r - u * l,
358
+ y: e.y + a * l + u * r
359
+ }));
360
+ }
361
+ function Pe(e, o, t) {
362
+ let n = 1 / 0, r = -1 / 0, l = 1 / 0, i = -1 / 0;
363
+ for (const s of e) {
364
+ const a = s.x * t.x + s.y * t.y;
365
+ n = Math.min(n, a), r = Math.max(r, a);
366
+ }
367
+ for (const s of o) {
368
+ const a = s.x * t.x + s.y * t.y;
369
+ l = Math.min(l, a), i = Math.max(i, a);
370
+ }
371
+ return Math.min(r, i) - Math.max(n, l);
372
+ }
373
+ function ae(e, o, t = 1, n = D, r = I) {
374
+ const l = te(e, n, r), i = te(o, n, r);
375
+ for (const s of [l, i])
376
+ for (let a = 0; a < 4; a++) {
377
+ const u = s[a], f = s[(a + 1) % 4], c = f.x - u.x, d = f.y - u.y, v = Math.hypot(c, d) || 1, y = { x: -d / v, y: c / v };
378
+ if (Pe(l, i, y) <= t)
379
+ return !1;
380
+ }
381
+ return !0;
382
+ }
383
+ function Ee(e, o, t, n) {
384
+ return o.some(
385
+ (r) => ae(e, r, 1, t, n)
386
+ );
387
+ }
388
+ const P = D / 4, ne = 24;
389
+ function ue({
390
+ startX: e,
391
+ startY: o,
392
+ angle: t,
393
+ branch: n,
394
+ layoutStyle: r,
395
+ dominoWidth: l = D,
396
+ dominoHeight: i = I,
397
+ leadGap: s,
398
+ depth: a = 0,
399
+ anchor: u,
400
+ outwardSign: f,
401
+ placed: c = [],
402
+ pushAxis: d,
403
+ minPushSteps: v = 0
404
+ }) {
405
+ const y = f ?? j(t), x = n.feet ? Object.keys(n.feet).map(Number).filter((p) => {
406
+ const h = n.dominoes[p];
407
+ return h && h.value1 === h.value2;
408
+ }).sort((p, h) => p - h)[0] : void 0, w = (p, h) => Oe({
409
+ startX: p,
410
+ startY: h,
411
+ angle: t,
412
+ dominoes: n.dominoes,
413
+ layoutStyle: r,
414
+ dominoWidth: l,
415
+ dominoHeight: i,
416
+ leadGap: s,
417
+ outwardSign: y,
418
+ hubIndex: x
419
+ });
420
+ let z = w(
421
+ e + (d?.x ?? 0) * P * v,
422
+ o + (d?.y ?? 0) * P * v
423
+ ), $ = u && d ? {
424
+ x: u.x + d.x * P * v,
425
+ y: u.y + d.y * P * v
426
+ } : u;
427
+ if (d && c.length > 0)
428
+ for (let p = v; p <= ne; p++) {
429
+ const h = e + d.x * P * p, M = o + d.y * P * p, O = w(h, M);
430
+ if (!O.some(
431
+ (g) => Ee(g, c, l, i)
432
+ ) || p === ne) {
433
+ z = O, $ = u && {
434
+ x: u.x + d.x * P * p,
435
+ y: u.y + d.y * P * p
436
+ };
437
+ break;
438
+ }
439
+ }
440
+ c.push(...z);
441
+ const m = [
442
+ {
443
+ angle: t,
444
+ depth: a,
445
+ layoutStyle: r,
446
+ outwardSign: y,
447
+ dominoes: n.dominoes,
448
+ layout: z,
449
+ anchor: $
450
+ }
451
+ ];
452
+ if (n.feet) {
453
+ const { dirX: p, dirY: h } = _(t), { perpX: M, perpY: O } = N(t), A = l / 2, g = i / 2;
454
+ for (const S of Object.keys(n.feet)) {
455
+ const E = Number(S), C = z[E], q = n.feet[E];
456
+ if (!(!C || !C.isDouble || !q))
457
+ for (let L = 0; L < q.length; L++) {
458
+ const he = q[L], J = Ie[L] ?? 0, R = Math.sign(J), Q = t + J, Z = N(Q), V = -R, be = C.x + p * (l / 2) + M * (i / 2) * R, we = C.y + h * (l / 2) + O * (i / 2) * R, H = be - Z.perpX * V * A, W = we - Z.perpY * V * A;
459
+ m.push(
460
+ ...ue({
461
+ startX: H,
462
+ startY: W,
463
+ angle: Q,
464
+ branch: he,
465
+ // Toes inherit the main style so they zigzag in offset mode.
466
+ layoutStyle: r,
467
+ dominoWidth: l,
468
+ dominoHeight: i,
469
+ leadGap: g,
470
+ outwardSign: V,
471
+ depth: a + 1,
472
+ anchor: { x: H, y: W },
473
+ placed: c,
474
+ // If the snug spot is still blocked (the offset center toe leans into
475
+ // one side), slide this toe along the double's open edge, away from
476
+ // center, until it clears. This keeps it butted against the double
477
+ // while stepping past the obstacle — independent per toe, so a foot
478
+ // ends up snug and only as asymmetric as the obstruction requires.
479
+ pushAxis: { x: M * R, y: O * R }
480
+ })
481
+ );
482
+ }
483
+ }
484
+ }
485
+ return m;
486
+ }
487
+ function Fe(e) {
488
+ return e.flatMap((o) => o.layout);
489
+ }
490
+ function io(e, o = 24, t = D, n = I) {
491
+ const r = Math.hypot(t, n) / 2;
492
+ if (e.length === 0)
493
+ return {
494
+ width: o * 2 + t,
495
+ height: o * 2 + n,
496
+ offsetX: o,
497
+ offsetY: o
498
+ };
499
+ let l = 1 / 0, i = 1 / 0, s = -1 / 0, a = -1 / 0;
500
+ for (const u of e)
501
+ l = Math.min(l, u.x - r), i = Math.min(i, u.y - r), s = Math.max(s, u.x + r), a = Math.max(a, u.y + r);
502
+ return {
503
+ width: Math.ceil(s - l + o * 2),
504
+ height: Math.ceil(a - i + o * 2),
505
+ offsetX: o - l,
506
+ offsetY: o - i
507
+ };
508
+ }
509
+ const Ae = ({
510
+ startX: e,
511
+ startY: o,
512
+ angle: t,
513
+ trainData: n,
514
+ layoutStyle: r,
515
+ tableWidth: l,
516
+ tableHeight: i,
517
+ centerX: s,
518
+ centerY: a,
519
+ pipColors: u
520
+ }) => {
521
+ const f = Se(
522
+ () => Fe(
523
+ ue({
524
+ startX: e,
525
+ startY: o,
526
+ angle: t,
527
+ branch: { dominoes: n.dominoes, feet: n.feet },
528
+ layoutStyle: r
529
+ })
530
+ ),
531
+ [
532
+ e,
533
+ o,
534
+ t,
535
+ n.dominoes,
536
+ n.feet,
537
+ r,
538
+ l,
539
+ i
540
+ ]
541
+ );
542
+ return /* @__PURE__ */ b(re, { children: f.map((c, d) => {
543
+ const v = n.isPublic;
544
+ return /* @__PURE__ */ b(
545
+ "div",
546
+ {
547
+ style: {
548
+ position: "absolute",
549
+ left: `${c.x - D / 2}px`,
550
+ top: `${c.y - I / 2}px`,
551
+ zIndex: 5
552
+ },
553
+ children: /* @__PURE__ */ b(
554
+ ie,
555
+ {
556
+ value1: c.value1,
557
+ value2: c.value2,
558
+ width: D,
559
+ height: I,
560
+ backgroundColor: "white",
561
+ pipColor: "black",
562
+ pipColors: u,
563
+ borderColor: v ? "red" : "black",
564
+ rotation: c.rotation
565
+ }
566
+ )
567
+ },
568
+ `main-train-${n.playerId}-${d}`
569
+ );
570
+ }) });
571
+ }, Re = ({
572
+ playerCount: e,
573
+ centerX: o,
574
+ centerY: t,
575
+ radius: n,
576
+ engineValue: r,
577
+ trains: l,
578
+ layoutStyle: i,
579
+ tableWidth: s,
580
+ tableHeight: a,
581
+ pipColors: u
582
+ }) => {
583
+ const f = Math.max(8, e), c = 120;
584
+ return /* @__PURE__ */ T("div", { style: { position: "relative", width: "100%", height: "100%" }, children: [
585
+ /* @__PURE__ */ b(
586
+ "div",
587
+ {
588
+ style: {
589
+ position: "absolute",
590
+ width: `${c}px`,
591
+ height: `${c}px`,
592
+ left: `${o - c / 2}px`,
593
+ top: `${t - c / 2}px`,
594
+ backgroundColor: "#d1d5db",
595
+ borderWidth: "3px",
596
+ borderStyle: "solid",
597
+ borderColor: "#6b7280",
598
+ borderRadius: "50%",
599
+ boxShadow: "0 4px 6px rgba(0,0,0,0.1)",
600
+ zIndex: 10,
601
+ display: "flex",
602
+ justifyContent: "center",
603
+ alignItems: "center"
604
+ },
605
+ children: /* @__PURE__ */ b("div", { style: { transform: "rotate(0deg)" }, children: /* @__PURE__ */ b(
606
+ ie,
607
+ {
608
+ value1: r,
609
+ value2: r,
610
+ width: 60,
611
+ height: 120,
612
+ backgroundColor: "white",
613
+ pipColor: "black",
614
+ pipColors: u,
615
+ borderColor: "#333"
616
+ }
617
+ ) })
618
+ }
619
+ ),
620
+ Array.from({ length: f }).map((y, x) => {
621
+ const w = x * 360 / f, z = w * Math.PI / 180, $ = o + (n + 20) * Math.cos(z), m = t + (n + 20) * Math.sin(z), p = l.find((h) => h.playerId === x) || {
622
+ dominoes: [],
623
+ playerId: x,
624
+ isPublic: !1
625
+ };
626
+ return /* @__PURE__ */ b(
627
+ Ae,
628
+ {
629
+ startX: $,
630
+ startY: m,
631
+ angle: w,
632
+ trainData: p,
633
+ layoutStyle: i,
634
+ tableWidth: s,
635
+ tableHeight: a,
636
+ centerX: o,
637
+ centerY: t,
638
+ pipColors: u
639
+ },
640
+ x
641
+ );
642
+ })
643
+ ] });
644
+ };
645
+ function F(e, o) {
646
+ return e <= o ? `${e}:${o}` : `${o}:${e}`;
647
+ }
648
+ function ce(e) {
649
+ return F(e.value1, e.value2);
650
+ }
651
+ function de(e) {
652
+ return e.value1 === e.value2;
653
+ }
654
+ function so(e, o) {
655
+ return e.value1 === o || e.value2 === o;
656
+ }
657
+ function ao(e, o) {
658
+ return e.value1 === o ? e.value2 : e.value2 === o ? e.value1 : null;
659
+ }
660
+ function fe(e, o) {
661
+ return e.value1 === o ? { value1: e.value1, value2: e.value2 } : e.value2 === o ? { value1: e.value2, value2: e.value1 } : null;
662
+ }
663
+ function uo(e) {
664
+ const o = [];
665
+ for (let t = 0; t <= e; t++)
666
+ for (let n = t; n <= e; n++)
667
+ o.push({ value1: t, value2: n });
668
+ return o;
669
+ }
670
+ function co(e) {
671
+ const o = e + 1;
672
+ return o * (o + 1) / 2;
673
+ }
674
+ function Xe(e, o = 12, t = {}) {
675
+ const n = /* @__PURE__ */ new Set([F(o, o)]), r = [];
676
+ for (let l = 0; l < e; l++) {
677
+ const i = 4 + Math.floor(Math.random() * 7), s = [];
678
+ let a = o, u = !1;
679
+ for (let c = 0; c < i; c++) {
680
+ const d = Ne(
681
+ a,
682
+ u,
683
+ c === 0,
684
+ o,
685
+ n
686
+ );
687
+ if (d === null)
688
+ break;
689
+ const v = d === a;
690
+ n.add(F(a, d)), s.push({ value1: a, value2: d }), u = v, a = d;
691
+ }
692
+ const f = t.chickenFeet ? _e(s, n) : void 0;
693
+ r.push({
694
+ playerId: l,
695
+ dominoes: s,
696
+ isPublic: Math.random() > 0.7,
697
+ ...f ? { feet: f } : {}
698
+ });
699
+ }
700
+ return r;
701
+ }
702
+ function _e(e, o) {
703
+ const t = {};
704
+ for (let n = 0; n < e.length; n++) {
705
+ if (e[n].value1 !== e[n].value2)
706
+ continue;
707
+ const r = e[n].value1, l = [];
708
+ for (let i = 0; i < 2; i++) {
709
+ const s = Le(r, o);
710
+ s && l.push(s);
711
+ }
712
+ l.length && (t[n] = l);
713
+ }
714
+ return Object.keys(t).length ? t : void 0;
715
+ }
716
+ function Le(e, o) {
717
+ const t = 1 + Math.floor(Math.random() * 2), n = [];
718
+ let r = e;
719
+ for (let l = 0; l < t; l++) {
720
+ const i = Ye(r, o);
721
+ if (i === null)
722
+ break;
723
+ o.add(F(r, i)), n.push({ value1: r, value2: i }), r = i;
724
+ }
725
+ return n.length ? { dominoes: n } : null;
726
+ }
727
+ function Ye(e, o) {
728
+ const t = [];
729
+ for (let n = 0; n < 13; n++)
730
+ n !== e && (o.has(F(e, n)) || t.push(n));
731
+ return t.length === 0 ? null : t[Math.floor(Math.random() * t.length)];
732
+ }
733
+ function Ne(e, o, t, n, r) {
734
+ const l = Array.from({ length: 13 }, (i, s) => s).filter(
735
+ (i) => je(
736
+ e,
737
+ i,
738
+ o,
739
+ t,
740
+ n,
741
+ r
742
+ )
743
+ );
744
+ return l.length === 0 ? null : l[Math.floor(Math.random() * l.length)];
745
+ }
746
+ function je(e, o, t, n, r, l) {
747
+ const i = o === e;
748
+ return !(n && i && e === r || i && t || l.has(F(e, o)));
749
+ }
750
+ const Be = {
751
+ playerCount: 8,
752
+ trains: [],
753
+ engineValue: 12
754
+ }, fo = ({
755
+ initialState: e = Be,
756
+ width: o = 1200,
757
+ height: t = 800,
758
+ pipColors: n,
759
+ onPipColorsChange: r
760
+ }) => {
761
+ const [l, i] = Y(e), [s, a] = Y("offset"), [u, f] = Y(!1), [c, d] = Y(void 0), v = n ?? c, y = r ?? d, x = v !== void 0, w = o / 2, z = t / 2, $ = (p = u) => {
762
+ const h = Xe(
763
+ l.playerCount,
764
+ l.engineValue,
765
+ { chickenFeet: p }
766
+ );
767
+ i((M) => ({
768
+ ...M,
769
+ trains: h
770
+ }));
771
+ };
772
+ ye(() => {
773
+ $();
774
+ }, []);
775
+ const m = () => {
776
+ const p = !u;
777
+ f(p), $(p);
778
+ };
779
+ return /* @__PURE__ */ T(
780
+ "div",
781
+ {
782
+ style: {
783
+ width: `${o}px`,
784
+ height: `${t}px`,
785
+ position: "relative",
786
+ backgroundColor: "#1f8a55",
787
+ // Classic green felt background
788
+ borderRadius: "8px",
789
+ boxShadow: "0 4px 12px rgba(0,0,0,0.2)",
790
+ overflow: "hidden"
791
+ },
792
+ children: [
793
+ /* @__PURE__ */ T(
794
+ "div",
795
+ {
796
+ style: { position: "absolute", top: "10px", left: "10px", zIndex: 100 },
797
+ children: [
798
+ /* @__PURE__ */ b(
799
+ "button",
800
+ {
801
+ onClick: () => $(),
802
+ style: {
803
+ padding: "8px 12px",
804
+ backgroundColor: "#fff",
805
+ border: "1px solid #ccc",
806
+ borderRadius: "4px",
807
+ marginRight: "10px",
808
+ cursor: "pointer"
809
+ },
810
+ children: "New trains"
811
+ }
812
+ ),
813
+ /* @__PURE__ */ T(
814
+ "button",
815
+ {
816
+ onClick: () => a(s === "offset" ? "linear" : "offset"),
817
+ style: {
818
+ padding: "8px 12px",
819
+ backgroundColor: "#fff",
820
+ border: "1px solid #ccc",
821
+ borderRadius: "4px",
822
+ marginRight: "10px",
823
+ cursor: "pointer"
824
+ },
825
+ children: [
826
+ "Layout: ",
827
+ s === "offset" ? "Offset" : "Linear"
828
+ ]
829
+ }
830
+ ),
831
+ /* @__PURE__ */ T(
832
+ "button",
833
+ {
834
+ onClick: m,
835
+ style: {
836
+ padding: "8px 12px",
837
+ backgroundColor: u ? "#fef3c7" : "#fff",
838
+ border: `1px solid ${u ? "#f59e0b" : "#ccc"}`,
839
+ borderRadius: "4px",
840
+ marginRight: "10px",
841
+ cursor: "pointer"
842
+ },
843
+ children: [
844
+ "Chicken Feet: ",
845
+ u ? "On" : "Off"
846
+ ]
847
+ }
848
+ ),
849
+ /* @__PURE__ */ T(
850
+ "button",
851
+ {
852
+ onClick: () => y(x ? void 0 : X),
853
+ style: {
854
+ padding: "8px 12px",
855
+ backgroundColor: x ? "#fef3c7" : "#fff",
856
+ border: `1px solid ${x ? "#f59e0b" : "#ccc"}`,
857
+ borderRadius: "4px",
858
+ cursor: "pointer"
859
+ },
860
+ children: [
861
+ "Pip Colors: ",
862
+ x ? "On" : "Off"
863
+ ]
864
+ }
865
+ )
866
+ ]
867
+ }
868
+ ),
869
+ /* @__PURE__ */ T(
870
+ "div",
871
+ {
872
+ style: {
873
+ position: "absolute",
874
+ top: "10px",
875
+ right: "10px",
876
+ zIndex: 100,
877
+ backgroundColor: "rgba(255,255,255,0.8)",
878
+ padding: "8px",
879
+ borderRadius: "4px",
880
+ fontSize: "14px"
881
+ },
882
+ children: [
883
+ /* @__PURE__ */ T("div", { children: [
884
+ "Engine: Double-",
885
+ l.engineValue
886
+ ] }),
887
+ /* @__PURE__ */ T("div", { children: [
888
+ "Players: ",
889
+ l.playerCount
890
+ ] })
891
+ ]
892
+ }
893
+ ),
894
+ /* @__PURE__ */ b(
895
+ Re,
896
+ {
897
+ playerCount: l.playerCount,
898
+ centerX: w,
899
+ centerY: z,
900
+ radius: 80,
901
+ engineValue: l.engineValue,
902
+ trains: l.trains,
903
+ layoutStyle: s,
904
+ tableWidth: o,
905
+ tableHeight: t,
906
+ pipColors: v
907
+ }
908
+ )
909
+ ]
910
+ }
911
+ );
912
+ }, B = 1;
913
+ function pe(e, o, t) {
914
+ const { dirX: n, dirY: r } = _(t);
915
+ return e * n + o * r;
916
+ }
917
+ function Ue(e, o, t) {
918
+ const { perpX: n, perpY: r } = N(t);
919
+ return e * n + o * r;
920
+ }
921
+ function K(e) {
922
+ const o = [];
923
+ for (let t = 1; t < e.length; t++)
924
+ e[t].value1 !== e[t - 1].value2 && o.push({
925
+ code: "chain-break",
926
+ message: `Domino ${t} does not connect to domino ${t - 1}`,
927
+ index: t
928
+ });
929
+ for (let t = 1; t < e.length; t++) {
930
+ const n = e[t - 1].value1 === e[t - 1].value2, r = e[t].value1 === e[t].value2;
931
+ n && r && o.push({
932
+ code: "consecutive-doubles",
933
+ message: `Consecutive doubles at index ${t - 1} and ${t}`,
934
+ index: t
935
+ });
936
+ }
937
+ return { valid: o.length === 0, issues: o };
938
+ }
939
+ function ve(e, o, t, n = D, r = I) {
940
+ const l = n / 2, i = e.map((c) => c.isDouble), s = [];
941
+ let a = 0, u = 0, f = 0;
942
+ for (let c = 0; c < e.length; c++) {
943
+ const d = i[c], v = c > 0 && i[c - 1];
944
+ o === "linear" ? (c > 0 && (a += k(v, d, n, r)), u = 0) : d ? c > 0 && (a += k(v, !0, n, r)) : c === 0 ? (f = t, u = f * l) : v ? a += k(!0, !1, n, r) : (a += r / 2, f = se(f, t), u = f * l), s.push({ along: a, perp: u });
945
+ }
946
+ return s;
947
+ }
948
+ function qe(e, o, t, n = B, r) {
949
+ const l = [], i = r ?? j(o), s = ve(e, t, i);
950
+ for (let a = 1; a < e.length; a++) {
951
+ const u = e[a - 1], f = e[a], c = f.x - u.x, d = f.y - u.y, v = pe(c, d, o), y = Ue(c, d, o), x = s[a].along - s[a - 1].along, w = s[a].perp - s[a - 1].perp;
952
+ Math.abs(v - x) > n && l.push({
953
+ code: "spacing-along-train",
954
+ message: `Along-train spacing between domino ${a - 1} and ${a} is ${v.toFixed(2)}px (expected ${x}px)`,
955
+ index: a
956
+ }), Math.abs(y - w) > n && l.push({
957
+ code: "spacing-perpendicular",
958
+ message: `Perpendicular spacing between domino ${a - 1} and ${a} is ${y.toFixed(2)}px (expected ${w}px)`,
959
+ index: a
960
+ });
961
+ }
962
+ return { valid: l.length === 0, issues: l };
963
+ }
964
+ function Ve(e, o, t, n = B, r) {
965
+ const l = [], i = r ?? j(o), s = ve(e, t, i);
966
+ for (let a = 1; a < e.length; a++) {
967
+ const u = e[a - 1], f = e[a], c = f.x - u.x, d = f.y - u.y, v = Math.hypot(c, d), y = s[a].along - s[a - 1].along, x = s[a].perp - s[a - 1].perp, w = Math.hypot(y, x) * 0.9;
968
+ v + n < w && l.push({
969
+ code: "overlap",
970
+ message: `Domino ${a - 1} and ${a} centers are ${v.toFixed(2)}px apart (minimum ${w.toFixed(2)}px)`,
971
+ index: a
972
+ });
973
+ }
974
+ return { valid: l.length === 0, issues: l };
975
+ }
976
+ function po(e, o, t, n, r = B, l) {
977
+ const i = [
978
+ ...K(o).issues,
979
+ ...qe(
980
+ e,
981
+ t,
982
+ n,
983
+ r,
984
+ l
985
+ ).issues,
986
+ ...Ve(
987
+ e,
988
+ t,
989
+ n,
990
+ r,
991
+ l
992
+ ).issues
993
+ ];
994
+ return e.length !== o.length && i.push({
995
+ code: "layout-length",
996
+ message: `Layout length ${e.length} does not match domino count ${o.length}`
997
+ }), { valid: i.length === 0, issues: i };
998
+ }
999
+ function vo(e) {
1000
+ const o = [], t = (n, r) => {
1001
+ if (o.push(
1002
+ ...K(n.dominoes).issues.map((l) => ({
1003
+ ...l,
1004
+ message: `[${r}] ${l.message}`
1005
+ }))
1006
+ ), !!n.feet)
1007
+ for (const l of Object.keys(n.feet)) {
1008
+ const i = Number(l), s = n.dominoes[i], a = n.feet[i] ?? [];
1009
+ if (!s) {
1010
+ o.push({
1011
+ code: "foot-host-missing",
1012
+ message: `[${r}] Foot references missing tile ${i}`
1013
+ });
1014
+ continue;
1015
+ }
1016
+ s.value1 !== s.value2 && o.push({
1017
+ code: "foot-host-not-double",
1018
+ message: `[${r}] Foot host tile ${i} is not a double`
1019
+ }), a.length > 2 && o.push({
1020
+ code: "foot-too-many-toes",
1021
+ message: `[${r}] Double ${i} has ${a.length} side toes (max 2; the center toe is the main line)`
1022
+ }), a.forEach((u, f) => {
1023
+ const c = u.dominoes[0];
1024
+ c && c.value1 !== s.value1 && o.push({
1025
+ code: "foot-connection",
1026
+ message: `[${r}] Toe ${f} on double ${i} starts with ${c.value1} but the double is ${s.value1}`
1027
+ }), t(u, `${r}.${i}.${f}`);
1028
+ });
1029
+ }
1030
+ };
1031
+ return t(e, "main"), { valid: o.length === 0, issues: o };
1032
+ }
1033
+ function xo(e, o = B) {
1034
+ const t = [];
1035
+ e.forEach((r, l) => {
1036
+ if (t.push(
1037
+ ...K(r.dominoes).issues.map((i) => ({
1038
+ ...i,
1039
+ message: `[segment ${l} @${r.angle}°] ${i.message}`
1040
+ }))
1041
+ ), r.layout.length !== r.dominoes.length && t.push({
1042
+ code: "layout-length",
1043
+ message: `[segment ${l}] Layout length ${r.layout.length} does not match domino count ${r.dominoes.length}`
1044
+ }), r.anchor && r.layout.length > 0) {
1045
+ const i = r.layout[0], s = pe(
1046
+ i.x - r.anchor.x,
1047
+ i.y - r.anchor.y,
1048
+ r.angle
1049
+ ), a = I / 2;
1050
+ Math.abs(s - a) > o && t.push({
1051
+ code: "foot-anchor",
1052
+ message: `[segment ${l}] First toe tile sits ${s.toFixed(2)}px from the double along the toe (expected ${a}px)`,
1053
+ index: 0
1054
+ });
1055
+ }
1056
+ });
1057
+ const n = e.flatMap((r) => r.layout);
1058
+ for (let r = 0; r < n.length; r++)
1059
+ for (let l = r + 1; l < n.length; l++)
1060
+ ae(n[r], n[l]) && t.push({
1061
+ code: "tile-overlap",
1062
+ message: `Tiles ${r} and ${l} overlap`,
1063
+ index: l
1064
+ });
1065
+ return { valid: t.length === 0, issues: t };
1066
+ }
1067
+ const go = [
1068
+ {
1069
+ id: "regular-after-double",
1070
+ name: "Regular after double",
1071
+ description: "Double followed by a two-tile offset run",
1072
+ angle: 0,
1073
+ dominoes: [
1074
+ { value1: 12, value2: 6 },
1075
+ { value1: 6, value2: 6 },
1076
+ { value1: 6, value2: 3 },
1077
+ { value1: 3, value2: 1 }
1078
+ ],
1079
+ layoutStyles: ["linear", "offset"]
1080
+ },
1081
+ {
1082
+ id: "double-after-regular",
1083
+ name: "Double after regular",
1084
+ description: "Offset run, a double, then another offset run",
1085
+ angle: 0,
1086
+ dominoes: [
1087
+ { value1: 12, value2: 9 },
1088
+ { value1: 9, value2: 4 },
1089
+ { value1: 4, value2: 4 },
1090
+ { value1: 4, value2: 2 },
1091
+ { value1: 2, value2: 7 }
1092
+ ],
1093
+ layoutStyles: ["linear", "offset"]
1094
+ },
1095
+ {
1096
+ id: "double-after-double",
1097
+ name: "Double after double",
1098
+ description: "Offset runs at the head, middle, and tail around two doubles",
1099
+ angle: 90,
1100
+ dominoes: [
1101
+ { value1: 12, value2: 7 },
1102
+ { value1: 7, value2: 8 },
1103
+ { value1: 8, value2: 8 },
1104
+ { value1: 8, value2: 3 },
1105
+ { value1: 3, value2: 5 },
1106
+ { value1: 5, value2: 5 },
1107
+ { value1: 5, value2: 2 },
1108
+ { value1: 2, value2: 1 }
1109
+ ],
1110
+ layoutStyles: ["linear", "offset"]
1111
+ },
1112
+ {
1113
+ id: "offset-zigzag",
1114
+ name: "Offset zigzag",
1115
+ description: "Alternating perpendicular tiles without doubles",
1116
+ angle: 0,
1117
+ dominoes: [
1118
+ { value1: 12, value2: 5 },
1119
+ { value1: 5, value2: 9 },
1120
+ { value1: 9, value2: 2 },
1121
+ { value1: 2, value2: 7 },
1122
+ { value1: 7, value2: 1 }
1123
+ ],
1124
+ layoutStyles: ["offset"]
1125
+ },
1126
+ {
1127
+ id: "horizontal-open",
1128
+ name: "Horizontal train",
1129
+ description: "Rightward train: offset head, double, offset tail",
1130
+ angle: 0,
1131
+ dominoes: [
1132
+ { value1: 5, value2: 12 },
1133
+ { value1: 12, value2: 11 },
1134
+ { value1: 11, value2: 11 },
1135
+ { value1: 11, value2: 6 },
1136
+ { value1: 6, value2: 2 }
1137
+ ],
1138
+ layoutStyles: ["linear", "offset"]
1139
+ },
1140
+ {
1141
+ id: "vertical-open",
1142
+ name: "Vertical train",
1143
+ description: "Downward train: offset head, double, offset tail",
1144
+ angle: 90,
1145
+ dominoes: [
1146
+ { value1: 3, value2: 12 },
1147
+ { value1: 12, value2: 10 },
1148
+ { value1: 10, value2: 10 },
1149
+ { value1: 10, value2: 4 },
1150
+ { value1: 4, value2: 1 }
1151
+ ],
1152
+ layoutStyles: ["linear", "offset"]
1153
+ }
1154
+ ], ho = [
1155
+ {
1156
+ id: "single-foot",
1157
+ name: "Single foot",
1158
+ description: "A double fans two angled toes (±45°) while the main line continues straight as the center toe",
1159
+ angle: 0,
1160
+ branch: {
1161
+ dominoes: [
1162
+ { value1: 12, value2: 6 },
1163
+ { value1: 6, value2: 6 },
1164
+ { value1: 6, value2: 3 },
1165
+ { value1: 3, value2: 1 }
1166
+ ],
1167
+ feet: {
1168
+ 1: [
1169
+ {
1170
+ dominoes: [
1171
+ { value1: 6, value2: 2 },
1172
+ { value1: 2, value2: 5 }
1173
+ ]
1174
+ },
1175
+ {
1176
+ dominoes: [
1177
+ { value1: 6, value2: 4 },
1178
+ { value1: 4, value2: 0 }
1179
+ ]
1180
+ }
1181
+ ]
1182
+ }
1183
+ },
1184
+ layoutStyles: ["linear", "offset"]
1185
+ },
1186
+ {
1187
+ id: "foot-no-center",
1188
+ name: "Foot at the tail",
1189
+ description: "Double ends the main line, so both side toes are present with no straight continuation",
1190
+ angle: 0,
1191
+ branch: {
1192
+ dominoes: [
1193
+ { value1: 9, value2: 7 },
1194
+ { value1: 7, value2: 7 }
1195
+ ],
1196
+ feet: {
1197
+ 1: [
1198
+ {
1199
+ dominoes: [
1200
+ { value1: 7, value2: 3 },
1201
+ { value1: 3, value2: 8 }
1202
+ ]
1203
+ },
1204
+ {
1205
+ dominoes: [
1206
+ { value1: 7, value2: 5 },
1207
+ { value1: 5, value2: 0 }
1208
+ ]
1209
+ }
1210
+ ]
1211
+ }
1212
+ },
1213
+ layoutStyles: ["linear", "offset"]
1214
+ },
1215
+ {
1216
+ id: "nested-foot",
1217
+ name: "Nested foot",
1218
+ description: "A side toe contains its own double, which sprouts a second-level foot",
1219
+ angle: 90,
1220
+ branch: {
1221
+ dominoes: [
1222
+ { value1: 12, value2: 8 },
1223
+ { value1: 8, value2: 8 },
1224
+ { value1: 8, value2: 3 }
1225
+ ],
1226
+ feet: {
1227
+ 1: [
1228
+ {
1229
+ dominoes: [
1230
+ { value1: 8, value2: 5 },
1231
+ { value1: 5, value2: 5 },
1232
+ { value1: 5, value2: 2 }
1233
+ ],
1234
+ feet: {
1235
+ 1: [
1236
+ {
1237
+ dominoes: [
1238
+ { value1: 5, value2: 9 },
1239
+ { value1: 9, value2: 1 }
1240
+ ]
1241
+ },
1242
+ {
1243
+ dominoes: [
1244
+ { value1: 5, value2: 4 },
1245
+ { value1: 4, value2: 6 }
1246
+ ]
1247
+ }
1248
+ ]
1249
+ }
1250
+ },
1251
+ {
1252
+ dominoes: [
1253
+ { value1: 8, value2: 1 },
1254
+ { value1: 1, value2: 7 }
1255
+ ]
1256
+ }
1257
+ ]
1258
+ }
1259
+ },
1260
+ layoutStyles: ["linear", "offset"]
1261
+ }
1262
+ ], G = {
1263
+ maxPips: 12,
1264
+ engineValue: 12,
1265
+ allowConsecutiveDoubles: !1,
1266
+ requireUniqueTiles: !0,
1267
+ requireSequential: !0,
1268
+ doubleObligation: "cover",
1269
+ chickenFoot: {
1270
+ toeCount: 3,
1271
+ sideToeAngles: [-45, 45]
1272
+ }
1273
+ };
1274
+ function Ge(e) {
1275
+ switch (e.doubleObligation) {
1276
+ case "chicken-foot":
1277
+ return Math.max(1, e.chickenFoot.toeCount);
1278
+ case "cover":
1279
+ return 1;
1280
+ default:
1281
+ return 0;
1282
+ }
1283
+ }
1284
+ function Ke(e) {
1285
+ return e.doubleObligation === "chicken-foot" ? Math.max(0, e.chickenFoot.toeCount - 1) : 0;
1286
+ }
1287
+ function bo(e = {}) {
1288
+ const o = e.maxPips ?? G.maxPips;
1289
+ return {
1290
+ ...G,
1291
+ ...e,
1292
+ maxPips: o,
1293
+ engineValue: e.engineValue ?? o,
1294
+ chickenFoot: {
1295
+ ...G.chickenFoot,
1296
+ ...e.chickenFoot ?? {}
1297
+ }
1298
+ };
1299
+ }
1300
+ function Je(e, o) {
1301
+ let t = e;
1302
+ for (const n of o)
1303
+ if (t = t?.feet?.[n.doubleIndex]?.[n.toeIndex], !t) return;
1304
+ return t;
1305
+ }
1306
+ function U(e, o, t) {
1307
+ if (t(e, o), !!e.feet)
1308
+ for (const n of Object.keys(e.feet)) {
1309
+ const r = Number(n);
1310
+ e.feet[r].forEach((l, i) => {
1311
+ U(l, [...o, { doubleIndex: r, toeIndex: i }], t);
1312
+ });
1313
+ }
1314
+ }
1315
+ function Qe(e) {
1316
+ const o = [];
1317
+ return U(e, [], (t, n) => {
1318
+ t.dominoes.forEach((r, l) => {
1319
+ if (r.value1 !== r.value2) return;
1320
+ const i = l < t.dominoes.length - 1, s = t.feet?.[l]?.length ?? 0;
1321
+ o.push({
1322
+ path: n,
1323
+ doubleIndex: l,
1324
+ value: r.value1,
1325
+ hasCenter: i,
1326
+ sideToes: s,
1327
+ answers: (i ? 1 : 0) + s
1328
+ });
1329
+ });
1330
+ }), o;
1331
+ }
1332
+ function Ze(e, o) {
1333
+ const t = Ge(o);
1334
+ return t <= 0 ? [] : Qe(e).filter((n) => n.answers < t);
1335
+ }
1336
+ function He(e) {
1337
+ const o = /* @__PURE__ */ new Set();
1338
+ return U(e, [], (t) => {
1339
+ for (const n of t.dominoes)
1340
+ o.add(ce(n));
1341
+ }), o;
1342
+ }
1343
+ function We(e, o, t) {
1344
+ if (e.dominoes.length === 0)
1345
+ return [
1346
+ {
1347
+ path: [],
1348
+ attach: "run-tail",
1349
+ value: o,
1350
+ attachToDouble: !0,
1351
+ // a train starts off the engine double
1352
+ obligation: !1
1353
+ }
1354
+ ];
1355
+ const n = Ze(e, t);
1356
+ if (t.doubleObligation !== "none" && n.length > 0) {
1357
+ const l = Ke(t), i = [];
1358
+ for (const s of n) {
1359
+ const a = Je(e, s.path);
1360
+ a && (!s.hasCenter && s.doubleIndex === a.dominoes.length - 1 && i.push({
1361
+ path: s.path,
1362
+ attach: "run-tail",
1363
+ value: s.value,
1364
+ attachToDouble: !0,
1365
+ obligation: !0
1366
+ }), s.sideToes < l && i.push({
1367
+ path: s.path,
1368
+ attach: "side-toe",
1369
+ value: s.value,
1370
+ doubleIndex: s.doubleIndex,
1371
+ toeSlot: s.sideToes,
1372
+ attachToDouble: !0,
1373
+ obligation: !0
1374
+ }));
1375
+ }
1376
+ return i;
1377
+ }
1378
+ const r = [];
1379
+ return U(e, [], (l, i) => {
1380
+ const s = l.dominoes[l.dominoes.length - 1];
1381
+ s && r.push({
1382
+ path: i,
1383
+ attach: "run-tail",
1384
+ value: s.value2,
1385
+ attachToDouble: de(s),
1386
+ obligation: !1
1387
+ });
1388
+ }), r;
1389
+ }
1390
+ function xe(e, o, t, n) {
1391
+ const r = [], l = fe(e, o.value);
1392
+ return n.requireSequential && !l && r.push("value-mismatch"), n.requireUniqueTiles && t.has(ce(e)) && r.push("duplicate-tile"), !n.allowConsecutiveDoubles && o.attachToDouble && de(e) && r.push("consecutive-doubles"), { legal: r.length === 0, violations: r };
1393
+ }
1394
+ function wo(e, o, t, n, r) {
1395
+ const l = We(e, o, r), i = [];
1396
+ for (const s of l)
1397
+ for (const a of t)
1398
+ xe(a, s, n, r).legal && i.push({ end: s, tile: a });
1399
+ return i;
1400
+ }
1401
+ function ge(e, o, t) {
1402
+ if (o.length === 0)
1403
+ return t(e);
1404
+ const [n, ...r] = o, i = (e.feet?.[n.doubleIndex] ?? []).map(
1405
+ (s, a) => a === n.toeIndex ? ge(s, r, t) : s
1406
+ );
1407
+ return {
1408
+ ...e,
1409
+ feet: { ...e.feet, [n.doubleIndex]: i }
1410
+ };
1411
+ }
1412
+ function eo(e, o, t) {
1413
+ const n = fe(o.tile, o.end.value) ?? { ...o.tile };
1414
+ return ge(e, o.end.path, (r) => {
1415
+ if (o.end.attach === "run-tail")
1416
+ return { ...r, dominoes: [...r.dominoes, n] };
1417
+ const l = o.end.doubleIndex ?? 0, i = o.end.toeSlot ?? r.feet?.[l]?.length ?? 0, s = r.feet?.[l] ? [...r.feet[l]] : [];
1418
+ return s[i] = { dominoes: [n] }, {
1419
+ ...r,
1420
+ feet: { ...r.feet, [l]: s }
1421
+ };
1422
+ });
1423
+ }
1424
+ function So(e, o, t) {
1425
+ const n = xe(
1426
+ o.tile,
1427
+ o.end,
1428
+ He(e),
1429
+ t
1430
+ );
1431
+ return n.legal ? { ok: !0, board: eo(e, o), violations: [] } : { ok: !1, board: e, violations: n.violations };
1432
+ }
1433
+ export {
1434
+ ho as CHICKEN_FOOT_FIXTURES,
1435
+ Ie as CHICKEN_FOOT_TOE_ANGLES,
1436
+ X as DEFAULT_PIP_COLORS,
1437
+ G as DEFAULT_RULES,
1438
+ Re as DominoHub,
1439
+ Ae as DominoTrain,
1440
+ ie as DoubleTwelve,
1441
+ fo as MexicanTrainGame,
1442
+ no as PIP_COLORS,
1443
+ Me as PIP_LAYOUTS,
1444
+ go as TRAIN_FIXTURES,
1445
+ eo as applyMove,
1446
+ He as collectPlayedKeys,
1447
+ Oe as computeTrainLayout,
1448
+ ue as computeTrainTree,
1449
+ ce as dominoKey,
1450
+ co as dominoSetSize,
1451
+ xe as evaluatePlacement,
1452
+ Fe as flattenSegments,
1453
+ uo as generateDominoSet,
1454
+ Je as getBranchAt,
1455
+ wo as getLegalMoves,
1456
+ We as getOpenEnds,
1457
+ Ce as getPipLayout,
1458
+ lo as getPipStyle,
1459
+ io as getTrainLayoutBounds,
1460
+ Ze as getUnsatisfiedDoubles,
1461
+ de as isDouble,
1462
+ ro as mergePipColors,
1463
+ fe as orientForConnection,
1464
+ ao as otherEnd,
1465
+ j as outwardPerpSign,
1466
+ So as playMove,
1467
+ Ge as requiredDoubleAnswers,
1468
+ ze as resolvePipPosition,
1469
+ le as resolvePipStyle,
1470
+ bo as resolveRules,
1471
+ Ke as sideToeSlots,
1472
+ k as stepAlongTrain,
1473
+ te as tileCorners,
1474
+ so as tileHasValue,
1475
+ F as tileKey,
1476
+ ae as tilesOverlap,
1477
+ vo as validateChickenFootChain,
1478
+ po as validateTrainLayout,
1479
+ xo as validateTrainTree
1480
+ };
1481
+ //# sourceMappingURL=index.js.map