doubletwelve 0.1.0 → 0.3.1

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 CHANGED
@@ -1,48 +1,73 @@
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
- };
1
+ import { jsx as z, Fragment as we, jsxs as $ } from "react/jsx-runtime";
2
+ import { useContext as Se, createContext as Ke, useEffect as ae, useMemo as He, useState as G, useRef as ve, useCallback as Ze } from "react";
3
+ const Je = {};
4
+ function ze(e, t) {
5
+ return t ? {
6
+ ...e,
7
+ ...t,
8
+ tileDataAttributes: {
9
+ ...e.tileDataAttributes,
10
+ ...t.tileDataAttributes
11
+ }
12
+ } : e;
13
+ }
14
+ function Qe(e) {
15
+ if (!e)
16
+ return {};
17
+ const t = {};
18
+ for (const [o, n] of Object.entries(e))
19
+ n === void 0 || n === !1 || (t[`data-${o}`] = n === !0 ? "true" : String(n));
20
+ return t;
16
21
  }
17
- const $e = ({
18
- row: e,
19
- col: o,
20
- gridSize: t,
21
- color: n,
22
- hollow: r,
23
- top: l,
24
- left: i
22
+ const le = Ke(Je), sn = ({
23
+ theme: e,
24
+ children: t
25
25
  }) => {
26
- const s = ze({ row: e, col: o, gridSize: t, top: l, left: i });
27
- return /* @__PURE__ */ b(
26
+ const o = Se(le), n = ze(o, e);
27
+ return /* @__PURE__ */ z(le.Provider, { value: n, children: t });
28
+ };
29
+ function Ie(e) {
30
+ const t = Se(le);
31
+ return ze(t, e);
32
+ }
33
+ const We = ({ ctx: e, theme: t }) => {
34
+ const { row: o, col: n, gridSize: r, color: i, hollow: l, positionStyle: s } = e, a = t?.pipStyle?.(e) ?? {};
35
+ return /* @__PURE__ */ z(
28
36
  "div",
29
37
  {
30
38
  "data-testid": "pip",
31
- "data-row": e,
32
- "data-col": o,
33
- "data-grid": t,
39
+ "data-row": o,
40
+ "data-col": n,
41
+ "data-grid": r,
42
+ "data-pip-value": e.value,
43
+ "data-hollow": l ? "true" : void 0,
34
44
  style: {
35
45
  position: "absolute",
36
- backgroundColor: r ? "transparent" : n,
37
- border: r ? "2px solid #888" : void 0,
38
46
  borderRadius: "50%",
39
47
  transform: "translate(-50%, -50%)",
40
- boxShadow: r ? void 0 : "1px 2px 3px rgba(0,0,0,0.3)",
41
- ...s
48
+ backgroundColor: l ? "transparent" : i,
49
+ border: l ? `2px solid ${i}` : void 0,
50
+ boxShadow: l ? void 0 : "1px 2px 3px rgba(0,0,0,0.3)",
51
+ ...s,
52
+ ...a
42
53
  }
43
54
  }
44
55
  );
45
- }, Me = {
56
+ }, et = {
57
+ "3x3": { rows: [20, 50, 80], cols: [20, 50, 80], size: "18%" },
58
+ "3x4": { rows: [24, 50, 76], cols: [22, 40, 60, 78], size: "12%" },
59
+ "4x3": { rows: [15, 38, 62, 85], cols: [20, 50, 80], size: "14%" }
60
+ };
61
+ function tt(e) {
62
+ const t = et[e.gridSize];
63
+ return {
64
+ top: e.top ?? `${t.rows[e.row]}%`,
65
+ left: e.left ?? `${t.cols[e.col]}%`,
66
+ width: t.size,
67
+ height: t.size
68
+ };
69
+ }
70
+ const nt = {
46
71
  0: [],
47
72
  1: [{ row: 1, col: 1, gridSize: "3x3" }],
48
73
  2: [
@@ -145,10 +170,10 @@ const $e = ({
145
170
  { row: 3, col: 2, gridSize: "4x3" }
146
171
  ]
147
172
  };
148
- function Ce(e) {
149
- return Me[e] ?? [];
173
+ function ot(e) {
174
+ return nt[e] ?? [];
150
175
  }
151
- const X = {
176
+ const q = {
152
177
  0: { color: "transparent" },
153
178
  1: { color: "#1a1a1a" },
154
179
  2: { color: "#8B1A1A" },
@@ -162,44 +187,45 @@ const X = {
162
187
  10: { color: "#EA580C" },
163
188
  11: { color: "#166534" },
164
189
  12: { color: "#DC2626" }
165
- }, no = X;
166
- function ro(e) {
167
- return { ...X, ...e };
190
+ }, an = q;
191
+ function un(e) {
192
+ return { ...q, ...e };
168
193
  }
169
- function le(e, o) {
170
- if (o !== void 0)
171
- return o[e] ?? X[e] ?? { color: "#1a1a1a" };
194
+ function Pe(e, t) {
195
+ if (t !== void 0)
196
+ return t[e] ?? q[e] ?? { color: "#1a1a1a" };
172
197
  }
173
- function lo(e) {
174
- return le(e, X);
198
+ function cn(e) {
199
+ return Pe(e, q);
175
200
  }
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 = ({
201
+ const rt = (e, t, o) => {
202
+ const n = Pe(e, o);
203
+ return n ? { color: n.color, hollow: n.hollow } : { color: t };
204
+ }, it = ({
180
205
  value: e,
181
- pipColor: o,
182
- pipColors: t
206
+ pipColor: t,
207
+ pipColors: o
183
208
  }) => {
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 = ({
209
+ const n = Ie(), { color: r, hollow: i } = rt(e, t, o), l = ot(e);
210
+ return /* @__PURE__ */ z(we, { children: l.map((s, a) => {
211
+ const c = {
212
+ value: e,
213
+ row: s.row,
214
+ col: s.col,
215
+ gridSize: s.gridSize,
216
+ color: r,
217
+ hollow: i,
218
+ top: s.top,
219
+ left: s.left,
220
+ positionStyle: tt(s)
221
+ };
222
+ return n.renderPip ? /* @__PURE__ */ z("span", { children: n.renderPip(c) }, a) : /* @__PURE__ */ z(We, { ctx: c, theme: n }, a);
223
+ }) });
224
+ }, xe = ({
199
225
  value: e,
200
- pipColor: o,
201
- pipColors: t
202
- }) => /* @__PURE__ */ b(
226
+ pipColor: t,
227
+ pipColors: o
228
+ }) => /* @__PURE__ */ z(
203
229
  "div",
204
230
  {
205
231
  style: {
@@ -209,25 +235,36 @@ const ke = (e, o, t) => {
209
235
  padding: "0",
210
236
  overflow: "hidden"
211
237
  },
212
- children: /* @__PURE__ */ b(De, { value: e, pipColor: o, pipColors: t })
238
+ children: /* @__PURE__ */ z(it, { value: e, pipColor: t, pipColors: o })
213
239
  }
214
- ), ie = ({
240
+ ), Te = ({
215
241
  value1: e = 0,
216
- value2: o = 0,
217
- width: t = 100,
242
+ value2: t = 0,
243
+ width: o = 100,
218
244
  height: n = 200,
219
245
  backgroundColor: r = "white",
220
- pipColor: l = "black",
221
- pipColors: i,
246
+ pipColor: i = "black",
247
+ pipColors: l,
222
248
  borderColor: s = "black",
223
- rotation: a = 0
249
+ rotation: a = 0,
250
+ theme: c
224
251
  }) => {
225
- const u = Math.min(Math.max(e, 0), 12), f = Math.min(Math.max(o, 0), 12);
226
- return /* @__PURE__ */ T(
252
+ const d = Ie(c), u = Math.min(Math.max(e, 0), 12), f = Math.min(Math.max(t, 0), 12), p = {
253
+ value1: u,
254
+ value2: f,
255
+ width: o,
256
+ height: n,
257
+ backgroundColor: r,
258
+ borderColor: s,
259
+ rotation: a
260
+ }, v = d.tileStyle?.(p) ?? {}, S = d.halfDividerStyle?.(p) ?? {};
261
+ return /* @__PURE__ */ $(
227
262
  "div",
228
263
  {
264
+ className: d.tileClassName,
265
+ ...Qe(d.tileDataAttributes),
229
266
  style: {
230
- width: `${t}px`,
267
+ width: `${o}px`,
231
268
  height: `${n}px`,
232
269
  backgroundColor: r,
233
270
  borderColor: s,
@@ -239,10 +276,11 @@ const ke = (e, o, t) => {
239
276
  boxShadow: "0 1px 2px rgba(0,0,0,0.2)",
240
277
  display: "flex",
241
278
  flexDirection: "column",
242
- overflow: "hidden"
279
+ overflow: "hidden",
280
+ ...v
243
281
  },
244
282
  children: [
245
- /* @__PURE__ */ b(
283
+ /* @__PURE__ */ z(
246
284
  "div",
247
285
  {
248
286
  style: {
@@ -250,347 +288,625 @@ const ke = (e, o, t) => {
250
288
  position: "relative",
251
289
  borderBottomWidth: "1px",
252
290
  borderBottomStyle: "solid",
253
- borderBottomColor: s
291
+ borderBottomColor: s,
292
+ ...S
254
293
  },
255
- children: /* @__PURE__ */ b(ee, { value: u, pipColor: l, pipColors: i })
294
+ children: /* @__PURE__ */ z(xe, { value: u, pipColor: i, pipColors: l })
256
295
  }
257
296
  ),
258
- /* @__PURE__ */ b(
297
+ /* @__PURE__ */ z(
259
298
  "div",
260
299
  {
261
300
  style: {
262
301
  flex: 1,
263
302
  position: "relative"
264
303
  },
265
- children: /* @__PURE__ */ b(ee, { value: f, pipColor: l, pipColors: i })
304
+ children: /* @__PURE__ */ z(xe, { value: f, pipColor: i, pipColors: l })
266
305
  }
267
306
  )
268
307
  ]
269
308
  }
270
309
  );
271
- }, D = 60, I = 120, Ie = [-45, 45];
272
- function oe(e, o = D, t = I) {
273
- return e ? o / 2 : t / 2;
310
+ }, C = 60, D = 120, lt = [-45, 45];
311
+ function W(e, t = C, o = D) {
312
+ return e ? t / 2 : o / 2;
274
313
  }
275
- function k(e, o, t = D, n = I) {
276
- return oe(e, t, n) + oe(o, t, n);
314
+ function A(e, t, o = C, n = D) {
315
+ return W(e, o, n) + W(t, o, n);
277
316
  }
278
- function _(e) {
279
- const o = e * Math.PI / 180;
317
+ function Y(e) {
318
+ const t = e * Math.PI / 180;
280
319
  return {
281
- dirX: Math.cos(o),
282
- dirY: Math.sin(o)
320
+ dirX: Math.cos(t),
321
+ dirY: Math.sin(t)
283
322
  };
284
323
  }
285
- function N(e) {
286
- const { dirX: o, dirY: t } = _(e);
287
- return { perpX: -t, perpY: o };
324
+ function L(e) {
325
+ const { dirX: t, dirY: o } = Y(e);
326
+ return { perpX: -o, perpY: t };
288
327
  }
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 });
328
+ function st(e) {
329
+ const t = e.map((o) => ({ ...o }));
330
+ for (let o = 1; o < t.length; o++) {
331
+ const n = t[o], r = t[o - 1].value2;
332
+ !(n.value1 === n.value2) && n.value1 !== r && n.value2 === r && (t[o] = { value1: n.value2, value2: n.value1 });
298
333
  }
299
334
  return t;
300
335
  }
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;
336
+ function K(e) {
337
+ const { dirX: t, dirY: o } = Y(e);
338
+ return Math.abs(t) >= Math.abs(o) ? t >= 0 ? 1 : -1 : o >= 0 ? 1 : -1;
304
339
  }
305
- function se(e, o) {
306
- return e === 0 ? o : e === o ? -o : o;
340
+ function Me(e, t) {
341
+ return e === 0 ? t : e === t ? -t : t;
307
342
  }
308
- function Oe({
309
- startX: e,
343
+ function ke({
344
+ orientedDominoes: e,
345
+ startX: t,
310
346
  startY: o,
311
- angle: t,
312
- dominoes: n,
347
+ angle: n,
313
348
  layoutStyle: r,
314
- dominoWidth: l = D,
315
- dominoHeight: i = I,
316
- leadGap: s = i * 0.3,
349
+ dominoWidth: i,
350
+ dominoHeight: l,
351
+ leadGap: s,
317
352
  outwardSign: a,
318
- hubIndex: u
353
+ hubIndex: c
319
354
  }) {
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;
355
+ const d = [], { dirX: u, dirY: f } = Y(n), { perpX: p, perpY: v } = L(n), S = r === "offset" && c != null, m = [];
356
+ let P = t + u * s, b = o + f * s, M = 0, g = 0;
357
+ const I = i / 2, k = (x) => {
358
+ const h = (x - M) * I;
359
+ P += p * h, b += v * h, M = x;
325
360
  };
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
361
+ for (let x = 0; x < e.length; x++) {
362
+ const h = e[x], y = h.value1 === h.value2, T = x > 0 && e[x - 1].value1 === e[x - 1].value2;
363
+ r === "linear" ? x > 0 && (y ? (P += u * A(T, !0, i, l), b += f * A(T, !0, i, l)) : T ? (P += u * A(!0, !1, i, l), b += f * A(!0, !1, i, l)) : (P += u * l, b += f * l)) : y ? x > 0 && (P += u * A(T, !0, i, l), b += f * A(T, !0, i, l)) : (x === 0 ? g = a : T ? (P += u * A(!0, !1, i, l), b += f * A(!0, !1, i, l)) : (P += u * (l / 2), b += f * (l / 2), g = Me(g, a)), k(g)), m.push(M), d.push({
364
+ x: P,
365
+ y: b,
366
+ rotation: y ? n + 180 : n - 90,
367
+ isDouble: y,
368
+ value1: h.value1,
369
+ value2: h.value2
335
370
  });
336
371
  }
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
372
+ if (S && c != null) {
373
+ const x = -m[c] * I;
374
+ if (x !== 0)
375
+ for (let h = 0; h < d.length; h++)
376
+ d[h] = {
377
+ ...d[h],
378
+ x: d[h].x + p * x,
379
+ y: d[h].y + v * x
345
380
  };
346
381
  }
347
- return f;
382
+ return d;
383
+ }
384
+ function Ce(e, t) {
385
+ if (!e || e.length === 0) return [];
386
+ const o = /* @__PURE__ */ new Map();
387
+ for (const n of e)
388
+ Number.isInteger(n.index) && (n.index <= 0 || n.index >= t || o.set(n.index, n.turn));
389
+ return [...o.entries()].map(([n, r]) => ({ index: n, turn: r })).sort((n, r) => n.index - r.index);
390
+ }
391
+ function at(e, t, o, n = 1 / 0) {
392
+ const r = Ce(t, Number.isFinite(n) ? n : o + 1);
393
+ let i = e;
394
+ for (const l of r)
395
+ if (l.index <= o) i += l.turn;
396
+ else break;
397
+ return i;
348
398
  }
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;
399
+ function ut(e, t, o, n) {
400
+ const { startX: r, startY: i, angle: l, layoutStyle: s, dominoWidth: a, dominoHeight: c, leadGap: d, outwardSign: u } = t, f = [0, ...o.map((b) => b.index), e.length], p = [];
401
+ let v = l, S = r, m = i, P = d;
402
+ for (let b = 0; b < f.length - 1; b++) {
403
+ const M = e.slice(f[b], f[b + 1]);
404
+ if (M.length === 0) continue;
405
+ const g = b === 0 && n != null && n < f[1] ? n : void 0, I = ke({
406
+ orientedDominoes: M,
407
+ startX: S,
408
+ startY: m,
409
+ angle: v,
410
+ layoutStyle: s,
411
+ dominoWidth: a,
412
+ dominoHeight: c,
413
+ leadGap: P,
414
+ outwardSign: u,
415
+ hubIndex: g
416
+ });
417
+ if (p.push(...I), b >= f.length - 2) break;
418
+ const x = I[I.length - 1], h = Y(v), y = W(x.isDouble, a, c);
419
+ v += o[b].turn;
420
+ const T = e[f[b + 1]], O = T.value1 === T.value2, _ = W(O, a, c), U = Y(v), j = L(v), E = a / 2, oe = x.x + h.dirX * (y - E) + U.dirX * (_ + E), H = x.y + h.dirY * (y - E) + U.dirY * (_ + E), R = s === "offset" && !O, Z = R ? j.perpX * E * u : 0, J = R ? j.perpY * E * u : 0;
421
+ S = oe - Z, m = H - J, P = 0;
422
+ }
423
+ return p;
424
+ }
425
+ function ct({
426
+ startX: e,
427
+ startY: t,
428
+ angle: o,
429
+ dominoes: n,
430
+ layoutStyle: r,
431
+ dominoWidth: i = C,
432
+ dominoHeight: l = D,
433
+ leadGap: s = l * 0.3,
434
+ outwardSign: a,
435
+ hubIndex: c,
436
+ bends: d
437
+ }) {
438
+ const u = st([...n]), f = a ?? K(o), p = Ce(d, u.length);
439
+ return p.length > 0 ? ut(
440
+ u,
441
+ {
442
+ startX: e,
443
+ startY: t,
444
+ angle: o,
445
+ layoutStyle: r,
446
+ dominoWidth: i,
447
+ dominoHeight: l,
448
+ leadGap: s,
449
+ outwardSign: f
450
+ },
451
+ p,
452
+ c
453
+ ) : ke({
454
+ orientedDominoes: u,
455
+ startX: e,
456
+ startY: t,
457
+ angle: o,
458
+ layoutStyle: r,
459
+ dominoWidth: i,
460
+ dominoHeight: l,
461
+ leadGap: s,
462
+ outwardSign: f,
463
+ hubIndex: c
464
+ });
465
+ }
466
+ function be(e, t = C, o = D) {
467
+ const n = e.rotation * Math.PI / 180, r = Math.cos(n), i = Math.sin(n), l = t / 2, s = o / 2;
351
468
  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
469
+ [-l, -s],
470
+ [l, -s],
471
+ [l, s],
472
+ [-l, s]
473
+ ].map(([a, c]) => ({
474
+ x: e.x + a * r - c * i,
475
+ y: e.y + a * i + c * r
359
476
  }));
360
477
  }
361
- function Pe(e, o, t) {
362
- let n = 1 / 0, r = -1 / 0, l = 1 / 0, i = -1 / 0;
478
+ function dt(e, t, o) {
479
+ let n = 1 / 0, r = -1 / 0, i = 1 / 0, l = -1 / 0;
363
480
  for (const s of e) {
364
- const a = s.x * t.x + s.y * t.y;
481
+ const a = s.x * o.x + s.y * o.y;
365
482
  n = Math.min(n, a), r = Math.max(r, a);
366
483
  }
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);
484
+ for (const s of t) {
485
+ const a = s.x * o.x + s.y * o.y;
486
+ i = Math.min(i, a), l = Math.max(l, a);
370
487
  }
371
- return Math.min(r, i) - Math.max(n, l);
488
+ return Math.min(r, l) - Math.max(n, i);
372
489
  }
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])
490
+ function ee(e, t, o = 1, n = C, r = D) {
491
+ const i = be(e, n, r), l = be(t, n, r);
492
+ for (const s of [i, l])
376
493
  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)
494
+ const c = s[a], d = s[(a + 1) % 4], u = d.x - c.x, f = d.y - c.y, p = Math.hypot(u, f) || 1, v = { x: -f / p, y: u / p };
495
+ if (dt(i, l, v) <= o)
379
496
  return !1;
380
497
  }
381
498
  return !0;
382
499
  }
383
- function Ee(e, o, t, n) {
384
- return o.some(
385
- (r) => ae(e, r, 1, t, n)
500
+ function ft(e, t, o, n) {
501
+ return t.some(
502
+ (r) => ee(e, r, 1, o, n)
503
+ );
504
+ }
505
+ function De(e, t, o = 1, n = C, r = D) {
506
+ return e.some(
507
+ (i) => t.some(
508
+ (l) => ee(i, l, o, n, r)
509
+ )
386
510
  );
387
511
  }
388
- const P = D / 4, ne = 24;
512
+ function $e(e, t = 1, o = C, n = D) {
513
+ for (let r = 0; r < e.length; r++)
514
+ for (let i = r + 1; i < e.length; i++)
515
+ if (ee(e[r], e[i], t, o, n))
516
+ return !0;
517
+ return !1;
518
+ }
519
+ const F = C / 4, ye = 24;
389
520
  function ue({
390
521
  startX: e,
391
- startY: o,
392
- angle: t,
522
+ startY: t,
523
+ angle: o,
393
524
  branch: n,
394
525
  layoutStyle: r,
395
- dominoWidth: l = D,
396
- dominoHeight: i = I,
526
+ dominoWidth: i = C,
527
+ dominoHeight: l = D,
397
528
  leadGap: s,
398
529
  depth: a = 0,
399
- anchor: u,
400
- outwardSign: f,
401
- placed: c = [],
402
- pushAxis: d,
403
- minPushSteps: v = 0
530
+ anchor: c,
531
+ outwardSign: d,
532
+ placed: u = [],
533
+ pushAxis: f,
534
+ minPushSteps: p = 0
404
535
  }) {
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,
536
+ const v = d ?? K(o), S = n.feet ? Object.keys(n.feet).map(Number).filter((g) => {
537
+ const I = n.dominoes[g];
538
+ return I && I.value1 === I.value2;
539
+ }).sort((g, I) => g - I)[0] : void 0, m = (g, I) => ct({
540
+ startX: g,
541
+ startY: I,
542
+ angle: o,
412
543
  dominoes: n.dominoes,
413
544
  layoutStyle: r,
414
- dominoWidth: l,
415
- dominoHeight: i,
545
+ dominoWidth: i,
546
+ dominoHeight: l,
416
547
  leadGap: s,
417
- outwardSign: y,
418
- hubIndex: x
548
+ outwardSign: v,
549
+ hubIndex: S,
550
+ bends: n.bends
419
551
  });
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
552
+ let P = m(
553
+ e + (f?.x ?? 0) * F * p,
554
+ t + (f?.y ?? 0) * F * p
555
+ ), b = c && f ? {
556
+ x: c.x + f.x * F * p,
557
+ y: c.y + f.y * F * p
558
+ } : c;
559
+ if (f && u.length > 0)
560
+ for (let g = p; g <= ye; g++) {
561
+ const I = e + f.x * F * g, k = t + f.y * F * g, x = m(I, k);
562
+ if (!x.some(
563
+ (y) => ft(y, u, i, l)
564
+ ) || g === ye) {
565
+ P = x, b = c && {
566
+ x: c.x + f.x * F * g,
567
+ y: c.y + f.y * F * g
436
568
  };
437
569
  break;
438
570
  }
439
571
  }
440
- c.push(...z);
441
- const m = [
572
+ u.push(...P);
573
+ const M = [
442
574
  {
443
- angle: t,
575
+ angle: o,
444
576
  depth: a,
445
577
  layoutStyle: r,
446
- outwardSign: y,
578
+ outwardSign: v,
447
579
  dominoes: n.dominoes,
448
- layout: z,
449
- anchor: $
580
+ layout: P,
581
+ anchor: b
450
582
  }
451
583
  ];
452
584
  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
- }
585
+ const g = i / 2, I = l / 2;
586
+ for (const k of Object.keys(n.feet)) {
587
+ const x = Number(k), h = P[x], y = n.feet[x];
588
+ if (!h || !h.isDouble || !y)
589
+ continue;
590
+ const T = at(
591
+ o,
592
+ n.bends,
593
+ x,
594
+ n.dominoes.length
595
+ ), { dirX: O, dirY: _ } = Y(T), { perpX: U, perpY: j } = L(T);
596
+ for (let E = 0; E < y.length; E++) {
597
+ const oe = y[E], H = lt[E] ?? 0, R = Math.sign(H), Z = T + H, J = L(Z), re = -R, Ge = h.x + O * (i / 2) + U * (l / 2) * R, qe = h.y + _ * (i / 2) + j * (l / 2) * R, he = Ge - J.perpX * re * g, ge = qe - J.perpY * re * g;
598
+ M.push(
599
+ ...ue({
600
+ startX: he,
601
+ startY: ge,
602
+ angle: Z,
603
+ branch: oe,
604
+ // Toes inherit the main style so they zigzag in offset mode.
605
+ layoutStyle: r,
606
+ dominoWidth: i,
607
+ dominoHeight: l,
608
+ leadGap: I,
609
+ outwardSign: re,
610
+ depth: a + 1,
611
+ anchor: { x: he, y: ge },
612
+ placed: u,
613
+ // If the snug spot is still blocked (the offset center toe leans into
614
+ // one side), slide this toe along the double's open edge, away from
615
+ // center, until it clears. This keeps it butted against the double
616
+ // while stepping past the obstacle — independent per toe, so a foot
617
+ // ends up snug and only as asymmetric as the obstruction requires.
618
+ pushAxis: { x: U * R, y: j * R }
619
+ })
620
+ );
621
+ }
483
622
  }
484
623
  }
485
- return m;
624
+ return M;
486
625
  }
487
- function Fe(e) {
488
- return e.flatMap((o) => o.layout);
626
+ function Ee(e) {
627
+ return e.flatMap((t) => t.layout);
489
628
  }
490
- function io(e, o = 24, t = D, n = I) {
491
- const r = Math.hypot(t, n) / 2;
629
+ function dn(e, t = 24, o = C, n = D) {
630
+ const r = Math.hypot(o, n) / 2;
492
631
  if (e.length === 0)
493
632
  return {
494
- width: o * 2 + t,
495
- height: o * 2 + n,
496
- offsetX: o,
497
- offsetY: o
633
+ width: t * 2 + o,
634
+ height: t * 2 + n,
635
+ offsetX: t,
636
+ offsetY: t
498
637
  };
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);
638
+ let i = 1 / 0, l = 1 / 0, s = -1 / 0, a = -1 / 0;
639
+ for (const c of e)
640
+ i = Math.min(i, c.x - r), l = Math.min(l, c.y - r), s = Math.max(s, c.x + r), a = Math.max(a, c.y + r);
502
641
  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
642
+ width: Math.ceil(s - i + t * 2),
643
+ height: Math.ceil(a - l + t * 2),
644
+ offsetX: t - i,
645
+ offsetY: t - l
646
+ };
647
+ }
648
+ const te = 1;
649
+ function Ae(e, t, o) {
650
+ const { dirX: n, dirY: r } = Y(o);
651
+ return e * n + t * r;
652
+ }
653
+ function pt(e, t, o) {
654
+ const { perpX: n, perpY: r } = L(o);
655
+ return e * n + t * r;
656
+ }
657
+ function ce(e) {
658
+ const t = [];
659
+ for (let o = 1; o < e.length; o++)
660
+ e[o].value1 !== e[o - 1].value2 && t.push({
661
+ code: "chain-break",
662
+ message: `Domino ${o} does not connect to domino ${o - 1}`,
663
+ index: o
664
+ });
665
+ for (let o = 1; o < e.length; o++) {
666
+ const n = e[o - 1].value1 === e[o - 1].value2, r = e[o].value1 === e[o].value2;
667
+ n && r && t.push({
668
+ code: "consecutive-doubles",
669
+ message: `Consecutive doubles at index ${o - 1} and ${o}`,
670
+ index: o
671
+ });
672
+ }
673
+ return { valid: t.length === 0, issues: t };
674
+ }
675
+ function Oe(e, t, o, n = C, r = D) {
676
+ const i = n / 2, l = e.map((u) => u.isDouble), s = [];
677
+ let a = 0, c = 0, d = 0;
678
+ for (let u = 0; u < e.length; u++) {
679
+ const f = l[u], p = u > 0 && l[u - 1];
680
+ t === "linear" ? (u > 0 && (a += A(p, f, n, r)), c = 0) : f ? u > 0 && (a += A(p, !0, n, r)) : u === 0 ? (d = o, c = d * i) : p ? a += A(!0, !1, n, r) : (a += r / 2, d = Me(d, o), c = d * i), s.push({ along: a, perp: c });
681
+ }
682
+ return s;
683
+ }
684
+ function ht(e, t, o, n = te, r) {
685
+ const i = [], l = r ?? K(t), s = Oe(e, o, l);
686
+ for (let a = 1; a < e.length; a++) {
687
+ const c = e[a - 1], d = e[a], u = d.x - c.x, f = d.y - c.y, p = Ae(u, f, t), v = pt(u, f, t), S = s[a].along - s[a - 1].along, m = s[a].perp - s[a - 1].perp;
688
+ Math.abs(p - S) > n && i.push({
689
+ code: "spacing-along-train",
690
+ message: `Along-train spacing between domino ${a - 1} and ${a} is ${p.toFixed(2)}px (expected ${S}px)`,
691
+ index: a
692
+ }), Math.abs(v - m) > n && i.push({
693
+ code: "spacing-perpendicular",
694
+ message: `Perpendicular spacing between domino ${a - 1} and ${a} is ${v.toFixed(2)}px (expected ${m}px)`,
695
+ index: a
696
+ });
697
+ }
698
+ return { valid: i.length === 0, issues: i };
699
+ }
700
+ function gt(e, t, o, n = te, r) {
701
+ const i = [], l = r ?? K(t), s = Oe(e, o, l);
702
+ for (let a = 1; a < e.length; a++) {
703
+ const c = e[a - 1], d = e[a], u = d.x - c.x, f = d.y - c.y, p = Math.hypot(u, f), v = s[a].along - s[a - 1].along, S = s[a].perp - s[a - 1].perp, m = Math.hypot(v, S) * 0.9;
704
+ p + n < m && i.push({
705
+ code: "overlap",
706
+ message: `Domino ${a - 1} and ${a} centers are ${p.toFixed(2)}px apart (minimum ${m.toFixed(2)}px)`,
707
+ index: a
708
+ });
709
+ }
710
+ return { valid: i.length === 0, issues: i };
711
+ }
712
+ function fn(e, t, o, n, r = te, i) {
713
+ const l = [
714
+ ...ce(t).issues,
715
+ ...ht(
716
+ e,
717
+ o,
718
+ n,
719
+ r,
720
+ i
721
+ ).issues,
722
+ ...gt(
723
+ e,
724
+ o,
725
+ n,
726
+ r,
727
+ i
728
+ ).issues
729
+ ];
730
+ return e.length !== t.length && l.push({
731
+ code: "layout-length",
732
+ message: `Layout length ${e.length} does not match domino count ${t.length}`
733
+ }), { valid: l.length === 0, issues: l };
734
+ }
735
+ function vt(e) {
736
+ const t = [], o = (n, r) => {
737
+ if (t.push(
738
+ ...ce(n.dominoes).issues.map((i) => ({
739
+ ...i,
740
+ message: `[${r}] ${i.message}`
741
+ }))
742
+ ), !!n.feet)
743
+ for (const i of Object.keys(n.feet)) {
744
+ const l = Number(i), s = n.dominoes[l], a = n.feet[l] ?? [];
745
+ if (!s) {
746
+ t.push({
747
+ code: "foot-host-missing",
748
+ message: `[${r}] Foot references missing tile ${l}`
749
+ });
750
+ continue;
751
+ }
752
+ s.value1 !== s.value2 && t.push({
753
+ code: "foot-host-not-double",
754
+ message: `[${r}] Foot host tile ${l} is not a double`
755
+ }), a.length > 2 && t.push({
756
+ code: "foot-too-many-toes",
757
+ message: `[${r}] Double ${l} has ${a.length} side toes (max 2; the center toe is the main line)`
758
+ }), a.forEach((c, d) => {
759
+ const u = c.dominoes[0];
760
+ u && u.value1 !== s.value1 && t.push({
761
+ code: "foot-connection",
762
+ message: `[${r}] Toe ${d} on double ${l} starts with ${u.value1} but the double is ${s.value1}`
763
+ }), o(c, `${r}.${l}.${d}`);
764
+ });
765
+ }
507
766
  };
767
+ return o(e, "main"), { valid: t.length === 0, issues: t };
508
768
  }
509
- const Ae = ({
769
+ function pn(e, t = te) {
770
+ const o = [];
771
+ e.forEach((r, i) => {
772
+ if (o.push(
773
+ ...ce(r.dominoes).issues.map((l) => ({
774
+ ...l,
775
+ message: `[segment ${i} @${r.angle}°] ${l.message}`
776
+ }))
777
+ ), r.layout.length !== r.dominoes.length && o.push({
778
+ code: "layout-length",
779
+ message: `[segment ${i}] Layout length ${r.layout.length} does not match domino count ${r.dominoes.length}`
780
+ }), r.anchor && r.layout.length > 0) {
781
+ const l = r.layout[0], s = Ae(
782
+ l.x - r.anchor.x,
783
+ l.y - r.anchor.y,
784
+ r.angle
785
+ ), a = D / 2;
786
+ Math.abs(s - a) > t && o.push({
787
+ code: "foot-anchor",
788
+ message: `[segment ${i}] First toe tile sits ${s.toFixed(2)}px from the double along the toe (expected ${a}px)`,
789
+ index: 0
790
+ });
791
+ }
792
+ });
793
+ const n = e.flatMap((r) => r.layout);
794
+ for (let r = 0; r < n.length; r++)
795
+ for (let i = r + 1; i < n.length; i++)
796
+ ee(n[r], n[i]) && o.push({
797
+ code: "tile-overlap",
798
+ message: `Tiles ${r} and ${i} overlap`,
799
+ index: i
800
+ });
801
+ return { valid: o.length === 0, issues: o };
802
+ }
803
+ const xt = (() => {
804
+ try {
805
+ return !1;
806
+ } catch {
807
+ return !1;
808
+ }
809
+ })(), bt = ({
510
810
  startX: e,
511
- startY: o,
512
- angle: t,
811
+ startY: t,
812
+ angle: o,
513
813
  trainData: n,
514
814
  layoutStyle: r,
515
- tableWidth: l,
516
- tableHeight: i,
815
+ tableWidth: i,
816
+ tableHeight: l,
517
817
  centerX: s,
518
818
  centerY: a,
519
- pipColors: u
819
+ pipColors: c
520
820
  }) => {
521
- const f = Se(
522
- () => Fe(
821
+ ae(() => {
822
+ if (!xt) return;
823
+ const u = vt({
824
+ dominoes: n.dominoes,
825
+ feet: n.feet
826
+ });
827
+ u.valid || console.warn(
828
+ `DominoTrain: player ${n.playerId} train does not follow the rules:`,
829
+ u.issues.map((f) => f.message)
830
+ );
831
+ }, [n.dominoes, n.feet, n.playerId]);
832
+ const d = He(
833
+ () => Ee(
523
834
  ue({
524
835
  startX: e,
525
- startY: o,
526
- angle: t,
836
+ startY: t,
837
+ angle: o,
527
838
  branch: { dominoes: n.dominoes, feet: n.feet },
528
839
  layoutStyle: r
529
840
  })
530
841
  ),
531
842
  [
532
843
  e,
533
- o,
534
844
  t,
845
+ o,
535
846
  n.dominoes,
536
847
  n.feet,
537
848
  r,
538
- l,
539
- i
849
+ i,
850
+ l
540
851
  ]
541
852
  );
542
- return /* @__PURE__ */ b(re, { children: f.map((c, d) => {
543
- const v = n.isPublic;
544
- return /* @__PURE__ */ b(
853
+ return /* @__PURE__ */ z(we, { children: d.map((u, f) => {
854
+ const p = n.isPublic;
855
+ return /* @__PURE__ */ z(
545
856
  "div",
546
857
  {
547
858
  style: {
548
859
  position: "absolute",
549
- left: `${c.x - D / 2}px`,
550
- top: `${c.y - I / 2}px`,
860
+ left: `${u.x - C / 2}px`,
861
+ top: `${u.y - D / 2}px`,
551
862
  zIndex: 5
552
863
  },
553
- children: /* @__PURE__ */ b(
554
- ie,
864
+ children: /* @__PURE__ */ z(
865
+ Te,
555
866
  {
556
- value1: c.value1,
557
- value2: c.value2,
558
- width: D,
559
- height: I,
867
+ value1: u.value1,
868
+ value2: u.value2,
869
+ width: C,
870
+ height: D,
560
871
  backgroundColor: "white",
561
872
  pipColor: "black",
562
- pipColors: u,
563
- borderColor: v ? "red" : "black",
564
- rotation: c.rotation
873
+ pipColors: c,
874
+ borderColor: p ? "red" : "black",
875
+ rotation: u.rotation
565
876
  }
566
877
  )
567
878
  },
568
- `main-train-${n.playerId}-${d}`
879
+ `main-train-${n.playerId}-${f}`
569
880
  );
570
881
  }) });
571
- }, Re = ({
882
+ };
883
+ function yt(e, t, o, n) {
884
+ const r = o * (n === "offset" ? 2.5 : 1.3);
885
+ return Math.max(t + 20, Math.ceil(r * e / (2 * Math.PI)));
886
+ }
887
+ const mt = ({
572
888
  playerCount: e,
573
- centerX: o,
574
- centerY: t,
889
+ centerX: t,
890
+ centerY: o,
575
891
  radius: n,
576
892
  engineValue: r,
577
- trains: l,
578
- layoutStyle: i,
893
+ trains: i,
894
+ layoutStyle: l,
579
895
  tableWidth: s,
580
896
  tableHeight: a,
581
- pipColors: u
897
+ pipColors: c
582
898
  }) => {
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(
899
+ const d = Math.max(8, e), u = 120, f = 60, p = 120, v = yt(d, n, f, l);
900
+ return /* @__PURE__ */ $("div", { style: { position: "relative", width: "100%", height: "100%" }, children: [
901
+ /* @__PURE__ */ z(
586
902
  "div",
587
903
  {
588
904
  style: {
589
905
  position: "absolute",
590
- width: `${c}px`,
591
- height: `${c}px`,
592
- left: `${o - c / 2}px`,
593
- top: `${t - c / 2}px`,
906
+ width: `${u}px`,
907
+ height: `${u}px`,
908
+ left: `${t - u / 2}px`,
909
+ top: `${o - u / 2}px`,
594
910
  backgroundColor: "#d1d5db",
595
911
  borderWidth: "3px",
596
912
  borderStyle: "solid",
@@ -602,186 +918,186 @@ const Ae = ({
602
918
  justifyContent: "center",
603
919
  alignItems: "center"
604
920
  },
605
- children: /* @__PURE__ */ b("div", { style: { transform: "rotate(0deg)" }, children: /* @__PURE__ */ b(
606
- ie,
921
+ children: /* @__PURE__ */ z("div", { style: { transform: "rotate(0deg)" }, children: /* @__PURE__ */ z(
922
+ Te,
607
923
  {
608
924
  value1: r,
609
925
  value2: r,
610
- width: 60,
611
- height: 120,
926
+ width: f,
927
+ height: p,
612
928
  backgroundColor: "white",
613
929
  pipColor: "black",
614
- pipColors: u,
930
+ pipColors: c,
615
931
  borderColor: "#333"
616
932
  }
617
933
  ) })
618
934
  }
619
935
  ),
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) || {
936
+ Array.from({ length: d }).map((S, m) => {
937
+ const P = m * 360 / d, b = P * Math.PI / 180, M = t + v * Math.cos(b), g = o + v * Math.sin(b), I = i.find((k) => k.playerId === m) || {
622
938
  dominoes: [],
623
- playerId: x,
939
+ playerId: m,
624
940
  isPublic: !1
625
941
  };
626
- return /* @__PURE__ */ b(
627
- Ae,
942
+ return /* @__PURE__ */ z(
943
+ bt,
628
944
  {
629
- startX: $,
630
- startY: m,
631
- angle: w,
632
- trainData: p,
633
- layoutStyle: i,
945
+ startX: M,
946
+ startY: g,
947
+ angle: P,
948
+ trainData: I,
949
+ layoutStyle: l,
634
950
  tableWidth: s,
635
951
  tableHeight: a,
636
- centerX: o,
637
- centerY: t,
638
- pipColors: u
952
+ centerX: t,
953
+ centerY: o,
954
+ pipColors: c
639
955
  },
640
- x
956
+ m
641
957
  );
642
958
  })
643
959
  ] });
644
960
  };
645
- function F(e, o) {
646
- return e <= o ? `${e}:${o}` : `${o}:${e}`;
961
+ function V(e, t) {
962
+ return e <= t ? `${e}:${t}` : `${t}:${e}`;
647
963
  }
648
- function ce(e) {
649
- return F(e.value1, e.value2);
964
+ function B(e) {
965
+ return V(e.value1, e.value2);
650
966
  }
651
- function de(e) {
967
+ function Re(e) {
652
968
  return e.value1 === e.value2;
653
969
  }
654
- function so(e, o) {
655
- return e.value1 === o || e.value2 === o;
970
+ function Fe(e, t) {
971
+ return e.value1 === t || e.value2 === t;
656
972
  }
657
- function ao(e, o) {
658
- return e.value1 === o ? e.value2 : e.value2 === o ? e.value1 : null;
973
+ function hn(e, t) {
974
+ return e.value1 === t ? e.value2 : e.value2 === t ? e.value1 : null;
659
975
  }
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;
976
+ function de(e, t) {
977
+ return e.value1 === t ? { value1: e.value1, value2: e.value2 } : e.value2 === t ? { value1: e.value2, value2: e.value1 } : null;
662
978
  }
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;
979
+ function wt(e) {
980
+ const t = [];
981
+ for (let o = 0; o <= e; o++)
982
+ for (let n = o; n <= e; n++)
983
+ t.push({ value1: o, value2: n });
984
+ return t;
985
+ }
986
+ function gn(e) {
987
+ const t = e + 1;
988
+ return t * (t + 1) / 2;
669
989
  }
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(
990
+ function St(e, t = 12, o = {}) {
991
+ const n = /* @__PURE__ */ new Set([V(t, t)]), r = [];
992
+ for (let i = 0; i < e; i++) {
993
+ const l = 4 + Math.floor(Math.random() * 7), s = [];
994
+ let a = t, c = !1;
995
+ for (let u = 0; u < l; u++) {
996
+ const f = Tt(
681
997
  a,
682
- u,
683
- c === 0,
684
- o,
998
+ c,
999
+ u === 0,
1000
+ t,
685
1001
  n
686
1002
  );
687
- if (d === null)
1003
+ if (f === null)
688
1004
  break;
689
- const v = d === a;
690
- n.add(F(a, d)), s.push({ value1: a, value2: d }), u = v, a = d;
1005
+ const p = f === a;
1006
+ n.add(V(a, f)), s.push({ value1: a, value2: f }), c = p, a = f;
691
1007
  }
692
- const f = t.chickenFeet ? _e(s, n) : void 0;
1008
+ const d = o.chickenFeet ? zt(s, n) : void 0;
693
1009
  r.push({
694
- playerId: l,
1010
+ playerId: i,
695
1011
  dominoes: s,
696
1012
  isPublic: Math.random() > 0.7,
697
- ...f ? { feet: f } : {}
1013
+ ...d ? { feet: d } : {}
698
1014
  });
699
1015
  }
700
1016
  return r;
701
1017
  }
702
- function _e(e, o) {
703
- const t = {};
1018
+ function zt(e, t) {
1019
+ const o = {};
704
1020
  for (let n = 0; n < e.length; n++) {
705
1021
  if (e[n].value1 !== e[n].value2)
706
1022
  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);
1023
+ const r = e[n].value1, i = [];
1024
+ for (let l = 0; l < 2; l++) {
1025
+ const s = It(r, t);
1026
+ s && i.push(s);
711
1027
  }
712
- l.length && (t[n] = l);
1028
+ i.length && (o[n] = i);
713
1029
  }
714
- return Object.keys(t).length ? t : void 0;
1030
+ return Object.keys(o).length ? o : void 0;
715
1031
  }
716
- function Le(e, o) {
717
- const t = 1 + Math.floor(Math.random() * 2), n = [];
1032
+ function It(e, t) {
1033
+ const o = 1 + Math.floor(Math.random() * 2), n = [];
718
1034
  let r = e;
719
- for (let l = 0; l < t; l++) {
720
- const i = Ye(r, o);
721
- if (i === null)
1035
+ for (let i = 0; i < o; i++) {
1036
+ const l = Pt(r, t);
1037
+ if (l === null)
722
1038
  break;
723
- o.add(F(r, i)), n.push({ value1: r, value2: i }), r = i;
1039
+ t.add(V(r, l)), n.push({ value1: r, value2: l }), r = l;
724
1040
  }
725
1041
  return n.length ? { dominoes: n } : null;
726
1042
  }
727
- function Ye(e, o) {
728
- const t = [];
1043
+ function Pt(e, t) {
1044
+ const o = [];
729
1045
  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)];
1046
+ n !== e && (t.has(V(e, n)) || o.push(n));
1047
+ return o.length === 0 ? null : o[Math.floor(Math.random() * o.length)];
732
1048
  }
733
- function Ne(e, o, t, n, r) {
734
- const l = Array.from({ length: 13 }, (i, s) => s).filter(
735
- (i) => je(
1049
+ function Tt(e, t, o, n, r) {
1050
+ const i = Array.from({ length: 13 }, (l, s) => s).filter(
1051
+ (l) => Mt(
736
1052
  e,
737
- i,
738
- o,
1053
+ l,
739
1054
  t,
1055
+ o,
740
1056
  n,
741
1057
  r
742
1058
  )
743
1059
  );
744
- return l.length === 0 ? null : l[Math.floor(Math.random() * l.length)];
1060
+ return i.length === 0 ? null : i[Math.floor(Math.random() * i.length)];
745
1061
  }
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)));
1062
+ function Mt(e, t, o, n, r, i) {
1063
+ const l = t === e;
1064
+ return !(n && l && e === r || l && o || i.has(V(e, t)));
749
1065
  }
750
- const Be = {
1066
+ const kt = {
751
1067
  playerCount: 8,
752
1068
  trains: [],
753
1069
  engineValue: 12
754
- }, fo = ({
755
- initialState: e = Be,
756
- width: o = 1200,
757
- height: t = 800,
1070
+ }, vn = ({
1071
+ initialState: e = kt,
1072
+ width: t = 1200,
1073
+ height: o = 800,
758
1074
  pipColors: n,
759
1075
  onPipColorsChange: r
760
1076
  }) => {
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 }
1077
+ const [i, l] = G(e), [s, a] = G("offset"), [c, d] = G(!1), [u, f] = G(void 0), p = n ?? u, v = r ?? f, S = p !== void 0, m = t / 2, P = o / 2, b = (g = c) => {
1078
+ const I = St(
1079
+ i.playerCount,
1080
+ i.engineValue,
1081
+ { chickenFeet: g }
766
1082
  );
767
- i((M) => ({
768
- ...M,
769
- trains: h
1083
+ l((k) => ({
1084
+ ...k,
1085
+ trains: I
770
1086
  }));
771
1087
  };
772
- ye(() => {
773
- $();
1088
+ ae(() => {
1089
+ b();
774
1090
  }, []);
775
- const m = () => {
776
- const p = !u;
777
- f(p), $(p);
1091
+ const M = () => {
1092
+ const g = !c;
1093
+ d(g), b(g);
778
1094
  };
779
- return /* @__PURE__ */ T(
1095
+ return /* @__PURE__ */ $(
780
1096
  "div",
781
1097
  {
782
1098
  style: {
783
- width: `${o}px`,
784
- height: `${t}px`,
1099
+ width: `${t}px`,
1100
+ height: `${o}px`,
785
1101
  position: "relative",
786
1102
  backgroundColor: "#1f8a55",
787
1103
  // Classic green felt background
@@ -790,15 +1106,15 @@ const Be = {
790
1106
  overflow: "hidden"
791
1107
  },
792
1108
  children: [
793
- /* @__PURE__ */ T(
1109
+ /* @__PURE__ */ $(
794
1110
  "div",
795
1111
  {
796
1112
  style: { position: "absolute", top: "10px", left: "10px", zIndex: 100 },
797
1113
  children: [
798
- /* @__PURE__ */ b(
1114
+ /* @__PURE__ */ z(
799
1115
  "button",
800
1116
  {
801
- onClick: () => $(),
1117
+ onClick: () => b(),
802
1118
  style: {
803
1119
  padding: "8px 12px",
804
1120
  backgroundColor: "#fff",
@@ -810,7 +1126,7 @@ const Be = {
810
1126
  children: "New trains"
811
1127
  }
812
1128
  ),
813
- /* @__PURE__ */ T(
1129
+ /* @__PURE__ */ $(
814
1130
  "button",
815
1131
  {
816
1132
  onClick: () => a(s === "offset" ? "linear" : "offset"),
@@ -828,45 +1144,45 @@ const Be = {
828
1144
  ]
829
1145
  }
830
1146
  ),
831
- /* @__PURE__ */ T(
1147
+ /* @__PURE__ */ $(
832
1148
  "button",
833
1149
  {
834
- onClick: m,
1150
+ onClick: M,
835
1151
  style: {
836
1152
  padding: "8px 12px",
837
- backgroundColor: u ? "#fef3c7" : "#fff",
838
- border: `1px solid ${u ? "#f59e0b" : "#ccc"}`,
1153
+ backgroundColor: c ? "#fef3c7" : "#fff",
1154
+ border: `1px solid ${c ? "#f59e0b" : "#ccc"}`,
839
1155
  borderRadius: "4px",
840
1156
  marginRight: "10px",
841
1157
  cursor: "pointer"
842
1158
  },
843
1159
  children: [
844
1160
  "Chicken Feet: ",
845
- u ? "On" : "Off"
1161
+ c ? "On" : "Off"
846
1162
  ]
847
1163
  }
848
1164
  ),
849
- /* @__PURE__ */ T(
1165
+ /* @__PURE__ */ $(
850
1166
  "button",
851
1167
  {
852
- onClick: () => y(x ? void 0 : X),
1168
+ onClick: () => v(S ? void 0 : q),
853
1169
  style: {
854
1170
  padding: "8px 12px",
855
- backgroundColor: x ? "#fef3c7" : "#fff",
856
- border: `1px solid ${x ? "#f59e0b" : "#ccc"}`,
1171
+ backgroundColor: S ? "#fef3c7" : "#fff",
1172
+ border: `1px solid ${S ? "#f59e0b" : "#ccc"}`,
857
1173
  borderRadius: "4px",
858
1174
  cursor: "pointer"
859
1175
  },
860
1176
  children: [
861
1177
  "Pip Colors: ",
862
- x ? "On" : "Off"
1178
+ S ? "On" : "Off"
863
1179
  ]
864
1180
  }
865
1181
  )
866
1182
  ]
867
1183
  }
868
1184
  ),
869
- /* @__PURE__ */ T(
1185
+ /* @__PURE__ */ $(
870
1186
  "div",
871
1187
  {
872
1188
  style: {
@@ -880,191 +1196,270 @@ const Be = {
880
1196
  fontSize: "14px"
881
1197
  },
882
1198
  children: [
883
- /* @__PURE__ */ T("div", { children: [
1199
+ /* @__PURE__ */ $("div", { children: [
884
1200
  "Engine: Double-",
885
- l.engineValue
1201
+ i.engineValue
886
1202
  ] }),
887
- /* @__PURE__ */ T("div", { children: [
1203
+ /* @__PURE__ */ $("div", { children: [
888
1204
  "Players: ",
889
- l.playerCount
1205
+ i.playerCount
890
1206
  ] })
891
1207
  ]
892
1208
  }
893
1209
  ),
894
- /* @__PURE__ */ b(
895
- Re,
1210
+ /* @__PURE__ */ z(
1211
+ mt,
896
1212
  {
897
- playerCount: l.playerCount,
898
- centerX: w,
899
- centerY: z,
1213
+ playerCount: i.playerCount,
1214
+ centerX: m,
1215
+ centerY: P,
900
1216
  radius: 80,
901
- engineValue: l.engineValue,
902
- trains: l.trains,
1217
+ engineValue: i.engineValue,
1218
+ trains: i.trains,
903
1219
  layoutStyle: s,
904
- tableWidth: o,
905
- tableHeight: t,
906
- pipColors: v
1220
+ tableWidth: t,
1221
+ tableHeight: o,
1222
+ pipColors: p
907
1223
  }
908
1224
  )
909
1225
  ]
910
1226
  }
911
1227
  );
912
- }, B = 1;
913
- function pe(e, o, t) {
914
- const { dirX: n, dirY: r } = _(t);
915
- return e * n + o * r;
1228
+ }, fe = 90;
1229
+ function se(e, t = fe) {
1230
+ return e === "right" ? t : -t;
916
1231
  }
917
- function Ue(e, o, t) {
918
- const { perpX: n, perpY: r } = N(t);
919
- return e * n + o * r;
1232
+ function Ne(e) {
1233
+ return e === "right" ? "left" : "right";
920
1234
  }
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 };
1235
+ function xn(e, t) {
1236
+ return (t ?? K(e)) >= 0 ? "left" : "right";
938
1237
  }
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;
1238
+ function bn(e, t, o) {
1239
+ const { perpX: n, perpY: r } = L(t), i = (a, c) => {
1240
+ let d = 1 / 0;
1241
+ return a > 0 ? d = Math.min(d, (o.width - e.x) / a) : a < 0 && (d = Math.min(d, (0 - e.x) / a)), c > 0 ? d = Math.min(d, (o.height - e.y) / c) : c < 0 && (d = Math.min(d, (0 - e.y) / c)), Number.isFinite(d) ? Math.max(0, d) : 1 / 0;
1242
+ }, l = i(n, r), s = i(-n, -r);
1243
+ return l >= s ? "right" : "left";
947
1244
  }
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
- });
1245
+ function Ye(e, t) {
1246
+ return Ee(
1247
+ ue({
1248
+ startX: t.startX,
1249
+ startY: t.startY,
1250
+ angle: t.angle,
1251
+ branch: e,
1252
+ layoutStyle: t.layoutStyle
1253
+ })
1254
+ );
1255
+ }
1256
+ function Q(e, t, o) {
1257
+ const n = (e ?? []).filter((r) => r.index !== t);
1258
+ return o === null ? n : [...n, { index: t, turn: o }].sort((r, i) => r.index - i.index);
1259
+ }
1260
+ function yn({
1261
+ branch: e,
1262
+ index: t,
1263
+ build: o,
1264
+ obstacles: n,
1265
+ preferredSide: r,
1266
+ degrees: i = fe
1267
+ }) {
1268
+ const l = [r, Ne(r)];
1269
+ for (const s of l) {
1270
+ const a = se(s, i), c = {
1271
+ ...e,
1272
+ bends: Q(e.bends, t, a)
1273
+ }, d = Ye(c, o);
1274
+ if (!$e(d) && !De(d, n))
1275
+ return { turn: a };
961
1276
  }
962
- return { valid: l.length === 0, issues: l };
1277
+ return { turn: null, reason: "blocked" };
963
1278
  }
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
- });
1279
+ function mn(e, t, o, n, r, i = fe) {
1280
+ const l = (e.bends ?? []).find((u) => u.index === t), s = se(r, i), a = se(Ne(r), i), c = (u) => {
1281
+ const f = {
1282
+ ...e,
1283
+ bends: Q(e.bends, t, u)
1284
+ }, p = Ye(f, o);
1285
+ return !$e(p) && !De(p, n);
1286
+ };
1287
+ let d;
1288
+ l ? l.turn === s ? d = [a, null] : l.turn === a ? d = [null] : d = [s, a, null] : d = [s, a];
1289
+ for (const u of d) {
1290
+ if (u === null)
1291
+ return { bends: Q(e.bends, t, null), changed: !0, blocked: !1 };
1292
+ if (c(u))
1293
+ return { bends: Q(e.bends, t, u), changed: !0, blocked: !1 };
973
1294
  }
974
- return { valid: l.length === 0, issues: l };
1295
+ return { bends: e.bends ?? [], changed: !1, blocked: !0 };
975
1296
  }
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 };
1297
+ function pe(e, t, o) {
1298
+ return Math.min(o, Math.max(t, e));
998
1299
  }
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
- }
1300
+ function me(e, t, o, n, r) {
1301
+ const i = pe(e.scale * t, n, r), l = i / e.scale;
1302
+ return {
1303
+ scale: i,
1304
+ x: o.x - (o.x - e.x) * l,
1305
+ y: o.y - (o.y - e.y) * l
1030
1306
  };
1031
- return t(e, "main"), { valid: o.length === 0, issues: o };
1032
1307
  }
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 };
1308
+ function Ct(e, t, o, n, r) {
1309
+ const i = Math.max(1, e.width), l = Math.max(1, e.height), s = Math.min(
1310
+ (t.width - o * 2) / i,
1311
+ (t.height - o * 2) / l
1312
+ ), a = pe(s, n, r);
1313
+ return {
1314
+ scale: a,
1315
+ x: (t.width - i * a) / 2,
1316
+ y: (t.height - l * a) / 2
1317
+ };
1066
1318
  }
1067
- const go = [
1319
+ function wn(e, t) {
1320
+ return {
1321
+ x: (t.x - e.x) / e.scale,
1322
+ y: (t.y - e.y) / e.scale
1323
+ };
1324
+ }
1325
+ const Dt = 3, Sn = ({
1326
+ width: e,
1327
+ height: t,
1328
+ contentWidth: o,
1329
+ contentHeight: n,
1330
+ children: r,
1331
+ minScale: i = 0.2,
1332
+ maxScale: l = 4,
1333
+ zoomStep: s = 1.15,
1334
+ padding: a = 40,
1335
+ background: c = "#1f8a55",
1336
+ showControls: d = !0,
1337
+ testId: u = "viewport"
1338
+ }) => {
1339
+ const f = ve(null), p = Ze(
1340
+ () => Ct(
1341
+ { width: o, height: n },
1342
+ { width: e, height: t },
1343
+ a,
1344
+ i,
1345
+ l
1346
+ ),
1347
+ [o, n, e, t, a, i, l]
1348
+ ), [v, S] = G(p);
1349
+ ae(() => {
1350
+ S(p());
1351
+ }, [p]);
1352
+ const m = ve(null), P = (h, y) => {
1353
+ const T = f.current?.getBoundingClientRect();
1354
+ return { x: h - (T?.left ?? 0), y: y - (T?.top ?? 0) };
1355
+ }, b = (h) => {
1356
+ m.current = {
1357
+ pointerX: h.clientX,
1358
+ pointerY: h.clientY,
1359
+ startX: v.x,
1360
+ startY: v.y,
1361
+ moved: !1
1362
+ };
1363
+ }, M = (h) => {
1364
+ const y = m.current;
1365
+ if (!y) return;
1366
+ const T = h.clientX - y.pointerX, O = h.clientY - y.pointerY;
1367
+ !y.moved && Math.hypot(T, O) < Dt || (y.moved = !0, f.current?.setPointerCapture?.(h.pointerId), S((_) => ({ ..._, x: y.startX + T, y: y.startY + O })));
1368
+ }, g = (h) => {
1369
+ m.current?.moved && h.preventDefault(), m.current = null;
1370
+ }, I = (h) => {
1371
+ h.preventDefault();
1372
+ const y = P(h.clientX, h.clientY), T = h.deltaY < 0 ? s : 1 / s;
1373
+ S((O) => me(O, T, y, i, l));
1374
+ }, k = (h) => S(
1375
+ (y) => me(y, h, { x: e / 2, y: t / 2 }, i, l)
1376
+ ), x = {
1377
+ width: 32,
1378
+ height: 32,
1379
+ fontSize: 18,
1380
+ lineHeight: "30px",
1381
+ textAlign: "center",
1382
+ cursor: "pointer",
1383
+ background: "#fff",
1384
+ border: "1px solid #d1d5db",
1385
+ borderRadius: 6,
1386
+ userSelect: "none"
1387
+ };
1388
+ return /* @__PURE__ */ $(
1389
+ "div",
1390
+ {
1391
+ ref: f,
1392
+ "data-testid": u,
1393
+ onPointerDown: b,
1394
+ onPointerMove: M,
1395
+ onPointerUp: g,
1396
+ onPointerLeave: g,
1397
+ onWheel: I,
1398
+ style: {
1399
+ position: "relative",
1400
+ width: e,
1401
+ height: t,
1402
+ overflow: "hidden",
1403
+ background: c,
1404
+ borderRadius: 8,
1405
+ cursor: "grab",
1406
+ touchAction: "none"
1407
+ },
1408
+ children: [
1409
+ /* @__PURE__ */ z(
1410
+ "div",
1411
+ {
1412
+ "data-testid": `${u}-content`,
1413
+ style: {
1414
+ position: "absolute",
1415
+ left: 0,
1416
+ top: 0,
1417
+ transformOrigin: "0 0",
1418
+ transform: `translate(${v.x}px, ${v.y}px) scale(${v.scale})`
1419
+ },
1420
+ children: r
1421
+ }
1422
+ ),
1423
+ d && /* @__PURE__ */ $(
1424
+ "div",
1425
+ {
1426
+ "data-testid": `${u}-controls`,
1427
+ style: {
1428
+ position: "absolute",
1429
+ right: 12,
1430
+ bottom: 12,
1431
+ display: "flex",
1432
+ flexDirection: "column",
1433
+ gap: 6
1434
+ },
1435
+ children: [
1436
+ /* @__PURE__ */ z("div", { style: x, role: "button", "aria-label": "Zoom in", onClick: () => k(s), children: "+" }),
1437
+ /* @__PURE__ */ z("div", { style: x, role: "button", "aria-label": "Zoom out", onClick: () => k(1 / s), children: "−" }),
1438
+ /* @__PURE__ */ z(
1439
+ "div",
1440
+ {
1441
+ style: { ...x, fontSize: 12, lineHeight: "30px" },
1442
+ role: "button",
1443
+ "aria-label": "Reset view",
1444
+ onClick: () => S(p()),
1445
+ children: "⤢"
1446
+ }
1447
+ ),
1448
+ /* @__PURE__ */ z(
1449
+ "div",
1450
+ {
1451
+ "data-testid": `${u}-zoom-readout`,
1452
+ style: { ...x, fontSize: 11, cursor: "default" },
1453
+ children: Math.round(pe(v.scale, i, l) * 100)
1454
+ }
1455
+ )
1456
+ ]
1457
+ }
1458
+ )
1459
+ ]
1460
+ }
1461
+ );
1462
+ }, zn = [
1068
1463
  {
1069
1464
  id: "regular-after-double",
1070
1465
  name: "Regular after double",
@@ -1151,7 +1546,7 @@ const go = [
1151
1546
  ],
1152
1547
  layoutStyles: ["linear", "offset"]
1153
1548
  }
1154
- ], ho = [
1549
+ ], In = [
1155
1550
  {
1156
1551
  id: "single-foot",
1157
1552
  name: "Single foot",
@@ -1259,7 +1654,7 @@ const go = [
1259
1654
  },
1260
1655
  layoutStyles: ["linear", "offset"]
1261
1656
  }
1262
- ], G = {
1657
+ ], ie = {
1263
1658
  maxPips: 12,
1264
1659
  engineValue: 12,
1265
1660
  allowConsecutiveDoubles: !1,
@@ -1271,7 +1666,7 @@ const go = [
1271
1666
  sideToeAngles: [-45, 45]
1272
1667
  }
1273
1668
  };
1274
- function Ge(e) {
1669
+ function $t(e) {
1275
1670
  switch (e.doubleObligation) {
1276
1671
  case "chicken-foot":
1277
1672
  return Math.max(1, e.chickenFoot.toeCount);
@@ -1281,89 +1676,89 @@ function Ge(e) {
1281
1676
  return 0;
1282
1677
  }
1283
1678
  }
1284
- function Ke(e) {
1679
+ function Et(e) {
1285
1680
  return e.doubleObligation === "chicken-foot" ? Math.max(0, e.chickenFoot.toeCount - 1) : 0;
1286
1681
  }
1287
- function bo(e = {}) {
1288
- const o = e.maxPips ?? G.maxPips;
1682
+ function Pn(e = {}) {
1683
+ const t = e.maxPips ?? ie.maxPips;
1289
1684
  return {
1290
- ...G,
1685
+ ...ie,
1291
1686
  ...e,
1292
- maxPips: o,
1293
- engineValue: e.engineValue ?? o,
1687
+ maxPips: t,
1688
+ engineValue: e.engineValue ?? t,
1294
1689
  chickenFoot: {
1295
- ...G.chickenFoot,
1690
+ ...ie.chickenFoot,
1296
1691
  ...e.chickenFoot ?? {}
1297
1692
  }
1298
1693
  };
1299
1694
  }
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;
1695
+ function At(e, t) {
1696
+ let o = e;
1697
+ for (const n of t)
1698
+ if (o = o?.feet?.[n.doubleIndex]?.[n.toeIndex], !o) return;
1699
+ return o;
1305
1700
  }
1306
- function U(e, o, t) {
1307
- if (t(e, o), !!e.feet)
1701
+ function ne(e, t, o) {
1702
+ if (o(e, t), !!e.feet)
1308
1703
  for (const n of Object.keys(e.feet)) {
1309
1704
  const r = Number(n);
1310
- e.feet[r].forEach((l, i) => {
1311
- U(l, [...o, { doubleIndex: r, toeIndex: i }], t);
1705
+ e.feet[r].forEach((i, l) => {
1706
+ ne(i, [...t, { doubleIndex: r, toeIndex: l }], o);
1312
1707
  });
1313
1708
  }
1314
1709
  }
1315
- function Qe(e) {
1316
- const o = [];
1317
- return U(e, [], (t, n) => {
1318
- t.dominoes.forEach((r, l) => {
1710
+ function Ot(e) {
1711
+ const t = [];
1712
+ return ne(e, [], (o, n) => {
1713
+ o.dominoes.forEach((r, i) => {
1319
1714
  if (r.value1 !== r.value2) return;
1320
- const i = l < t.dominoes.length - 1, s = t.feet?.[l]?.length ?? 0;
1321
- o.push({
1715
+ const l = i < o.dominoes.length - 1, s = o.feet?.[i]?.length ?? 0;
1716
+ t.push({
1322
1717
  path: n,
1323
- doubleIndex: l,
1718
+ doubleIndex: i,
1324
1719
  value: r.value1,
1325
- hasCenter: i,
1720
+ hasCenter: l,
1326
1721
  sideToes: s,
1327
- answers: (i ? 1 : 0) + s
1722
+ answers: (l ? 1 : 0) + s
1328
1723
  });
1329
1724
  });
1330
- }), o;
1725
+ }), t;
1331
1726
  }
1332
- function Ze(e, o) {
1333
- const t = Ge(o);
1334
- return t <= 0 ? [] : Qe(e).filter((n) => n.answers < t);
1727
+ function Rt(e, t) {
1728
+ const o = $t(t);
1729
+ return o <= 0 ? [] : Ot(e).filter((n) => n.answers < o);
1335
1730
  }
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;
1731
+ function Xe(e) {
1732
+ const t = /* @__PURE__ */ new Set();
1733
+ return ne(e, [], (o) => {
1734
+ for (const n of o.dominoes)
1735
+ t.add(B(n));
1736
+ }), t;
1342
1737
  }
1343
- function We(e, o, t) {
1738
+ function Ft(e, t, o) {
1344
1739
  if (e.dominoes.length === 0)
1345
1740
  return [
1346
1741
  {
1347
1742
  path: [],
1348
1743
  attach: "run-tail",
1349
- value: o,
1744
+ value: t,
1350
1745
  attachToDouble: !0,
1351
1746
  // a train starts off the engine double
1352
1747
  obligation: !1
1353
1748
  }
1354
1749
  ];
1355
- const n = Ze(e, t);
1356
- if (t.doubleObligation !== "none" && n.length > 0) {
1357
- const l = Ke(t), i = [];
1750
+ const n = Rt(e, o);
1751
+ if (o.doubleObligation !== "none" && n.length > 0) {
1752
+ const i = Et(o), l = [];
1358
1753
  for (const s of n) {
1359
- const a = Je(e, s.path);
1360
- a && (!s.hasCenter && s.doubleIndex === a.dominoes.length - 1 && i.push({
1754
+ const a = At(e, s.path);
1755
+ a && (!s.hasCenter && s.doubleIndex === a.dominoes.length - 1 && l.push({
1361
1756
  path: s.path,
1362
1757
  attach: "run-tail",
1363
1758
  value: s.value,
1364
1759
  attachToDouble: !0,
1365
1760
  obligation: !0
1366
- }), s.sideToes < l && i.push({
1761
+ }), s.sideToes < i && l.push({
1367
1762
  path: s.path,
1368
1763
  attach: "side-toe",
1369
1764
  value: s.value,
@@ -1373,109 +1768,431 @@ function We(e, o, t) {
1373
1768
  obligation: !0
1374
1769
  }));
1375
1770
  }
1376
- return i;
1771
+ return l;
1377
1772
  }
1378
1773
  const r = [];
1379
- return U(e, [], (l, i) => {
1380
- const s = l.dominoes[l.dominoes.length - 1];
1774
+ return ne(e, [], (i, l) => {
1775
+ const s = i.dominoes[i.dominoes.length - 1];
1381
1776
  s && r.push({
1382
- path: i,
1777
+ path: l,
1383
1778
  attach: "run-tail",
1384
1779
  value: s.value2,
1385
- attachToDouble: de(s),
1780
+ attachToDouble: Re(s),
1386
1781
  obligation: !1
1387
1782
  });
1388
1783
  }), r;
1389
1784
  }
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 };
1785
+ function _e(e, t, o, n) {
1786
+ const r = [], i = de(e, t.value);
1787
+ return n.requireSequential && !i && r.push("value-mismatch"), n.requireUniqueTiles && o.has(B(e)) && r.push("duplicate-tile"), !n.allowConsecutiveDoubles && t.attachToDouble && Re(e) && r.push("consecutive-doubles"), { legal: r.length === 0, violations: r };
1393
1788
  }
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;
1789
+ function Nt(e, t, o, n, r) {
1790
+ const i = Ft(e, t, r), l = [];
1791
+ for (const s of i)
1792
+ for (const a of o)
1793
+ _e(a, s, n, r).legal && l.push({ end: s, tile: a });
1794
+ return l;
1400
1795
  }
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
1796
+ function Le(e, t, o) {
1797
+ if (t.length === 0)
1798
+ return o(e);
1799
+ const [n, ...r] = t, l = (e.feet?.[n.doubleIndex] ?? []).map(
1800
+ (s, a) => a === n.toeIndex ? Le(s, r, o) : s
1406
1801
  );
1407
1802
  return {
1408
1803
  ...e,
1409
- feet: { ...e.feet, [n.doubleIndex]: i }
1804
+ feet: { ...e.feet, [n.doubleIndex]: l }
1410
1805
  };
1411
1806
  }
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")
1807
+ function Yt(e, t, o) {
1808
+ const n = de(t.tile, t.end.value) ?? { ...t.tile };
1809
+ return Le(e, t.end.path, (r) => {
1810
+ if (t.end.attach === "run-tail")
1416
1811
  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] }, {
1812
+ const i = t.end.doubleIndex ?? 0, l = t.end.toeSlot ?? r.feet?.[i]?.length ?? 0, s = r.feet?.[i] ? [...r.feet[i]] : [];
1813
+ return s[l] = { dominoes: [n] }, {
1419
1814
  ...r,
1420
- feet: { ...r.feet, [l]: s }
1815
+ feet: { ...r.feet, [i]: s }
1421
1816
  };
1422
1817
  });
1423
1818
  }
1424
- function So(e, o, t) {
1425
- const n = xe(
1426
- o.tile,
1427
- o.end,
1428
- He(e),
1429
- t
1819
+ function Tn(e, t, o) {
1820
+ const n = _e(
1821
+ t.tile,
1822
+ t.end,
1823
+ Xe(e),
1824
+ o
1825
+ );
1826
+ return n.legal ? { ok: !0, board: Yt(e, t), violations: [] } : { ok: !1, board: e, violations: n.violations };
1827
+ }
1828
+ function X(e) {
1829
+ return e.kind === "play";
1830
+ }
1831
+ function Xt(e) {
1832
+ const t = [];
1833
+ return e.trains.forEach((o, n) => {
1834
+ (o.playerId === e.selfPlayerId || o.isPublic) && t.push(n);
1835
+ }), t;
1836
+ }
1837
+ function Ve(e) {
1838
+ const t = /* @__PURE__ */ new Set();
1839
+ for (const o of e)
1840
+ for (const n of Xe(o))
1841
+ t.add(n);
1842
+ return t;
1843
+ }
1844
+ function _t(e) {
1845
+ const t = Ve(e.trains), o = [];
1846
+ for (const n of Xt(e)) {
1847
+ const r = e.trains[n], i = Nt(
1848
+ r,
1849
+ e.engineValue,
1850
+ e.hand,
1851
+ t,
1852
+ e.rules
1853
+ );
1854
+ for (const l of i)
1855
+ o.push({ kind: "play", trainIndex: n, move: l });
1856
+ }
1857
+ return o;
1858
+ }
1859
+ function Lt(e = {}) {
1860
+ return (t) => {
1861
+ const o = _t(t), n = [...o];
1862
+ return (t.drawPileSize ?? Number.POSITIVE_INFINITY) > 0 && !t.turnDrawUsed && (o.length === 0 || e.allowOptionalDraw) && n.push({ kind: "draw" }), n.length === 0 && n.push({ kind: "pass" }), n;
1863
+ };
1864
+ }
1865
+ const Vt = Lt(), N = {
1866
+ preferPlay: "prefer-play",
1867
+ dumpPips: "dump-pips",
1868
+ doublesEarly: "play-doubles-early",
1869
+ ownTrain: "own-train",
1870
+ obligationRelief: "obligation-relief",
1871
+ handFlexibility: "hand-flexibility",
1872
+ defensivePublic: "defensive-public"
1873
+ };
1874
+ function Be(e) {
1875
+ const t = de(e.move.tile, e.move.end.value);
1876
+ return t ? t.value2 : e.move.tile.value2;
1877
+ }
1878
+ const Bt = {
1879
+ id: N.preferPlay,
1880
+ score(e) {
1881
+ return e.kind === "play" ? 100 : e.kind === "draw" ? 0 : -50;
1882
+ }
1883
+ }, Ut = {
1884
+ id: N.dumpPips,
1885
+ score(e) {
1886
+ if (!X(e)) return 0;
1887
+ const t = e.move.tile;
1888
+ return t.value1 + t.value2;
1889
+ }
1890
+ }, jt = {
1891
+ id: N.doublesEarly,
1892
+ score(e, t) {
1893
+ if (!X(e)) return 0;
1894
+ const o = e.move.tile;
1895
+ return o.value1 !== o.value2 ? 0 : Math.min(t.obs.hand.length, 12);
1896
+ }
1897
+ }, Gt = {
1898
+ id: N.ownTrain,
1899
+ score(e, t) {
1900
+ if (!X(e)) return 0;
1901
+ const o = t.obs.trains[e.trainIndex];
1902
+ return o && o.playerId === t.obs.selfPlayerId ? 8 : 0;
1903
+ }
1904
+ }, qt = {
1905
+ id: N.obligationRelief,
1906
+ score(e) {
1907
+ return X(e) && e.move.end.obligation ? 10 : 0;
1908
+ }
1909
+ }, Kt = {
1910
+ id: N.handFlexibility,
1911
+ score(e, t) {
1912
+ if (!X(e)) return 0;
1913
+ const o = Be(e), n = B(e.move.tile);
1914
+ let r = !1, i = 0;
1915
+ for (const l of t.obs.hand) {
1916
+ if (!r && B(l) === n) {
1917
+ r = !0;
1918
+ continue;
1919
+ }
1920
+ Fe(l, o) && i++;
1921
+ }
1922
+ return i * 3;
1923
+ }
1924
+ }, Ht = {
1925
+ id: N.defensivePublic,
1926
+ score(e, t) {
1927
+ if (!X(e)) return 0;
1928
+ const o = t.obs.trains[e.trainIndex];
1929
+ if (!o || o.playerId === t.obs.selfPlayerId) return 0;
1930
+ const n = Be(e);
1931
+ let r = 0;
1932
+ for (const i of t.unseen)
1933
+ Fe(i, n) && r++;
1934
+ return -r;
1935
+ }
1936
+ }, Zt = [
1937
+ Bt,
1938
+ Ut,
1939
+ jt,
1940
+ Gt,
1941
+ qt,
1942
+ Kt,
1943
+ Ht
1944
+ ], w = N, Jt = {
1945
+ beginner: {
1946
+ id: "beginner",
1947
+ temperature: 2.5,
1948
+ blunderRate: 0.25,
1949
+ lookaheadDepth: 0,
1950
+ enabled: /* @__PURE__ */ new Set([w.preferPlay, w.dumpPips]),
1951
+ weights: {
1952
+ [w.preferPlay]: 1,
1953
+ [w.dumpPips]: 0.2
1954
+ }
1955
+ },
1956
+ intermediate: {
1957
+ id: "intermediate",
1958
+ temperature: 0.6,
1959
+ blunderRate: 0.05,
1960
+ lookaheadDepth: 0,
1961
+ enabled: /* @__PURE__ */ new Set([w.preferPlay, w.dumpPips, w.doublesEarly, w.ownTrain]),
1962
+ weights: {
1963
+ [w.preferPlay]: 1,
1964
+ [w.dumpPips]: 1,
1965
+ [w.doublesEarly]: 1,
1966
+ [w.ownTrain]: 1
1967
+ }
1968
+ },
1969
+ advanced: {
1970
+ id: "advanced",
1971
+ temperature: 0.15,
1972
+ blunderRate: 0,
1973
+ lookaheadDepth: 0,
1974
+ enabled: /* @__PURE__ */ new Set([
1975
+ w.preferPlay,
1976
+ w.dumpPips,
1977
+ w.doublesEarly,
1978
+ w.ownTrain,
1979
+ w.obligationRelief,
1980
+ w.handFlexibility,
1981
+ w.defensivePublic
1982
+ ]),
1983
+ weights: {
1984
+ [w.preferPlay]: 1,
1985
+ [w.dumpPips]: 1.2,
1986
+ [w.doublesEarly]: 1.5,
1987
+ [w.ownTrain]: 1,
1988
+ [w.obligationRelief]: 1.5,
1989
+ [w.handFlexibility]: 1,
1990
+ [w.defensivePublic]: 1.5
1991
+ }
1992
+ }
1993
+ };
1994
+ function Mn(e) {
1995
+ return Jt[e];
1996
+ }
1997
+ function Qt(e, t, o, n) {
1998
+ let r = 0;
1999
+ for (const i of n.enabled) {
2000
+ const l = o.get(i);
2001
+ if (!l) continue;
2002
+ const s = n.weights[i] ?? 1;
2003
+ r += s * l.score(e, t);
2004
+ }
2005
+ return r;
2006
+ }
2007
+ function Wt(e, t) {
2008
+ let o = Number.NEGATIVE_INFINITY, n = [];
2009
+ return e.forEach((r, i) => {
2010
+ r > o ? (o = r, n = [i]) : r === o && n.push(i);
2011
+ }), n[Math.floor(t() * n.length)];
2012
+ }
2013
+ function en(e, t, o) {
2014
+ const n = Math.max(...e), r = e.map((s) => Math.exp((s - n) / t)), i = r.reduce((s, a) => s + a, 0);
2015
+ let l = o() * i;
2016
+ for (let s = 0; s < r.length; s++)
2017
+ if (l -= r[s], l <= 0) return s;
2018
+ return r.length - 1;
2019
+ }
2020
+ function tn(e, t, o) {
2021
+ return e.length <= 1 ? 0 : t.temperature <= 0 ? Wt(e, o) : en(e, t.temperature, o);
2022
+ }
2023
+ function nn(e) {
2024
+ const { skill: t, generateCandidates: o, buildContext: n, fallback: r } = e, i = e.rng ?? Math.random, l = new Map(e.heuristics.map((s) => [s.id, s]));
2025
+ return {
2026
+ decide(s) {
2027
+ const a = o(s);
2028
+ if (a.length === 0) return r(s);
2029
+ if (a.length === 1) return a[0];
2030
+ if (t.blunderRate > 0 && i() < t.blunderRate)
2031
+ return a[Math.floor(i() * a.length)];
2032
+ const c = n(s, a), d = a.map(
2033
+ (u) => Qt(u, c, l, t)
2034
+ );
2035
+ return a[tn(d, t, i)];
2036
+ }
2037
+ };
2038
+ }
2039
+ function on(e, t, o) {
2040
+ const n = Ve(e.trains), r = new Set(n);
2041
+ for (const l of e.hand)
2042
+ r.add(B(l));
2043
+ const i = wt(e.rules.maxPips).filter(
2044
+ (l) => !r.has(B(l))
1430
2045
  );
1431
- return n.legal ? { ok: !0, board: eo(e, o), violations: [] } : { ok: !1, board: e, violations: n.violations };
2046
+ return {
2047
+ obs: e,
2048
+ playedKeys: n,
2049
+ candidates: t,
2050
+ playCandidates: t.filter(X),
2051
+ unseen: i,
2052
+ rng: o
2053
+ };
2054
+ }
2055
+ function kn(e) {
2056
+ const t = e.heuristics ?? Zt, o = e.generateCandidates ?? Vt, n = e.rng ?? Math.random;
2057
+ return nn({
2058
+ skill: e.skill,
2059
+ heuristics: t,
2060
+ generateCandidates: o,
2061
+ buildContext: (r, i) => on(r, i, n),
2062
+ fallback: () => ({ kind: "pass" }),
2063
+ rng: n
2064
+ });
2065
+ }
2066
+ function Ue(e, t, o) {
2067
+ let n = t.legalActions(e);
2068
+ return t.orderActions && (n = t.orderActions(e, n)), Number.isFinite(o) && n.length > o && (n = n.slice(0, o)), n;
2069
+ }
2070
+ function je(e, t, o, n, r) {
2071
+ if (o <= 0 || t.isTerminal(e))
2072
+ return t.evaluate(e, n);
2073
+ const i = Ue(e, t, r);
2074
+ if (i.length === 0)
2075
+ return t.evaluate(e, n);
2076
+ const l = t.currentPlayer(e) === n;
2077
+ let s = l ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY;
2078
+ for (const a of i) {
2079
+ const c = je(
2080
+ t.applyAction(e, a),
2081
+ t,
2082
+ o - 1,
2083
+ n,
2084
+ r
2085
+ );
2086
+ s = l ? Math.max(s, c) : Math.min(s, c);
2087
+ }
2088
+ return s;
2089
+ }
2090
+ function Cn(e, t, o) {
2091
+ const n = o.rng ?? Math.random, r = Math.max(1, o.determinizations ?? 1), i = o.maxBranch ?? Number.POSITIVE_INFINITY, l = Math.max(1, o.depth);
2092
+ return Ue(e, t, i).map((a) => {
2093
+ let c = 0;
2094
+ for (let d = 0; d < r; d++) {
2095
+ const u = t.determinize ? t.determinize(e, o.perspective, n) : e;
2096
+ c += je(
2097
+ t.applyAction(u, a),
2098
+ t,
2099
+ l - 1,
2100
+ o.perspective,
2101
+ i
2102
+ );
2103
+ }
2104
+ return { action: a, value: c / r };
2105
+ });
1432
2106
  }
1433
2107
  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,
2108
+ In as CHICKEN_FOOT_FIXTURES,
2109
+ lt as CHICKEN_FOOT_TOE_ANGLES,
2110
+ Je as DEFAULT_DOMINO_THEME,
2111
+ Zt as DEFAULT_HEURISTICS,
2112
+ q as DEFAULT_PIP_COLORS,
2113
+ ie as DEFAULT_RULES,
2114
+ We as DefaultPip,
2115
+ mt as DominoHub,
2116
+ sn as DominoThemeProvider,
2117
+ bt as DominoTrain,
2118
+ Te as DoubleTwelve,
2119
+ N as HEURISTIC_IDS,
2120
+ vn as MexicanTrainGame,
2121
+ an as PIP_COLORS,
2122
+ nt as PIP_LAYOUTS,
2123
+ Jt as SKILL_PRESETS,
2124
+ zn as TRAIN_FIXTURES,
2125
+ fe as TURN_DEGREES,
2126
+ Sn as Viewport,
2127
+ Yt as applyMove,
2128
+ Wt as argmaxIndex,
2129
+ Ye as buildBranchTiles,
2130
+ tn as chooseActionIndex,
2131
+ pe as clampScale,
2132
+ Ve as collectAllPlayedKeys,
2133
+ Xe as collectPlayedKeys,
2134
+ ct as computeTrainLayout,
1448
2135
  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
2136
+ kn as createAiPlayer,
2137
+ Lt as createCandidateGenerator,
2138
+ nn as createPolicyPlayer,
2139
+ mn as cycleBendAt,
2140
+ Vt as defaultCandidateGenerator,
2141
+ B as dominoKey,
2142
+ gn as dominoSetSize,
2143
+ _e as evaluatePlacement,
2144
+ Ct as fitToBounds,
2145
+ Ee as flattenSegments,
2146
+ wt as generateDominoSet,
2147
+ _t as generatePlayActions,
2148
+ St as generateSampleTrains,
2149
+ Xt as getAccessibleTrainIndices,
2150
+ At as getBranchAt,
2151
+ Nt as getLegalMoves,
2152
+ Ft as getOpenEnds,
2153
+ ot as getPipLayout,
2154
+ cn as getPipStyle,
2155
+ Mn as getSkillProfile,
2156
+ dn as getTrainLayoutBounds,
2157
+ Rt as getUnsatisfiedDoubles,
2158
+ at as headingAtIndex,
2159
+ yt as hubTrainStartDistance,
2160
+ Re as isDouble,
2161
+ X as isPlayAction,
2162
+ $e as layoutSelfIntersects,
2163
+ De as layoutsCollide,
2164
+ bn as linearDefaultSide,
2165
+ ze as mergeDominoTheme,
2166
+ un as mergePipColors,
2167
+ Ce as normalizeBends,
2168
+ xn as offsetDefaultSide,
2169
+ Ne as oppositeSide,
2170
+ de as orientForConnection,
2171
+ hn as otherEnd,
2172
+ K as outwardPerpSign,
2173
+ Tn as playMove,
2174
+ $t as requiredDoubleAnswers,
2175
+ yn as resolveBend,
2176
+ tt as resolvePipPosition,
2177
+ Pe as resolvePipStyle,
2178
+ Pn as resolveRules,
2179
+ Qt as scoreWithHeuristics,
2180
+ wn as screenToContent,
2181
+ Cn as searchActionValues,
2182
+ se as sideToTurn,
2183
+ Et as sideToeSlots,
2184
+ en as softmaxIndex,
2185
+ A as stepAlongTrain,
2186
+ Qe as themeDataAttributes,
2187
+ be as tileCorners,
2188
+ Fe as tileHasValue,
2189
+ V as tileKey,
2190
+ ee as tilesOverlap,
2191
+ Ie as useDominoTheme,
2192
+ vt as validateChickenFootChain,
2193
+ fn as validateTrainLayout,
2194
+ pn as validateTrainTree,
2195
+ Q as withBendAt,
2196
+ me as zoomAt
1480
2197
  };
1481
2198
  //# sourceMappingURL=index.js.map