[{"data":1,"prerenderedAt":235},["ShallowReactive",2],{"profile":3,"source-chess":213},{"name":4,"meta":5,"statement":6,"lede":9,"description":10,"origin":11,"role":12,"work":13,"trajectory":59,"notes":89,"lab":92,"about":95,"contact":101,"home":115},"Chris Wijnia","Engineer · Co-founder",{"text":7,"accent":8},"I build software that holds up.","holds up.","I work out what’s worth building next.","Dutch engineer and co-founder. I work out what’s worth building next.","Netherlands","Product \u002F R&D",{"title":14,"accent":15,"outro":16,"projects":17},"A few things I’ve worked on.","worked on.","The work has changed a lot over the years. The habit of making things hasn’t.",[18,24,30,36,42,48,53],{"no":19,"name":20,"area":21,"period":22,"slug":23},"01","Agio Digital","Financial software \u002F Compliance","2021–Now","agio-digital",{"no":25,"name":26,"area":27,"period":28,"slug":29},"02","AI systems","Agents \u002F Automation \u002F Developer tools","2022–Now","ai-systems",{"no":31,"name":32,"area":33,"period":34,"slug":35},"03","1GRAM","Wallet software","2020–2021","1gram",{"no":37,"name":38,"area":39,"period":40,"slug":41},"04","MVRDV","Digital platform \u002F Architecture","2015–2019","mvrdv",{"no":43,"name":44,"area":45,"period":46,"slug":47},"05","JIJ & Overijssel","Public participation platform","2014–2018","jij-overijssel",{"no":49,"name":50,"area":51,"period":52,"slug":50},"06","100-100-100","Sustainability campaign platform","2014–2019",{"no":54,"name":55,"area":56,"period":57,"slug":58},"07","Archive","Design \u002F Web \u002F Software","2007–2022","archive",{"title":60,"eras":61},"Moving down the stack as the web evolved.",[62,66,70,73,77,81,85],{"year":63,"name":64,"line":65},"2005","Design","Learning the web by making things.",{"year":67,"name":68,"line":69},"2013","Product","Design became code.",{"name":71,"line":72},"Engineering","Code became systems.",{"year":74,"name":75,"line":76},"2018","Wallets","Software for a new kind of money.",{"year":78,"name":79,"line":80},"2021","Financial infra","Building systems where software meets regulation.",{"year":82,"name":83,"line":84},"2022","AI","From using models to orchestrating them.",{"year":86,"name":87,"line":88},"Now","Building","All of it, at once.",{"title":90,"intro":91},"Notes","Things I’m working on, learning or trying to understand.",{"title":93,"intro":94},"Small working things.","Games and toys built to find something out. Two of them let Jev play: chess, and a shared canvas of a million emoji.",{"title":96,"paragraphs":97},"I’ve been making things on computers for most of my life.",[98,99,100],"I grew up in the Netherlands and built my first websites at thirteen.","I like small teams, ambitious projects, good engineering and people who can disagree without making it tedious. I still enjoy opening an empty repository and figuring something out.","I work internationally. Outside work I train Muay Thai and like [chess](\u002Flab\u002Fchess), which I played competitively in Zwolle and taught to primary-school children there. I also build things that occasionally have no sensible commercial purpose.",{"title":102,"accent":103,"intro":104,"links":105},"Making something interesting?","interesting?","For collaborations, technical discussions, or a good reason I haven’t thought of.",[106,109,112],{"label":107,"href":108},"LinkedIn","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fchris-wijnia-1364a29b",{"label":110,"href":111},"GitHub","https:\u002F\u002Fgithub.com\u002Fcwdx",{"label":113,"href":114},"X","https:\u002F\u002Fx.com\u002FChrisWijnia",{"hero":116,"chapters":123,"principles":187,"work":203,"contact":207},{"headline":117,"lede":121,"cue":122},[118,119,120],"Every system","is one bit,","repeated.","Chris Wijnia is a Dutch engineer and co-founder. He works on financial software and AI systems.","Scroll to scale up",[124,135,147,161,175],{"id":125,"power":126,"name":127,"label":128,"formation":125,"cell":129,"headline":130,"body":133,"prompt":134},"bit","2^0","Bit","The bit · 1 state of 2",16,[131,132],"Yes.","Or no.","Approve the payment or hold it. Trust the answer or ask again. Ship the pixel or move it one to the left. Everything I build ends in a decision small enough to fit in one bit. The work is making sure it is the right one.","Flip the bit. This page has two states.",{"id":136,"power":137,"name":138,"label":139,"formation":136,"cell":140,"headline":141,"body":145,"prompt":146},"byte","2^3","Byte","The byte · design",8,[142,143,144],"Eight bits","make a","letter.","I started in design, placing pixels one at a time until a shape read as a word. Software is built the same way: from the smallest unit up.","Flip a bit. Make a letter.",{"id":148,"power":149,"name":150,"label":151,"formation":148,"cell":152,"ink":153,"headline":154,"body":159,"prompt":160},"ledger","2^10","Ledger","The ledger · financial software",4,true,[155,156,157,158],"Money is","the least","forgiving","data type.","In financial software nothing is probably right. No rounding error is too small to matter, and no state is allowed to drift. Every debit meets its credit. Every action leaves a record that adds up, today and in the audit years from now.","Simulated ledger",{"id":162,"power":163,"name":164,"label":165,"formation":162,"cell":166,"headline":167,"body":172,"prompt":173,"note":174},"weights","2^20","Weights","The weights · AI systems",2,[168,169,170,171],"A million","decisions,","none made","on purpose.","A model is a vast field of numbers nobody set by hand. Useful, and never quite certain. I build the part around it: where it may act alone, where it has to ask, and how anyone can check afterwards what it did and why.","Confidence","ai-makes-software-cheaper",{"id":176,"power":177,"name":178,"label":179,"formation":180,"cell":152,"headline":181,"body":186},"company","2^n","Company","The company · co-founder","knot",[182,183,184,185],"A company","is a system","with people","inside.","A company runs on what good software runs on: clear states, clean interfaces, and nothing that only works as long as someone remembers.",[188,191,194,197,200],{"name":189,"line":190},"Resolution is a choice","Decide how much detail a problem deserves, then commit to it.",{"name":192,"line":193},"Two states beat five","If a feature cannot say yes or no, it is not finished.",{"name":195,"line":196},"The ledger balances","Every action leaves a record, and the records add up.",{"name":198,"line":199},"The model proposes","A person signs. The system always knows which is which.",{"name":201,"line":202},"Every pixel on purpose","Including the ones nobody will ever notice.",{"label":204,"headline":205},"Work · 2007–now",[206],"Work.",{"label":208,"headline":209,"intro":212},"Back to one bit",[210,211],"Send","one bit.","Building something where a wrong answer costs money, or where a machine’s answer has to be trusted? Tell me in a line. I will answer in more than one bit.",{"files":214},[215,220,225,230],{"path":216,"lines":217,"code":218,"html":219},"app\u002Fcomponents\u002Flab\u002FChessBoard.vue",215,"\u003Cscript setup lang=\"ts\">\nimport type { NormalMove, Role } from 'chessops\u002Ftypes'\nimport { isDarkSquare, NAMES, squareName } from '@cw\u002Fchess\u002Frules'\nimport { BOARD_THEMES, PLAIN_FONTS, squareGlyph, type BoardTheme, type ChessFont } from '#core\u002Fdomain\u002Fchess-board'\nimport type { Ply } from '~\u002Fcomposables\u002FuseChessGame'\n\nconst props = defineProps\u003C{\n  squares: string[]\n  font: ChessFont\n  theme: BoardTheme\n  flipped: boolean\n  interactive: boolean\n  targets: (from: number) => Map\u003Cnumber, NormalMove>\n  needsPromotion: (move: NormalMove) => boolean\n  check?: number\n  last?: Ply\n  plyCount: number\n  \u002F** While an engine thinks, the person's colour: a move becomes a premove. *\u002F\n  premoveColor?: 'white' | 'black'\n  premove?: { from: number; to: number }\n  arrows?: { from: number; to: number; p: number }[]\n}>()\nconst emit = defineEmits\u003C{ move: [NormalMove]; premove: [{ from: number; to: number }]; cancelPremove: [] }>()\n\nconst family = computed(() => `'Chess ${props.font}', var(--font-mono)`)\nconst themeVars = computed(() => {\n  const t: { ground: string; ink: string; mark: string; dark?: string } = BOARD_THEMES[props.theme]\n  return {\n    '--board-ground': `var(--color-${t.ground})`, '--board-ink': `var(--color-${t.ink})`, '--board-mark': `var(--color-${t.mark})`,\n    \u002F\u002F a font that draws no squares gets them from the board: the theme's own dark, else a tint of its ink\n    '--board-dark': t.dark ? `var(--color-${t.dark})` : 'color-mix(in srgb, var(--board-ink) 16%, var(--board-ground))',\n  }\n})\nconst centre = (sq: number) => { const f = sq & 7, r = sq >> 3; return props.flipped ? [7 - f + 0.5, r + 0.5] : [f + 0.5, 7 - r + 0.5] }\nconst arrowLines = computed(() => (props.arrows ?? []).filter((a) => a.p >= 0.02).map((a) => {\n  const [x1, y1] = centre(a.from), [x2, y2] = centre(a.to)\n  \u002F\u002F stop short of the centre, so the head (0.42 wide, its tip 0.3 past the line's end) points at the square\n  const len = Math.hypot(x2! - x1!, y2! - y1!), cut = 0.35 \u002F len\n  return { key: `${a.from}-${a.to}`, x1, y1, x2: x2! - (x2! - x1!) * cut, y2: y2! - (y2! - y1!) * cut, w: 0.07 + a.p * 0.13, o: 0.35 + a.p * 0.6 }\n}))\nconst order = computed(() => Array.from({ length: 64 }, (_, i) => {\n  const row = i >> 3, col = i & 7\n  return props.flipped ? row * 8 + (7 - col) : (7 - row) * 8 + col\n}))\n\nconst selected = ref\u003Cnumber>()\nconst legal = computed(() => (selected.value === undefined ? new Map\u003Cnumber, NormalMove>() : props.targets(selected.value)))\nconst promoting = ref\u003CNormalMove>()\nconst hidden = ref(new Set\u003Cnumber>())\nconst focus = ref(12)\nconst board = ref\u003CHTMLElement>()\n\nconst ownPiece = (sq: number, white: boolean) => { const p = props.squares[sq]; return !!p && (p === p.toUpperCase()) === white }\nconst whiteToMove = computed(() => props.plyCount % 2 === 0)\nconst premoving = computed(() => !props.interactive && !!props.premoveColor)\nconst mover = computed(() => (props.interactive ? (whiteToMove.value ? 'white' : 'black') : props.premoveColor))\n\nfunction pick(sq: number) {\n  if (premoving.value) {\n    \u002F\u002F any square will do for a premove; it is checked once the engine has moved\n    if (selected.value !== undefined && sq !== selected.value) { emit('premove', { from: selected.value, to: sq }); selected.value = undefined; return }\n    if (selected.value === undefined && !ownPiece(sq, mover.value === 'white')) { emit('cancelPremove'); return }\n    selected.value = selected.value === sq ? undefined : sq\n    return\n  }\n  if (!props.interactive) return\n  const move = legal.value.get(sq)\n  if (move) {\n    selected.value = undefined\n    if (props.needsPromotion(move)) { promoting.value = move; return }\n    emit('move', move)\n    return\n  }\n  selected.value = selected.value !== sq && ownPiece(sq, mover.value === 'white') && props.targets(sq).size ? sq : undefined\n}\nfunction promote(role: Role) {\n  if (!promoting.value) return\n  emit('move', { ...promoting.value, promotion: role })\n  promoting.value = undefined\n}\nwatch(() => props.plyCount, () => { if (!premoving.value) selected.value = undefined; promoting.value = undefined })\n\nfunction label(sq: number) {\n  const p = props.squares[sq]\n  const piece = p ? `${p === p.toUpperCase() ? 'white' : 'black'} ${NAMES[p.toUpperCase()]!.toLowerCase()}` : 'empty'\n  const extra = sq === selected.value ? ', selected' : legal.value.has(sq) ? ', move here' : ''\n  return `${squareName(sq)}, ${piece}${extra}`\n}\nfunction key(e: KeyboardEvent) {\n  const step: Record\u003Cstring, [number, number]> = { ArrowUp: [0, 1], ArrowDown: [0, -1], ArrowLeft: [-1, 0], ArrowRight: [1, 0] }\n  const d = step[e.key]\n  if (!d) return\n  e.preventDefault()\n  const [df, dr] = props.flipped ? [-d[0], -d[1]] : d\n  const f = Math.min(7, Math.max(0, (focus.value & 7) + df)), r = Math.min(7, Math.max(0, (focus.value >> 3) + dr))\n  focus.value = r * 8 + f\n  board.value?.querySelector\u003CHTMLElement>(`[data-sq=\"${focus.value}\"]`)?.focus()\n}\n\n\u002F\u002F a White glyph is only an outline, so the solid Black glyph goes underneath in Paper to fill it\nfunction makeTile(piece: string, size: number) {\n  const tile = document.createElement('span')\n  tile.className = 'board__tile'\n  tile.append(\n    Object.assign(document.createElement('span'), { className: 'board__fill', textContent: squareGlyph(piece.toLowerCase(), false, props.font) }),\n    Object.assign(document.createElement('span'), { textContent: squareGlyph(piece, false, props.font) }),\n  )\n  Object.assign(tile.style, { width: `${size}px`, height: `${size}px`, fontFamily: family.value })\n  board.value!.append(tile)\n  return tile\n}\n\nlet drag: { from: number; x: number; y: number; tile?: HTMLElement; size: number } | undefined\nlet dropped = false\nlet swallowClick = false\nconst movable = (sq: number) => (props.interactive || premoving.value) && !!mover.value && ownPiece(sq, mover.value === 'white')\nlet unlisten: (() => void)[] = []\nfunction down(sq: number, e: PointerEvent) {\n  if (!movable(sq) || e.button !== 0) return\n  const size = board.value!.querySelector\u003CHTMLElement>(`[data-sq=\"${sq}\"]`)!.getBoundingClientRect().width\n  drag = { from: sq, x: e.clientX, y: e.clientY, size }\n  unlisten = [useEventListener(window, 'pointermove', moveDrag), useEventListener(window, 'pointerup', endDrag), useEventListener(window, 'pointercancel', cleanup)]\n}\nfunction place(tile: HTMLElement, x: number, y: number, size: number) {\n  const o = board.value!.getBoundingClientRect()\n  tile.style.left = `${x - o.left - size \u002F 2}px`\n  tile.style.top = `${y - o.top - size \u002F 2}px`\n}\nfunction moveDrag(e: PointerEvent) {\n  if (!drag) return\n  if (!drag.tile) {\n    if (Math.hypot(e.clientX - drag.x, e.clientY - drag.y) \u003C 5) return\n    selected.value = drag.from\n    hidden.value = new Set([drag.from])\n    drag.tile = makeTile(props.squares[drag.from]!, drag.size)\n    drag.tile.classList.add('is-dragging')\n  }\n  place(drag.tile, e.clientX, e.clientY, drag.size)\n}\nfunction cleanup() {\n  unlisten.forEach((u) => u())\n  drag?.tile?.remove()\n  hidden.value = new Set()\n  drag = undefined\n}\nfunction endDrag(e: PointerEvent) {\n  if (!drag?.tile) return cleanup()\n  swallowClick = true\n  const target = document.elementFromPoint(e.clientX, e.clientY)?.closest\u003CHTMLElement>('[data-sq]')\n  const to = target ? Number(target.dataset.sq) : undefined\n  const from = drag.from\n  cleanup()\n  if (premoving.value) { selected.value = undefined; if (to !== undefined && to !== from) emit('premove', { from, to }); return }\n  if (to !== undefined && legal.value.has(to)) { dropped = true; pick(to) } else selected.value = undefined\n}\nfunction clicked(sq: number) {\n  if (swallowClick) { swallowClick = false; return }\n  focus.value = sq\n  pick(sq)\n}\nonBeforeUnmount(cleanup)\n\nasync function animate(ply: Ply) {\n  if (dropped) { dropped = false; return }\n  if (useReducedMotion() || !board.value) return\n  const paths: [number, number][] = ply.castle\n    ? [[ply.move.from, ply.castle.kingTo], [ply.castle.rookFrom, ply.castle.rookTo]]\n    : [[ply.move.from, ply.move.to]]\n  hidden.value = new Set(paths.map(([, to]) => to))\n  await nextTick()\n  const rect = (sq: number) => board.value!.querySelector\u003CHTMLElement>(`[data-sq=\"${sq}\"]`)!.getBoundingClientRect()\n  const origin = board.value.getBoundingClientRect()\n  await Promise.all(paths.map(([from, to]) => {\n    const a = rect(from), b = rect(to)\n    const tile = makeTile(props.squares[to]!, a.width)\n    Object.assign(tile.style, { left: `${a.left - origin.left}px`, top: `${a.top - origin.top}px` })\n    const dx = b.left - a.left, dy = b.top - a.top\n    return tile.animate(\n      [{ transform: 'translate(0, 0)' }, { transform: `translate(${dx}px, ${dy}px)` }],\n      { duration: 240, easing: 'cubic-bezier(.2, .7, .1, 1)' },\n    ).finished.finally(() => tile.remove())\n  }))\n  hidden.value = new Set()\n}\nwatch(() => props.last, (ply, prev) => { if (ply && ply !== prev && props.plyCount > 0) void animate(ply) })\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv ref=\"board\" class=\"board__grid\" :class=\"{ 'board__grid--plain': PLAIN_FONTS.has(font) }\" role=\"grid\" aria-label=\"Chess board\" :style=\"{ fontFamily: family, ...themeVars }\" @keydown=\"key\">\n    \u003Cbutton\n      v-for=\"sq in order\" :key=\"sq\" type=\"button\" class=\"board__sq\" :data-sq=\"sq\"\n      :class=\"{\n        'is-dark': isDarkSquare(sq),\n        'is-selected': sq === selected,\n        'is-target': legal.has(sq),\n        'is-capture': legal.has(sq) && !!squares[sq],\n        'is-last': last && (sq === last.move.from || sq === (last.castle?.kingTo ?? last.move.to)),\n        'is-check': sq === check,\n        'is-movable': movable(sq),\n        'is-premove': premove && (sq === premove.from || sq === premove.to),\n      }\"\n      :tabindex=\"sq === focus ? 0 : -1\" :aria-label=\"label(sq)\" :aria-disabled=\"!interactive\"\n      @click=\"clicked(sq)\" @pointerdown=\"down(sq, $event)\"\n    >{{ squareGlyph(hidden.has(sq) ? '' : squares[sq]!, isDarkSquare(sq), font) }}\u003C\u002Fbutton>\n    \u003Csvg v-if=\"arrowLines.length\" class=\"board__arrows\" viewBox=\"0 0 8 8\" aria-hidden=\"true\">\n      \u003Cdefs>\u003Cmarker id=\"board-arrow\" viewBox=\"0 0 4 4\" refX=\"1\" refY=\"2\" markerUnits=\"userSpaceOnUse\" markerWidth=\"0.42\" markerHeight=\"0.42\" orient=\"auto\">\u003Cpath d=\"M0,0 L4,2 L0,4 z\" fill=\"context-stroke\" \u002F>\u003C\u002Fmarker>\u003C\u002Fdefs>\n      \u003Cline v-for=\"a in arrowLines\" :key=\"a.key\" :x1=\"a.x1\" :y1=\"a.y1\" :x2=\"a.x2\" :y2=\"a.y2\" :stroke-width=\"a.w\" :opacity=\"a.o\" marker-end=\"url(#board-arrow)\" \u002F>\n    \u003C\u002Fsvg>\n    \u003Cdiv v-if=\"promoting\" class=\"board__promote\" role=\"dialog\" aria-label=\"Promote to\">\n      \u003Cbutton v-for=\"r in (['queen', 'rook', 'bishop', 'knight'] as Role[])\" :key=\"r\" type=\"button\" :aria-label=\"`Promote to ${r}`\" @click=\"promote(r)\">\n        {{ squareGlyph(({ queen: 'Q', rook: 'R', bishop: 'B', knight: 'N' } as Record\u003Cstring, string>)[r]![whiteToMove ? 'toUpperCase' : 'toLowerCase'](), false, font) }}\n      \u003C\u002Fbutton>\n    \u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>","\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">script\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">setup\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">lang\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;ts&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"language-javascript\">\n\u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan> type { \u003Cspan class=\"hljs-title class_\">NormalMove\u003C\u002Fspan>, \u003Cspan class=\"hljs-title class_\">Role\u003C\u002Fspan> } \u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;chessops\u002Ftypes&#x27;\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan> { isDarkSquare, \u003Cspan class=\"hljs-variable constant_\">NAMES\u003C\u002Fspan>, squareName } \u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;@cw\u002Fchess\u002Frules&#x27;\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan> { \u003Cspan class=\"hljs-variable constant_\">BOARD_THEMES\u003C\u002Fspan>, \u003Cspan class=\"hljs-variable constant_\">PLAIN_FONTS\u003C\u002Fspan>, squareGlyph, type \u003Cspan class=\"hljs-title class_\">BoardTheme\u003C\u002Fspan>, type \u003Cspan class=\"hljs-title class_\">ChessFont\u003C\u002Fspan> } \u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;#core\u002Fdomain\u002Fchess-board&#x27;\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan> type { \u003Cspan class=\"hljs-title class_\">Ply\u003C\u002Fspan> } \u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;~\u002Fcomposables\u002FuseChessGame&#x27;\u003C\u002Fspan>\n\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> props = defineProps&lt;{\n  \u003Cspan class=\"hljs-attr\">squares\u003C\u002Fspan>: string[]\n  \u003Cspan class=\"hljs-attr\">font\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">ChessFont\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-attr\">theme\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">BoardTheme\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-attr\">flipped\u003C\u002Fspan>: boolean\n  \u003Cspan class=\"hljs-attr\">interactive\u003C\u002Fspan>: boolean\n  \u003Cspan class=\"hljs-attr\">targets\u003C\u002Fspan>: \u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">\u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan>: number\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Map\u003C\u002Fspan>&lt;number, \u003Cspan class=\"hljs-title class_\">NormalMove\u003C\u002Fspan>&gt;\n  \u003Cspan class=\"hljs-attr\">needsPromotion\u003C\u002Fspan>: \u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">move: NormalMove\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> boolean\n  check?: number\n  last?: \u003Cspan class=\"hljs-title class_\">Ply\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-attr\">plyCount\u003C\u002Fspan>: number\n  \u003Cspan class=\"hljs-comment\">\u002F** While an engine thinks, the person&#x27;s colour: a move becomes a premove. *\u002F\u003C\u002Fspan>\n  premoveColor?: \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan> | \u003Cspan class=\"hljs-string\">&#x27;black&#x27;\u003C\u002Fspan>\n  premove?: { \u003Cspan class=\"hljs-attr\">from\u003C\u002Fspan>: number; \u003Cspan class=\"hljs-attr\">to\u003C\u002Fspan>: number }\n  arrows?: { \u003Cspan class=\"hljs-attr\">from\u003C\u002Fspan>: number; \u003Cspan class=\"hljs-attr\">to\u003C\u002Fspan>: number; \u003Cspan class=\"hljs-attr\">p\u003C\u002Fspan>: number }[]\n}&gt;()\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> emit = defineEmits&lt;{ \u003Cspan class=\"hljs-attr\">move\u003C\u002Fspan>: [\u003Cspan class=\"hljs-title class_\">NormalMove\u003C\u002Fspan>]; \u003Cspan class=\"hljs-attr\">premove\u003C\u002Fspan>: [{ \u003Cspan class=\"hljs-attr\">from\u003C\u002Fspan>: number; \u003Cspan class=\"hljs-attr\">to\u003C\u002Fspan>: number }]; \u003Cspan class=\"hljs-attr\">cancelPremove\u003C\u002Fspan>: [] }&gt;()\n\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> family = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">`&#x27;Chess \u003Cspan class=\"hljs-subst\">${props.font}\u003C\u002Fspan>&#x27;, var(--font-mono)`\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> themeVars = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> {\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">t\u003C\u002Fspan>: { \u003Cspan class=\"hljs-attr\">ground\u003C\u002Fspan>: string; \u003Cspan class=\"hljs-attr\">ink\u003C\u002Fspan>: string; \u003Cspan class=\"hljs-attr\">mark\u003C\u002Fspan>: string; dark?: string } = \u003Cspan class=\"hljs-variable constant_\">BOARD_THEMES\u003C\u002Fspan>[props.\u003Cspan class=\"hljs-property\">theme\u003C\u002Fspan>]\n  \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> {\n    \u003Cspan class=\"hljs-string\">&#x27;--board-ground&#x27;\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">`var(--color-\u003Cspan class=\"hljs-subst\">${t.ground}\u003C\u002Fspan>)`\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;--board-ink&#x27;\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">`var(--color-\u003Cspan class=\"hljs-subst\">${t.ink}\u003C\u002Fspan>)`\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;--board-mark&#x27;\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">`var(--color-\u003Cspan class=\"hljs-subst\">${t.mark}\u003C\u002Fspan>)`\u003C\u002Fspan>,\n    \u003Cspan class=\"hljs-comment\">\u002F\u002F a font that draws no squares gets them from the board: the theme&#x27;s own dark, else a tint of its ink\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-string\">&#x27;--board-dark&#x27;\u003C\u002Fspan>: t.\u003Cspan class=\"hljs-property\">dark\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">`var(--color-\u003Cspan class=\"hljs-subst\">${t.dark}\u003C\u002Fspan>)`\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;color-mix(in srgb, var(--board-ink) 16%, var(--board-ground))&#x27;\u003C\u002Fspan>,\n  }\n})\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">centre\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">sq: number\u003C\u002Fspan>) =&gt; { \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> f = sq &amp; \u003Cspan class=\"hljs-number\">7\u003C\u002Fspan>, r = sq &gt;&gt; \u003Cspan class=\"hljs-number\">3\u003C\u002Fspan>; \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> props.\u003Cspan class=\"hljs-property\">flipped\u003C\u002Fspan> ? [\u003Cspan class=\"hljs-number\">7\u003C\u002Fspan> - f + \u003Cspan class=\"hljs-number\">0.5\u003C\u002Fspan>, r + \u003Cspan class=\"hljs-number\">0.5\u003C\u002Fspan>] : [f + \u003Cspan class=\"hljs-number\">0.5\u003C\u002Fspan>, \u003Cspan class=\"hljs-number\">7\u003C\u002Fspan> - r + \u003Cspan class=\"hljs-number\">0.5\u003C\u002Fspan>] }\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> arrowLines = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> (props.\u003Cspan class=\"hljs-property\">arrows\u003C\u002Fspan> ?? []).\u003Cspan class=\"hljs-title function_\">filter\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">a\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> a.\u003Cspan class=\"hljs-property\">p\u003C\u002Fspan> &gt;= \u003Cspan class=\"hljs-number\">0.02\u003C\u002Fspan>).\u003Cspan class=\"hljs-title function_\">map\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">a\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> {\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> [x1, y1] = \u003Cspan class=\"hljs-title function_\">centre\u003C\u002Fspan>(a.\u003Cspan class=\"hljs-property\">from\u003C\u002Fspan>), [x2, y2] = \u003Cspan class=\"hljs-title function_\">centre\u003C\u002Fspan>(a.\u003Cspan class=\"hljs-property\">to\u003C\u002Fspan>)\n  \u003Cspan class=\"hljs-comment\">\u002F\u002F stop short of the centre, so the head (0.42 wide, its tip 0.3 past the line&#x27;s end) points at the square\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> len = \u003Cspan class=\"hljs-title class_\">Math\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">hypot\u003C\u002Fspan>(x2! - x1!, y2! - y1!), cut = \u003Cspan class=\"hljs-number\">0.35\u003C\u002Fspan> \u002F len\n  \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> { \u003Cspan class=\"hljs-attr\">key\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${a.\u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan>}\u003C\u002Fspan>-\u003Cspan class=\"hljs-subst\">${a.to}\u003C\u002Fspan>`\u003C\u002Fspan>, x1, y1, \u003Cspan class=\"hljs-attr\">x2\u003C\u002Fspan>: x2! - (x2! - x1!) * cut, \u003Cspan class=\"hljs-attr\">y2\u003C\u002Fspan>: y2! - (y2! - y1!) * cut, \u003Cspan class=\"hljs-attr\">w\u003C\u002Fspan>: \u003Cspan class=\"hljs-number\">0.07\u003C\u002Fspan> + a.\u003Cspan class=\"hljs-property\">p\u003C\u002Fspan> * \u003Cspan class=\"hljs-number\">0.13\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">o\u003C\u002Fspan>: \u003Cspan class=\"hljs-number\">0.35\u003C\u002Fspan> + a.\u003Cspan class=\"hljs-property\">p\u003C\u002Fspan> * \u003Cspan class=\"hljs-number\">0.6\u003C\u002Fspan> }\n}))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> order = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Array\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">from\u003C\u002Fspan>({ \u003Cspan class=\"hljs-attr\">length\u003C\u002Fspan>: \u003Cspan class=\"hljs-number\">64\u003C\u002Fspan> }, \u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">_, i\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> {\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> row = i &gt;&gt; \u003Cspan class=\"hljs-number\">3\u003C\u002Fspan>, col = i &amp; \u003Cspan class=\"hljs-number\">7\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> props.\u003Cspan class=\"hljs-property\">flipped\u003C\u002Fspan> ? row * \u003Cspan class=\"hljs-number\">8\u003C\u002Fspan> + (\u003Cspan class=\"hljs-number\">7\u003C\u002Fspan> - col) : (\u003Cspan class=\"hljs-number\">7\u003C\u002Fspan> - row) * \u003Cspan class=\"hljs-number\">8\u003C\u002Fspan> + col\n}))\n\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> selected = ref&lt;number&gt;()\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> legal = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> (selected.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan> ? \u003Cspan class=\"hljs-keyword\">new\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Map\u003C\u002Fspan>&lt;number, \u003Cspan class=\"hljs-title class_\">NormalMove\u003C\u002Fspan>&gt;() : props.\u003Cspan class=\"hljs-title function_\">targets\u003C\u002Fspan>(selected.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>)))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> promoting = ref&lt;\u003Cspan class=\"hljs-title class_\">NormalMove\u003C\u002Fspan>&gt;()\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> hidden = \u003Cspan class=\"hljs-title function_\">ref\u003C\u002Fspan>(\u003Cspan class=\"hljs-keyword\">new\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Set\u003C\u002Fspan>&lt;number&gt;())\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> focus = \u003Cspan class=\"hljs-title function_\">ref\u003C\u002Fspan>(\u003Cspan class=\"hljs-number\">12\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> board = ref&lt;\u003Cspan class=\"hljs-title class_\">HTMLElement\u003C\u002Fspan>&gt;()\n\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">ownPiece\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">sq: number, white: boolean\u003C\u002Fspan>) =&gt; { \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> p = props.\u003Cspan class=\"hljs-property\">squares\u003C\u002Fspan>[sq]; \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> !!p &amp;&amp; (p === p.\u003Cspan class=\"hljs-title function_\">toUpperCase\u003C\u002Fspan>()) === white }\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> whiteToMove = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> props.\u003Cspan class=\"hljs-property\">plyCount\u003C\u002Fspan> % \u003Cspan class=\"hljs-number\">2\u003C\u002Fspan> === \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> premoving = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> !props.\u003Cspan class=\"hljs-property\">interactive\u003C\u002Fspan> &amp;&amp; !!props.\u003Cspan class=\"hljs-property\">premoveColor\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> mover = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> (props.\u003Cspan class=\"hljs-property\">interactive\u003C\u002Fspan> ? (whiteToMove.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;black&#x27;\u003C\u002Fspan>) : props.\u003Cspan class=\"hljs-property\">premoveColor\u003C\u002Fspan>))\n\n\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">pick\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">sq: number\u003C\u002Fspan>) {\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (premoving.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) {\n    \u003Cspan class=\"hljs-comment\">\u002F\u002F any square will do for a premove; it is checked once the engine has moved\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (selected.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> !== \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan> &amp;&amp; sq !== selected.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) { \u003Cspan class=\"hljs-title function_\">emit\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;premove&#x27;\u003C\u002Fspan>, { \u003Cspan class=\"hljs-attr\">from\u003C\u002Fspan>: selected.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">to\u003C\u002Fspan>: sq }); selected.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>; \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> }\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (selected.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan> &amp;&amp; !\u003Cspan class=\"hljs-title function_\">ownPiece\u003C\u002Fspan>(sq, mover.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan>)) { \u003Cspan class=\"hljs-title function_\">emit\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;cancelPremove&#x27;\u003C\u002Fspan>); \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> }\n    selected.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = selected.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === sq ? \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan> : sq\n    \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n  }\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!props.\u003Cspan class=\"hljs-property\">interactive\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> move = legal.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">get\u003C\u002Fspan>(sq)\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (move) {\n    selected.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (props.\u003Cspan class=\"hljs-title function_\">needsPromotion\u003C\u002Fspan>(move)) { promoting.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = move; \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> }\n    \u003Cspan class=\"hljs-title function_\">emit\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;move&#x27;\u003C\u002Fspan>, move)\n    \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n  }\n  selected.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = selected.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> !== sq &amp;&amp; \u003Cspan class=\"hljs-title function_\">ownPiece\u003C\u002Fspan>(sq, mover.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan>) &amp;&amp; props.\u003Cspan class=\"hljs-title function_\">targets\u003C\u002Fspan>(sq).\u003Cspan class=\"hljs-property\">size\u003C\u002Fspan> ? sq : \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>\n}\n\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">promote\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">role: Role\u003C\u002Fspan>) {\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!promoting.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-title function_\">emit\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;move&#x27;\u003C\u002Fspan>, { ...promoting.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">promotion\u003C\u002Fspan>: role })\n  promoting.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>\n}\n\u003Cspan class=\"hljs-title function_\">watch\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> props.\u003Cspan class=\"hljs-property\">plyCount\u003C\u002Fspan>, \u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> { \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!premoving.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) selected.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>; promoting.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan> })\n\n\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">label\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">sq: number\u003C\u002Fspan>) {\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> p = props.\u003Cspan class=\"hljs-property\">squares\u003C\u002Fspan>[sq]\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> piece = p ? \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${p === p.toUpperCase() ? \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;black&#x27;\u003C\u002Fspan>}\u003C\u002Fspan> \u003Cspan class=\"hljs-subst\">${NAMES[p.toUpperCase()]!.toLowerCase()}\u003C\u002Fspan>`\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;empty&#x27;\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> extra = sq === selected.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;, selected&#x27;\u003C\u002Fspan> : legal.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">has\u003C\u002Fspan>(sq) ? \u003Cspan class=\"hljs-string\">&#x27;, move here&#x27;\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${squareName(sq)}\u003C\u002Fspan>, \u003Cspan class=\"hljs-subst\">${piece}\u003C\u002Fspan>\u003Cspan class=\"hljs-subst\">${extra}\u003C\u002Fspan>`\u003C\u002Fspan>\n}\n\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">key\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">e: KeyboardEvent\u003C\u002Fspan>) {\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">step\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">Record\u003C\u002Fspan>&lt;string, [number, number]&gt; = { \u003Cspan class=\"hljs-title class_\">ArrowUp\u003C\u002Fspan>: [\u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>, \u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>], \u003Cspan class=\"hljs-title class_\">ArrowDown\u003C\u002Fspan>: [\u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>, -\u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>], \u003Cspan class=\"hljs-title class_\">ArrowLeft\u003C\u002Fspan>: [-\u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>, \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>], \u003Cspan class=\"hljs-title class_\">ArrowRight\u003C\u002Fspan>: [\u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>, \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>] }\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> d = step[e.\u003Cspan class=\"hljs-property\">key\u003C\u002Fspan>]\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!d) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n  e.\u003Cspan class=\"hljs-title function_\">preventDefault\u003C\u002Fspan>()\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> [df, dr] = props.\u003Cspan class=\"hljs-property\">flipped\u003C\u002Fspan> ? [-d[\u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>], -d[\u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>]] : d\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> f = \u003Cspan class=\"hljs-title class_\">Math\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">min\u003C\u002Fspan>(\u003Cspan class=\"hljs-number\">7\u003C\u002Fspan>, \u003Cspan class=\"hljs-title class_\">Math\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">max\u003C\u002Fspan>(\u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>, (focus.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> &amp; \u003Cspan class=\"hljs-number\">7\u003C\u002Fspan>) + df)), r = \u003Cspan class=\"hljs-title class_\">Math\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">min\u003C\u002Fspan>(\u003Cspan class=\"hljs-number\">7\u003C\u002Fspan>, \u003Cspan class=\"hljs-title class_\">Math\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">max\u003C\u002Fspan>(\u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>, (focus.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> &gt;&gt; \u003Cspan class=\"hljs-number\">3\u003C\u002Fspan>) + dr))\n  focus.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = r * \u003Cspan class=\"hljs-number\">8\u003C\u002Fspan> + f\n  board.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>?.\u003Cspan class=\"hljs-property\">querySelector\u003C\u002Fspan>&lt;\u003Cspan class=\"hljs-title class_\">HTMLElement\u003C\u002Fspan>&gt;(\u003Cspan class=\"hljs-string\">`[data-sq=&quot;\u003Cspan class=\"hljs-subst\">${focus.value}\u003C\u002Fspan>&quot;]`\u003C\u002Fspan>)?.\u003Cspan class=\"hljs-title function_\">focus\u003C\u002Fspan>()\n}\n\n\u003Cspan class=\"hljs-comment\">\u002F\u002F a White glyph is only an outline, so the solid Black glyph goes underneath in Paper to fill it\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">makeTile\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">piece: string, size: number\u003C\u002Fspan>) {\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> tile = \u003Cspan class=\"hljs-variable language_\">document\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">createElement\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;span&#x27;\u003C\u002Fspan>)\n  tile.\u003Cspan class=\"hljs-property\">className\u003C\u002Fspan> = \u003Cspan class=\"hljs-string\">&#x27;board__tile&#x27;\u003C\u002Fspan>\n  tile.\u003Cspan class=\"hljs-title function_\">append\u003C\u002Fspan>(\n    \u003Cspan class=\"hljs-title class_\">Object\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">assign\u003C\u002Fspan>(\u003Cspan class=\"hljs-variable language_\">document\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">createElement\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;span&#x27;\u003C\u002Fspan>), { \u003Cspan class=\"hljs-attr\">className\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;board__fill&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">textContent\u003C\u002Fspan>: \u003Cspan class=\"hljs-title function_\">squareGlyph\u003C\u002Fspan>(piece.\u003Cspan class=\"hljs-title function_\">toLowerCase\u003C\u002Fspan>(), \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>, props.\u003Cspan class=\"hljs-property\">font\u003C\u002Fspan>) }),\n    \u003Cspan class=\"hljs-title class_\">Object\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">assign\u003C\u002Fspan>(\u003Cspan class=\"hljs-variable language_\">document\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">createElement\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;span&#x27;\u003C\u002Fspan>), { \u003Cspan class=\"hljs-attr\">textContent\u003C\u002Fspan>: \u003Cspan class=\"hljs-title function_\">squareGlyph\u003C\u002Fspan>(piece, \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>, props.\u003Cspan class=\"hljs-property\">font\u003C\u002Fspan>) }),\n  )\n  \u003Cspan class=\"hljs-title class_\">Object\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">assign\u003C\u002Fspan>(tile.\u003Cspan class=\"hljs-property\">style\u003C\u002Fspan>, { \u003Cspan class=\"hljs-attr\">width\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${size}\u003C\u002Fspan>px`\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">height\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${size}\u003C\u002Fspan>px`\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">fontFamily\u003C\u002Fspan>: family.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> })\n  board.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>!.\u003Cspan class=\"hljs-title function_\">append\u003C\u002Fspan>(tile)\n  \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> tile\n}\n\n\u003Cspan class=\"hljs-keyword\">let\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">drag\u003C\u002Fspan>: { \u003Cspan class=\"hljs-attr\">from\u003C\u002Fspan>: number; \u003Cspan class=\"hljs-attr\">x\u003C\u002Fspan>: number; \u003Cspan class=\"hljs-attr\">y\u003C\u002Fspan>: number; tile?: \u003Cspan class=\"hljs-title class_\">HTMLElement\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">size\u003C\u002Fspan>: number } | \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">let\u003C\u002Fspan> dropped = \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">let\u003C\u002Fspan> swallowClick = \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">movable\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">sq: number\u003C\u002Fspan>) =&gt; (props.\u003Cspan class=\"hljs-property\">interactive\u003C\u002Fspan> || premoving.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) &amp;&amp; !!mover.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> &amp;&amp; \u003Cspan class=\"hljs-title function_\">ownPiece\u003C\u002Fspan>(sq, mover.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">let\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">unlisten\u003C\u002Fspan>: (\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">void\u003C\u002Fspan>)[] = []\n\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">down\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">sq: number, e: PointerEvent\u003C\u002Fspan>) {\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!\u003Cspan class=\"hljs-title function_\">movable\u003C\u002Fspan>(sq) || e.\u003Cspan class=\"hljs-property\">button\u003C\u002Fspan> !== \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> size = board.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>!.\u003Cspan class=\"hljs-property\">querySelector\u003C\u002Fspan>&lt;\u003Cspan class=\"hljs-title class_\">HTMLElement\u003C\u002Fspan>&gt;(\u003Cspan class=\"hljs-string\">`[data-sq=&quot;\u003Cspan class=\"hljs-subst\">${sq}\u003C\u002Fspan>&quot;]`\u003C\u002Fspan>)!.\u003Cspan class=\"hljs-title function_\">getBoundingClientRect\u003C\u002Fspan>().\u003Cspan class=\"hljs-property\">width\u003C\u002Fspan>\n  drag = { \u003Cspan class=\"hljs-attr\">from\u003C\u002Fspan>: sq, \u003Cspan class=\"hljs-attr\">x\u003C\u002Fspan>: e.\u003Cspan class=\"hljs-property\">clientX\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">y\u003C\u002Fspan>: e.\u003Cspan class=\"hljs-property\">clientY\u003C\u002Fspan>, size }\n  unlisten = [\u003Cspan class=\"hljs-title function_\">useEventListener\u003C\u002Fspan>(\u003Cspan class=\"hljs-variable language_\">window\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;pointermove&#x27;\u003C\u002Fspan>, moveDrag), \u003Cspan class=\"hljs-title function_\">useEventListener\u003C\u002Fspan>(\u003Cspan class=\"hljs-variable language_\">window\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;pointerup&#x27;\u003C\u002Fspan>, endDrag), \u003Cspan class=\"hljs-title function_\">useEventListener\u003C\u002Fspan>(\u003Cspan class=\"hljs-variable language_\">window\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;pointercancel&#x27;\u003C\u002Fspan>, cleanup)]\n}\n\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">place\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">tile: HTMLElement, x: number, y: number, size: number\u003C\u002Fspan>) {\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> o = board.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>!.\u003Cspan class=\"hljs-title function_\">getBoundingClientRect\u003C\u002Fspan>()\n  tile.\u003Cspan class=\"hljs-property\">style\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">left\u003C\u002Fspan> = \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${x - o.left - size \u002F \u003Cspan class=\"hljs-number\">2\u003C\u002Fspan>}\u003C\u002Fspan>px`\u003C\u002Fspan>\n  tile.\u003Cspan class=\"hljs-property\">style\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">top\u003C\u002Fspan> = \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${y - o.top - size \u002F \u003Cspan class=\"hljs-number\">2\u003C\u002Fspan>}\u003C\u002Fspan>px`\u003C\u002Fspan>\n}\n\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">moveDrag\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">e: PointerEvent\u003C\u002Fspan>) {\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!drag) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!drag.\u003Cspan class=\"hljs-property\">tile\u003C\u002Fspan>) {\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (\u003Cspan class=\"hljs-title class_\">Math\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">hypot\u003C\u002Fspan>(e.\u003Cspan class=\"hljs-property\">clientX\u003C\u002Fspan> - drag.\u003Cspan class=\"hljs-property\">x\u003C\u002Fspan>, e.\u003Cspan class=\"hljs-property\">clientY\u003C\u002Fspan> - drag.\u003Cspan class=\"hljs-property\">y\u003C\u002Fspan>) &lt; \u003Cspan class=\"hljs-number\">5\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n    selected.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = drag.\u003Cspan class=\"hljs-property\">from\u003C\u002Fspan>\n    hidden.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-keyword\">new\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Set\u003C\u002Fspan>([drag.\u003Cspan class=\"hljs-property\">from\u003C\u002Fspan>])\n    drag.\u003Cspan class=\"hljs-property\">tile\u003C\u002Fspan> = \u003Cspan class=\"hljs-title function_\">makeTile\u003C\u002Fspan>(props.\u003Cspan class=\"hljs-property\">squares\u003C\u002Fspan>[drag.\u003Cspan class=\"hljs-property\">from\u003C\u002Fspan>]!, drag.\u003Cspan class=\"hljs-property\">size\u003C\u002Fspan>)\n    drag.\u003Cspan class=\"hljs-property\">tile\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">classList\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">add\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;is-dragging&#x27;\u003C\u002Fspan>)\n  }\n  \u003Cspan class=\"hljs-title function_\">place\u003C\u002Fspan>(drag.\u003Cspan class=\"hljs-property\">tile\u003C\u002Fspan>, e.\u003Cspan class=\"hljs-property\">clientX\u003C\u002Fspan>, e.\u003Cspan class=\"hljs-property\">clientY\u003C\u002Fspan>, drag.\u003Cspan class=\"hljs-property\">size\u003C\u002Fspan>)\n}\n\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">cleanup\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">\u003C\u002Fspan>) {\n  unlisten.\u003Cspan class=\"hljs-title function_\">forEach\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">u\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">u\u003C\u002Fspan>())\n  drag?.\u003Cspan class=\"hljs-property\">tile\u003C\u002Fspan>?.\u003Cspan class=\"hljs-title function_\">remove\u003C\u002Fspan>()\n  hidden.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-keyword\">new\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Set\u003C\u002Fspan>()\n  drag = \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>\n}\n\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">endDrag\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">e: PointerEvent\u003C\u002Fspan>) {\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!drag?.\u003Cspan class=\"hljs-property\">tile\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">cleanup\u003C\u002Fspan>()\n  swallowClick = \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> target = \u003Cspan class=\"hljs-variable language_\">document\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">elementFromPoint\u003C\u002Fspan>(e.\u003Cspan class=\"hljs-property\">clientX\u003C\u002Fspan>, e.\u003Cspan class=\"hljs-property\">clientY\u003C\u002Fspan>)?.\u003Cspan class=\"hljs-property\">closest\u003C\u002Fspan>&lt;\u003Cspan class=\"hljs-title class_\">HTMLElement\u003C\u002Fspan>&gt;(\u003Cspan class=\"hljs-string\">&#x27;[data-sq]&#x27;\u003C\u002Fspan>)\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> to = target ? \u003Cspan class=\"hljs-title class_\">Number\u003C\u002Fspan>(target.\u003Cspan class=\"hljs-property\">dataset\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">sq\u003C\u002Fspan>) : \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan> = drag.\u003Cspan class=\"hljs-property\">from\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-title function_\">cleanup\u003C\u002Fspan>()\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (premoving.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) { selected.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>; \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (to !== \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan> &amp;&amp; to !== \u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan>) \u003Cspan class=\"hljs-title function_\">emit\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;premove&#x27;\u003C\u002Fspan>, { \u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan>, to }); \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> }\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (to !== \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan> &amp;&amp; legal.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">has\u003C\u002Fspan>(to)) { dropped = \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>; \u003Cspan class=\"hljs-title function_\">pick\u003C\u002Fspan>(to) } \u003Cspan class=\"hljs-keyword\">else\u003C\u002Fspan> selected.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>\n}\n\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">clicked\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">sq: number\u003C\u002Fspan>) {\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (swallowClick) { swallowClick = \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>; \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> }\n  focus.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = sq\n  \u003Cspan class=\"hljs-title function_\">pick\u003C\u002Fspan>(sq)\n}\n\u003Cspan class=\"hljs-title function_\">onBeforeUnmount\u003C\u002Fspan>(cleanup)\n\n\u003Cspan class=\"hljs-keyword\">async\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">animate\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">ply: Ply\u003C\u002Fspan>) {\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (dropped) { dropped = \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>; \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> }\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (\u003Cspan class=\"hljs-title function_\">useReducedMotion\u003C\u002Fspan>() || !board.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">paths\u003C\u002Fspan>: [number, number][] = ply.\u003Cspan class=\"hljs-property\">castle\u003C\u002Fspan>\n    ? [[ply.\u003Cspan class=\"hljs-property\">move\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">from\u003C\u002Fspan>, ply.\u003Cspan class=\"hljs-property\">castle\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">kingTo\u003C\u002Fspan>], [ply.\u003Cspan class=\"hljs-property\">castle\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">rookFrom\u003C\u002Fspan>, ply.\u003Cspan class=\"hljs-property\">castle\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">rookTo\u003C\u002Fspan>]]\n    : [[ply.\u003Cspan class=\"hljs-property\">move\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">from\u003C\u002Fspan>, ply.\u003Cspan class=\"hljs-property\">move\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">to\u003C\u002Fspan>]]\n  hidden.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-keyword\">new\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Set\u003C\u002Fspan>(paths.\u003Cspan class=\"hljs-title function_\">map\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">[, to]\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> to))\n  \u003Cspan class=\"hljs-keyword\">await\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">nextTick\u003C\u002Fspan>()\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">rect\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">sq: number\u003C\u002Fspan>) =&gt; board.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>!.\u003Cspan class=\"hljs-property\">querySelector\u003C\u002Fspan>&lt;\u003Cspan class=\"hljs-title class_\">HTMLElement\u003C\u002Fspan>&gt;(\u003Cspan class=\"hljs-string\">`[data-sq=&quot;\u003Cspan class=\"hljs-subst\">${sq}\u003C\u002Fspan>&quot;]`\u003C\u002Fspan>)!.\u003Cspan class=\"hljs-title function_\">getBoundingClientRect\u003C\u002Fspan>()\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> origin = board.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">getBoundingClientRect\u003C\u002Fspan>()\n  \u003Cspan class=\"hljs-keyword\">await\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Promise\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">all\u003C\u002Fspan>(paths.\u003Cspan class=\"hljs-title function_\">map\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">[\u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan>, to]\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> {\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> a = \u003Cspan class=\"hljs-title function_\">rect\u003C\u002Fspan>(\u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan>), b = \u003Cspan class=\"hljs-title function_\">rect\u003C\u002Fspan>(to)\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> tile = \u003Cspan class=\"hljs-title function_\">makeTile\u003C\u002Fspan>(props.\u003Cspan class=\"hljs-property\">squares\u003C\u002Fspan>[to]!, a.\u003Cspan class=\"hljs-property\">width\u003C\u002Fspan>)\n    \u003Cspan class=\"hljs-title class_\">Object\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">assign\u003C\u002Fspan>(tile.\u003Cspan class=\"hljs-property\">style\u003C\u002Fspan>, { \u003Cspan class=\"hljs-attr\">left\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${a.left - origin.left}\u003C\u002Fspan>px`\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">top\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${a.top - origin.top}\u003C\u002Fspan>px`\u003C\u002Fspan> })\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> dx = b.\u003Cspan class=\"hljs-property\">left\u003C\u002Fspan> - a.\u003Cspan class=\"hljs-property\">left\u003C\u002Fspan>, dy = b.\u003Cspan class=\"hljs-property\">top\u003C\u002Fspan> - a.\u003Cspan class=\"hljs-property\">top\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> tile.\u003Cspan class=\"hljs-title function_\">animate\u003C\u002Fspan>(\n      [{ \u003Cspan class=\"hljs-attr\">transform\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;translate(0, 0)&#x27;\u003C\u002Fspan> }, { \u003Cspan class=\"hljs-attr\">transform\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">`translate(\u003Cspan class=\"hljs-subst\">${dx}\u003C\u002Fspan>px, \u003Cspan class=\"hljs-subst\">${dy}\u003C\u002Fspan>px)`\u003C\u002Fspan> }],\n      { \u003Cspan class=\"hljs-attr\">duration\u003C\u002Fspan>: \u003Cspan class=\"hljs-number\">240\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">easing\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;cubic-bezier(.2, .7, .1, 1)&#x27;\u003C\u002Fspan> },\n    ).\u003Cspan class=\"hljs-property\">finished\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">finally\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> tile.\u003Cspan class=\"hljs-title function_\">remove\u003C\u002Fspan>())\n  }))\n  hidden.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-keyword\">new\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Set\u003C\u002Fspan>()\n}\n\u003Cspan class=\"hljs-title function_\">watch\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> props.\u003Cspan class=\"hljs-property\">last\u003C\u002Fspan>, \u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">ply, prev\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> { \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (ply &amp;&amp; ply !== prev &amp;&amp; props.\u003Cspan class=\"hljs-property\">plyCount\u003C\u002Fspan> &gt; \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">void\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">animate\u003C\u002Fspan>(ply) })\n\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">script\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n\n\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">ref\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;board&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;board__grid&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;{ &#x27;board__grid--plain&#x27;: PLAIN_FONTS.has(font) }&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">role\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;grid&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">aria-label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;Chess board&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:style\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;{ fontFamily: family, ...themeVars }&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">keydown\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;key&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">button\u003C\u002Fspan>\n      \u003Cspan class=\"hljs-attr\">v-for\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;sq in order&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:key\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;sq&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">type\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;button&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;board__sq&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:data-sq\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;sq&quot;\u003C\u002Fspan>\n      \u003Cspan class=\"hljs-attr\">:class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;{\n        &#x27;is-dark&#x27;: isDarkSquare(sq),\n        &#x27;is-selected&#x27;: sq === selected,\n        &#x27;is-target&#x27;: legal.has(sq),\n        &#x27;is-capture&#x27;: legal.has(sq) &amp;&amp; !!squares[sq],\n        &#x27;is-last&#x27;: last &amp;&amp; (sq === last.move.from || sq === (last.castle?.kingTo ?? last.move.to)),\n        &#x27;is-check&#x27;: sq === check,\n        &#x27;is-movable&#x27;: movable(sq),\n        &#x27;is-premove&#x27;: premove &amp;&amp; (sq === premove.from || sq === premove.to),\n      }&quot;\u003C\u002Fspan>\n      \u003Cspan class=\"hljs-attr\">:tabindex\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;sq === focus ? 0 : -1&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:aria-label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;label(sq)&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:aria-disabled\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;!interactive&quot;\u003C\u002Fspan>\n      @\u003Cspan class=\"hljs-attr\">click\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;clicked(sq)&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">pointerdown\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;down(sq, $event)&quot;\u003C\u002Fspan>\n    &gt;\u003C\u002Fspan>{{ squareGlyph(hidden.has(sq) ? &#x27;&#x27; : squares[sq]!, isDarkSquare(sq), font) }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">button\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">svg\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;arrowLines.length&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;board__arrows&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">viewBox\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;0 0 8 8&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">aria-hidden\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;true&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n      \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">defs\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">marker\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">id\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;board-arrow&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">viewBox\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;0 0 4 4&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">refX\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;1&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">refY\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;2&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">markerUnits\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;userSpaceOnUse&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">markerWidth\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;0.42&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">markerHeight\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;0.42&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">orient\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;auto&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">path\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">d\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;M0,0 L4,2 L0,4 z&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">fill\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;context-stroke&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">marker\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">defs\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n      \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">line\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-for\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;a in arrowLines&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:key\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;a.key&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:x1\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;a.x1&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:y1\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;a.y1&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:x2\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;a.x2&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:y2\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;a.y2&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:stroke-width\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;a.w&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:opacity\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;a.o&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">marker-end\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;url(#board-arrow)&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">svg\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;promoting&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;board__promote&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">role\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;dialog&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">aria-label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;Promote to&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n      \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">button\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-for\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;r in ([&#x27;queen&#x27;, &#x27;rook&#x27;, &#x27;bishop&#x27;, &#x27;knight&#x27;] as Role[])&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:key\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;r&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">type\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;button&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:aria-label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;`Promote to ${r}`&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">click\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;promote(r)&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n        {{ squareGlyph(({ queen: &#x27;Q&#x27;, rook: &#x27;R&#x27;, bishop: &#x27;B&#x27;, knight: &#x27;N&#x27; } as Record&lt;string, string&gt;)[r]![whiteToMove ? &#x27;toUpperCase&#x27; : &#x27;toLowerCase&#x27;](), false, font) }}\n      \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">button\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan>&gt;\u003C\u002Fspan>",{"path":221,"lines":222,"code":223,"html":224},"app\u002Fcomposables\u002FuseChessGame.ts",231,"import type { Chess } from 'chessops\u002Fchess'\nimport type { NormalMove, Role } from 'chessops\u002Ftypes'\nimport { simpleMove, startFen, startSquares } from '@cw\u002Fchess\u002Frules'\n\n\u002F\u002F chessops is imported on mount, so it ships in its own chunk that link prefetch never fetches.\ntype Ops = {\n  Chess: typeof import('chessops\u002Fchess').Chess\n  castlingSide: typeof import('chessops\u002Fchess').castlingSide\n  parseFen: typeof import('chessops\u002Ffen').parseFen\n  makeFen: typeof import('chessops\u002Ffen').makeFen\n  makeSanAndPlay: typeof import('chessops\u002Fsan').makeSanAndPlay\n  makeSan: typeof import('chessops\u002Fsan').makeSan\n  pgn: typeof import('chessops\u002Fpgn')\n  kingCastlesTo: typeof import('chessops\u002Futil').kingCastlesTo\n  parseUci: typeof import('chessops\u002Futil').parseUci\n  makeUci: typeof import('chessops\u002Futil').makeUci\n}\nexport type Player = 'human' | 'simple' | 'jev'\nexport type EngineDecision = {\n  engine: Exclude\u003CPlayer, 'human'>\n  san: string\n  ms: number\n  candidates?: { uci?: string; san: string; p: number }[]\n  confidence?: number\n  model?: string\n  options?: number\n  note?: string\n  \u002F** Played without asking Jev: the only legal move, the only safe one, or a mate the rules found. *\u002F\n  forced?: 'legal' | 'safe' | 'mate'\n  \u002F** How many of the legal moves Jev was offered: at normal and hard, only those that lose nothing. *\u002F\n  offered?: number\n  \u002F** Rate-limited and nothing played: seconds to wait. *\u002F\n  resting?: number\n  \u002F** eval: White's winning chances 0–1. *\u002F\n  reading?: { eval?: number; kingRisk?: number; sharpness?: number; plan?: string }\n}\nexport type Ply = { move: NormalMove; san: string; before: Chess; castle?: { kingTo: number; rookFrom: number; rookTo: number } }\nexport type Outcome = { winner?: 'white' | 'black'; reason: string }\n\nconst LETTER: Record\u003CRole, string> = { pawn: 'p', knight: 'n', bishop: 'b', rook: 'r', queen: 'q', king: 'k' }\n\nexport function useChessGame(rank: Ref\u003Cstring>) {\n  let ops: Ops | null = null\n  const pos = shallowRef\u003CChess | null>(null)\n  const plies = shallowRef\u003CPly[]>([])\n  const ready = computed(() => pos.value !== null)\n\n  async function load() {\n    const [chess, fen, san, pgn, util] = await Promise.all([\n      import('chessops\u002Fchess'), import('chessops\u002Ffen'), import('chessops\u002Fsan'), import('chessops\u002Fpgn'), import('chessops\u002Futil'),\n    ])\n    ops = { Chess: chess.Chess, castlingSide: chess.castlingSide, parseFen: fen.parseFen, makeFen: fen.makeFen, makeSanAndPlay: san.makeSanAndPlay, makeSan: san.makeSan, pgn, kingCastlesTo: util.kingCastlesTo, parseUci: util.parseUci, makeUci: util.makeUci }\n    reset()\n  }\n  function reset() {\n    if (!ops) return\n    pos.value = ops.Chess.fromSetup(ops.parseFen(startFen(rank.value)).unwrap()).unwrap()\n    plies.value = []\n  }\n  watch(rank, reset)\n\n  \u002F\u002F a1 = 0\n  const squaresOf = (p: Chess) => Array.from({ length: 64 }, (_, sq) => {\n    const piece = p.board.get(sq)\n    if (!piece) return ''\n    const letter = LETTER[piece.role]\n    return piece.color === 'white' ? letter.toUpperCase() : letter\n  })\n  const checkOf = (p: Chess) => (p.isCheck() ? p.board.kingOf(p.turn) : undefined)\n  const squares = computed\u003Cstring[]>(() => (pos.value ? squaresOf(pos.value) : startSquares(rank.value)))\n  const turn = computed(() => pos.value?.turn ?? 'white')\n  const check = computed(() => (pos.value ? checkOf(pos.value) : undefined))\n  \u002F\u002F promotions are to a queen, as on the board\n  const legal = computed(() => {\n    const p = pos.value\n    if (!p || !ops) return []\n    return [...p.allDests()].flatMap(([from, tos]) => [...tos].map((to) => {\n      const m: NormalMove = { from, to, ...(p.board.get(from)?.role === 'pawn' && (to >> 3 === 0 || to >> 3 === 7) ? { promotion: 'queen' as const } : {}) }\n      return { uci: ops!.makeUci(m), san: ops!.makeSan(p, m), move: m }\n    }))\n  })\n  const positionAt = (k: number) => (k >= plies.value.length ? pos.value : plies.value[k]!.before)\n  const squaresAt = (k: number) => { const p = positionAt(k); return p ? squaresOf(p) : startSquares(rank.value) }\n  const checkAt = (k: number) => { const p = positionAt(k); return p ? checkOf(p) : undefined }\n  const sanAt = (k: number, uci: string) => { const p = positionAt(k), m = ops?.parseUci(uci); return p && ops && m ? ops.makeSan(p, m) : uci }\n  const fenAt = (k: number) => { const p = positionAt(k); return p && ops ? ops.makeFen(p.toSetup()) : startFen(rank.value) }\n\n  \u002F\u002F chessops castles king onto rook; the king's final square is accepted too, since that is what people click\n  function targets(from: number): Map\u003Cnumber, NormalMove> {\n    const p = pos.value, out = new Map\u003Cnumber, NormalMove>()\n    if (!p || !ops) return out\n    for (const to of p.dests(from)) {\n      const move = { from, to }\n      out.set(to, move)\n      const side = ops.castlingSide(p, move)\n      if (side) {\n        const kingTo = ops.kingCastlesTo(p.turn, side)\n        if (!out.has(kingTo) && !p.dests(from).has(kingTo)) out.set(kingTo, move)\n      }\n    }\n    return out\n  }\n  const needsPromotion = (move: NormalMove) => {\n    const p = pos.value\n    return !!p && p.board.get(move.from)?.role === 'pawn' && (move.to >> 3 === 7 || move.to >> 3 === 0)\n  }\n\n  function play(move: NormalMove): Ply | undefined {\n    const p = pos.value\n    if (!p || !ops || !p.isLegal(move)) return\n    const before = p.clone()\n    const side = ops.castlingSide(p, move)\n    const back = p.turn === 'white' ? 0 : 56\n    const castle = side ? { kingTo: back + (side === 'h' ? 6 : 2), rookFrom: move.to, rookTo: back + (side === 'h' ? 5 : 3) } : undefined\n    const next = p.clone()\n    const san = ops.makeSanAndPlay(next, move)\n    const ply: Ply = { move, san, before, castle }\n    pos.value = next\n    plies.value = [...plies.value, ply]\n    return ply\n  }\n  const moves = computed(() => {\n    const plies_ = plies.value \u002F\u002F read first, so it tracks the game before chessops loads\n    return ops ? plies_.map((p) => ops!.makeUci(p.move)) : []\n  })\n  function replay(ucis: string[]) {\n    if (!ops) return\n    reset()\n    for (const uci of ucis) {\n      const m = ops.parseUci(uci) as NormalMove | undefined\n      if (!m || !play(m)) break\n    }\n  }\n  function undo() {\n    const last = plies.value.at(-1)\n    if (!last) return\n    pos.value = last.before\n    plies.value = plies.value.slice(0, -1)\n  }\n\n  const outcome = computed\u003COutcome | undefined>(() => {\n    const p = pos.value\n    if (!p) return\n    if (p.isCheckmate()) return { winner: p.turn === 'white' ? 'black' : 'white', reason: 'Checkmate' }\n    if (p.isStalemate()) return { reason: 'Stalemate' }\n    if (p.isInsufficientMaterial()) return { reason: 'Insufficient material' }\n    if (p.halfmoves >= 100) return { reason: 'Fifty-move rule' }\n    \u002F\u002F chessops leaves move history to the caller, so threefold repetition is counted here\n    if (ops) {\n      const key = (x: Chess) => ops!.makeFen(x.toSetup()).split(' ').slice(0, 4).join(' ')\n      const now = key(p)\n      if (plies.value.filter((ply) => key(ply.before) === now).length >= 2) return { reason: 'Threefold repetition' }\n    }\n    return\n  })\n\n  const fen = computed(() => (pos.value && ops ? ops.makeFen(pos.value.toSetup()) : startFen(rank.value)))\n  function pgnText(notes: { marks?: string[]; comments?: Record\u003Cnumber, string>; tags?: Record\u003Cstring, string> } = {}) {\n    \u002F\u002F read first, so a computed calling this tracks the game while chessops loads\n    const plies_ = plies.value, o = outcome.value\n    if (!pos.value || !ops) return ''\n    const { pgn } = ops\n    const game = pgn.defaultGame\u003Cimport('chessops\u002Fpgn').PgnNodeData>(pgn.emptyHeaders)\n    \u002F\u002F the page's tags first, in the order of PGN's own roster\n    for (const [k, v] of Object.entries(notes.tags ?? {})) game.headers.set(k, v)\n    \u002F\u002F chessops drops the Variant header for standard rules, so a Chess960 game sets it after the start position\n    pgn.setStartingPosition(game.headers, ops.Chess.fromSetup(ops.parseFen(startFen(rank.value)).unwrap()).unwrap())\n    if (rank.value !== 'RNBQKBNR') game.headers.set('Variant', 'Chess960')\n    game.headers.set('Result', pgn.makeOutcome(o ? { winner: o.winner } : undefined))\n    let node: import('chessops\u002Fpgn').Node\u003Cimport('chessops\u002Fpgn').PgnNodeData> = game.moves\n    plies_.forEach((ply, i) => {\n      const comment = notes.comments?.[i]\n      const child = new pgn.ChildNode({ san: ply.san + (notes.marks?.[i] ?? ''), comments: comment ? [comment] : undefined })\n      node.children.push(child)\n      node = child\n    })\n    \u002F\u002F one move number per line: PGN allows a line break between any two tokens, so it still copies as valid PGN\n    const [tags, movetext = ''] = pgn.makePgn(game).trim().split(\u002F\\n\\n\u002F)\n    const lines = movetext.replace(\u002F\\s+\u002Fg, ' ').trim().replace(\u002F (?=\\d+\\. )\u002Fg, '\\n').replace(\u002F (1-0|0-1|1\\\u002F2-1\\\u002F2|\\*)$\u002F, '\\n$1')\n    return lines ? `${tags}\\n\\n${lines}` : tags!\n  }\n\n  function computerMove(): NormalMove | undefined {\n    const p = pos.value\n    return p && !outcome.value ? simpleMove(p) : undefined\n  }\n\n  \u002F\u002F A late answer (the position changed meanwhile) is never played.\n  async function engineMove(engine: Exclude\u003CPlayer, 'human'>, minMs = 0, level: 'easy' | 'normal' | 'hard' = 'hard', onDecided?: (d: EngineDecision) => void, fallback = true): Promise\u003CEngineDecision | undefined> {\n    const p = pos.value\n    if (!p || !ops || outcome.value) return\n    const at = plies.value.length, t0 = performance.now()\n    const local = (note?: string): { move?: NormalMove; decision: EngineDecision } => {\n      const move = computerMove()\n      return { move, decision: { engine: 'simple', san: '', ms: Math.round(performance.now() - t0), note } }\n    }\n    let move: NormalMove | undefined, decision: EngineDecision\n    if (engine === 'jev') {\n      try {\n        const r = await $fetch\u003C{ uci: string; san: string; candidates: { uci: string; san: string; p: number }[]; confidence?: number; model?: string; ms: number; options: number; offered?: number; forced?: EngineDecision['forced']; reading: EngineDecision['reading'] }>('\u002Fapi\u002Fchess\u002Fjev', {\n          method: 'POST',\n          body: { start: startFen(rank.value), moves: moves.value, history: plies.value.map((x) => x.san), variant: rank.value === 'RNBQKBNR' ? 'chess' : 'chess960', level },\n        })\n        const m = ops.parseUci(r.uci) as NormalMove | undefined\n        if (!m || !pos.value?.isLegal(m)) throw new Error('illegal')\n        move = m\n        decision = { engine: 'jev', san: r.san, ms: r.ms, candidates: r.candidates, confidence: r.confidence, model: r.model, options: r.options, forced: r.forced, offered: r.offered, reading: r.reading }\n      } catch (e) {\n        const err = e as { statusCode?: number; response?: Response }\n        const status = err.statusCode\n        \u002F\u002F watching, a stand-in would change the match\n        if (!fallback && status === 429) return { engine: 'jev', san: '', ms: 0, resting: Number(err.response?.headers.get('retry-after')) || 30 }\n        ;({ move, decision } = local(status === 429 ? 'Jev is resting (too many moves, or today\\'s budget is spent); the simple engine played.' : 'Jev did not answer; the simple engine played.'))\n      }\n    } else ({ move, decision } = local())\n    \u002F\u002F a minimum time per move, so a fast engine can still be watched\n    if (plies.value.length === at && pos.value === p) onDecided?.(decision)\n    const wait = minMs - (performance.now() - t0)\n    if (wait > 0) await new Promise((r) => setTimeout(r, wait))\n    if (!move || plies.value.length !== at || pos.value !== p) return\n    const ply = play(move)\n    return ply ? { ...decision, san: ply.san } : undefined\n  }\n\n  async function predictReply(): Promise\u003C{ san: string; p: number } | undefined> {\n    if (!pos.value || outcome.value) return\n    return $fetch\u003C{ san: string; p: number }>('\u002Fapi\u002Fchess\u002Fjev-predict', { method: 'POST', body: { fen: fen.value } }).catch(() => undefined)\n  }\n\n  return { position: pos, load, ready, legal, squares, squaresAt, checkAt, sanAt, fenAt, turn, check, targets, needsPromotion, play, undo, reset, plies, moves, replay, outcome, fen, pgnText, engineMove, predictReply }\n}","\u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">type\u003C\u002Fspan> { \u003Cspan class=\"hljs-title class_\">Chess\u003C\u002Fspan> } \u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;chessops\u002Fchess&#x27;\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">type\u003C\u002Fspan> { \u003Cspan class=\"hljs-title class_\">NormalMove\u003C\u002Fspan>, \u003Cspan class=\"hljs-title class_\">Role\u003C\u002Fspan> } \u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;chessops\u002Ftypes&#x27;\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan> { simpleMove, startFen, startSquares } \u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;@cw\u002Fchess\u002Frules&#x27;\u003C\u002Fspan>\n\n\u003Cspan class=\"hljs-comment\">\u002F\u002F chessops is imported on mount, so it ships in its own chunk that link prefetch never fetches.\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">type\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Ops\u003C\u002Fspan> = {\n  \u003Cspan class=\"hljs-title class_\">Chess\u003C\u002Fspan>: \u003Cspan class=\"hljs-keyword\">typeof\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;chessops\u002Fchess&#x27;\u003C\u002Fspan>).\u003Cspan class=\"hljs-property\">Chess\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-attr\">castlingSide\u003C\u002Fspan>: \u003Cspan class=\"hljs-keyword\">typeof\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;chessops\u002Fchess&#x27;\u003C\u002Fspan>).\u003Cspan class=\"hljs-property\">castlingSide\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-attr\">parseFen\u003C\u002Fspan>: \u003Cspan class=\"hljs-keyword\">typeof\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;chessops\u002Ffen&#x27;\u003C\u002Fspan>).\u003Cspan class=\"hljs-property\">parseFen\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-attr\">makeFen\u003C\u002Fspan>: \u003Cspan class=\"hljs-keyword\">typeof\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;chessops\u002Ffen&#x27;\u003C\u002Fspan>).\u003Cspan class=\"hljs-property\">makeFen\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-attr\">makeSanAndPlay\u003C\u002Fspan>: \u003Cspan class=\"hljs-keyword\">typeof\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;chessops\u002Fsan&#x27;\u003C\u002Fspan>).\u003Cspan class=\"hljs-property\">makeSanAndPlay\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-attr\">makeSan\u003C\u002Fspan>: \u003Cspan class=\"hljs-keyword\">typeof\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;chessops\u002Fsan&#x27;\u003C\u002Fspan>).\u003Cspan class=\"hljs-property\">makeSan\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-attr\">pgn\u003C\u002Fspan>: \u003Cspan class=\"hljs-keyword\">typeof\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;chessops\u002Fpgn&#x27;\u003C\u002Fspan>)\n  \u003Cspan class=\"hljs-attr\">kingCastlesTo\u003C\u002Fspan>: \u003Cspan class=\"hljs-keyword\">typeof\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;chessops\u002Futil&#x27;\u003C\u002Fspan>).\u003Cspan class=\"hljs-property\">kingCastlesTo\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-attr\">parseUci\u003C\u002Fspan>: \u003Cspan class=\"hljs-keyword\">typeof\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;chessops\u002Futil&#x27;\u003C\u002Fspan>).\u003Cspan class=\"hljs-property\">parseUci\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-attr\">makeUci\u003C\u002Fspan>: \u003Cspan class=\"hljs-keyword\">typeof\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;chessops\u002Futil&#x27;\u003C\u002Fspan>).\u003Cspan class=\"hljs-property\">makeUci\u003C\u002Fspan>\n}\n\u003Cspan class=\"hljs-keyword\">export\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">type\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Player\u003C\u002Fspan> = \u003Cspan class=\"hljs-string\">&#x27;human&#x27;\u003C\u002Fspan> | \u003Cspan class=\"hljs-string\">&#x27;simple&#x27;\u003C\u002Fspan> | \u003Cspan class=\"hljs-string\">&#x27;jev&#x27;\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">export\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">type\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">EngineDecision\u003C\u002Fspan> = {\n  \u003Cspan class=\"hljs-attr\">engine\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">Exclude\u003C\u002Fspan>&lt;\u003Cspan class=\"hljs-title class_\">Player\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;human&#x27;\u003C\u002Fspan>&gt;\n  \u003Cspan class=\"hljs-attr\">san\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">string\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-attr\">ms\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-attr\">candidates\u003C\u002Fspan>?: { \u003Cspan class=\"hljs-attr\">uci\u003C\u002Fspan>?: \u003Cspan class=\"hljs-built_in\">string\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">san\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">string\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">p\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan> }[]\n  \u003Cspan class=\"hljs-attr\">confidence\u003C\u002Fspan>?: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-attr\">model\u003C\u002Fspan>?: \u003Cspan class=\"hljs-built_in\">string\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-attr\">options\u003C\u002Fspan>?: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-attr\">note\u003C\u002Fspan>?: \u003Cspan class=\"hljs-built_in\">string\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-comment\">\u002F** Played without asking Jev: the only legal move, the only safe one, or a mate the rules found. *\u002F\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-attr\">forced\u003C\u002Fspan>?: \u003Cspan class=\"hljs-string\">&#x27;legal&#x27;\u003C\u002Fspan> | \u003Cspan class=\"hljs-string\">&#x27;safe&#x27;\u003C\u002Fspan> | \u003Cspan class=\"hljs-string\">&#x27;mate&#x27;\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-comment\">\u002F** How many of the legal moves Jev was offered: at normal and hard, only those that lose nothing. *\u002F\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-attr\">offered\u003C\u002Fspan>?: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-comment\">\u002F** Rate-limited and nothing played: seconds to wait. *\u002F\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-attr\">resting\u003C\u002Fspan>?: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-comment\">\u002F** eval: White&#x27;s winning chances 0–1. *\u002F\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-attr\">reading\u003C\u002Fspan>?: { \u003Cspan class=\"hljs-attr\">eval\u003C\u002Fspan>?: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">kingRisk\u003C\u002Fspan>?: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">sharpness\u003C\u002Fspan>?: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">plan\u003C\u002Fspan>?: \u003Cspan class=\"hljs-built_in\">string\u003C\u002Fspan> }\n}\n\u003Cspan class=\"hljs-keyword\">export\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">type\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Ply\u003C\u002Fspan> = { \u003Cspan class=\"hljs-attr\">move\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">NormalMove\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">san\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">string\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">before\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">Chess\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">castle\u003C\u002Fspan>?: { \u003Cspan class=\"hljs-attr\">kingTo\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">rookFrom\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">rookTo\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan> } }\n\u003Cspan class=\"hljs-keyword\">export\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">type\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Outcome\u003C\u002Fspan> = { \u003Cspan class=\"hljs-attr\">winner\u003C\u002Fspan>?: \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan> | \u003Cspan class=\"hljs-string\">&#x27;black&#x27;\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">reason\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">string\u003C\u002Fspan> }\n\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">LETTER\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">Record\u003C\u002Fspan>&lt;\u003Cspan class=\"hljs-title class_\">Role\u003C\u002Fspan>, \u003Cspan class=\"hljs-built_in\">string\u003C\u002Fspan>&gt; = { \u003Cspan class=\"hljs-attr\">pawn\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;p&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">knight\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;n&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">bishop\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;b&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">rook\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;r&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">queen\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;q&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">king\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;k&#x27;\u003C\u002Fspan> }\n\n\u003Cspan class=\"hljs-keyword\">export\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">useChessGame\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">\u003Cspan class=\"hljs-attr\">rank\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">Ref\u003C\u002Fspan>&lt;\u003Cspan class=\"hljs-built_in\">string\u003C\u002Fspan>&gt;\u003C\u002Fspan>) {\n  \u003Cspan class=\"hljs-keyword\">let\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">ops\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">Ops\u003C\u002Fspan> | \u003Cspan class=\"hljs-literal\">null\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">null\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> pos = shallowRef&lt;\u003Cspan class=\"hljs-title class_\">Chess\u003C\u002Fspan> | \u003Cspan class=\"hljs-literal\">null\u003C\u002Fspan>&gt;(\u003Cspan class=\"hljs-literal\">null\u003C\u002Fspan>)\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> plies = shallowRef&lt;\u003Cspan class=\"hljs-title class_\">Ply\u003C\u002Fspan>[]&gt;([])\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> ready = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> pos.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> !== \u003Cspan class=\"hljs-literal\">null\u003C\u002Fspan>)\n\n  \u003Cspan class=\"hljs-keyword\">async\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">load\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">\u003C\u002Fspan>) {\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> [chess, fen, san, pgn, util] = \u003Cspan class=\"hljs-keyword\">await\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Promise\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">all\u003C\u002Fspan>([\n      \u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;chessops\u002Fchess&#x27;\u003C\u002Fspan>), \u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;chessops\u002Ffen&#x27;\u003C\u002Fspan>), \u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;chessops\u002Fsan&#x27;\u003C\u002Fspan>), \u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;chessops\u002Fpgn&#x27;\u003C\u002Fspan>), \u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;chessops\u002Futil&#x27;\u003C\u002Fspan>),\n    ])\n    ops = { \u003Cspan class=\"hljs-title class_\">Chess\u003C\u002Fspan>: chess.\u003Cspan class=\"hljs-property\">Chess\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">castlingSide\u003C\u002Fspan>: chess.\u003Cspan class=\"hljs-property\">castlingSide\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">parseFen\u003C\u002Fspan>: fen.\u003Cspan class=\"hljs-property\">parseFen\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">makeFen\u003C\u002Fspan>: fen.\u003Cspan class=\"hljs-property\">makeFen\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">makeSanAndPlay\u003C\u002Fspan>: san.\u003Cspan class=\"hljs-property\">makeSanAndPlay\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">makeSan\u003C\u002Fspan>: san.\u003Cspan class=\"hljs-property\">makeSan\u003C\u002Fspan>, pgn, \u003Cspan class=\"hljs-attr\">kingCastlesTo\u003C\u002Fspan>: util.\u003Cspan class=\"hljs-property\">kingCastlesTo\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">parseUci\u003C\u002Fspan>: util.\u003Cspan class=\"hljs-property\">parseUci\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">makeUci\u003C\u002Fspan>: util.\u003Cspan class=\"hljs-property\">makeUci\u003C\u002Fspan> }\n    \u003Cspan class=\"hljs-title function_\">reset\u003C\u002Fspan>()\n  }\n  \u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">reset\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">\u003C\u002Fspan>) {\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!ops) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n    pos.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = ops.\u003Cspan class=\"hljs-property\">Chess\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">fromSetup\u003C\u002Fspan>(ops.\u003Cspan class=\"hljs-title function_\">parseFen\u003C\u002Fspan>(\u003Cspan class=\"hljs-title function_\">startFen\u003C\u002Fspan>(rank.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>)).\u003Cspan class=\"hljs-title function_\">unwrap\u003C\u002Fspan>()).\u003Cspan class=\"hljs-title function_\">unwrap\u003C\u002Fspan>()\n    plies.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = []\n  }\n  \u003Cspan class=\"hljs-title function_\">watch\u003C\u002Fspan>(rank, reset)\n\n  \u003Cspan class=\"hljs-comment\">\u002F\u002F a1 = 0\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">squaresOf\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">\u003Cspan class=\"hljs-attr\">p\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">Chess\u003C\u002Fspan>\u003C\u002Fspan>) =&gt; \u003Cspan class=\"hljs-title class_\">Array\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">from\u003C\u002Fspan>({ \u003Cspan class=\"hljs-attr\">length\u003C\u002Fspan>: \u003Cspan class=\"hljs-number\">64\u003C\u002Fspan> }, \u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">_, sq\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> {\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> piece = p.\u003Cspan class=\"hljs-property\">board\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">get\u003C\u002Fspan>(sq)\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!piece) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> letter = \u003Cspan class=\"hljs-variable constant_\">LETTER\u003C\u002Fspan>[piece.\u003Cspan class=\"hljs-property\">role\u003C\u002Fspan>]\n    \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> piece.\u003Cspan class=\"hljs-property\">color\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan> ? letter.\u003Cspan class=\"hljs-title function_\">toUpperCase\u003C\u002Fspan>() : letter\n  })\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">checkOf\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">\u003Cspan class=\"hljs-attr\">p\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">Chess\u003C\u002Fspan>\u003C\u002Fspan>) =&gt; (p.\u003Cspan class=\"hljs-title function_\">isCheck\u003C\u002Fspan>() ? p.\u003Cspan class=\"hljs-property\">board\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">kingOf\u003C\u002Fspan>(p.\u003Cspan class=\"hljs-property\">turn\u003C\u002Fspan>) : \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>)\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> squares = computed&lt;\u003Cspan class=\"hljs-built_in\">string\u003C\u002Fspan>[]&gt;(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> (pos.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? \u003Cspan class=\"hljs-title function_\">squaresOf\u003C\u002Fspan>(pos.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) : \u003Cspan class=\"hljs-title function_\">startSquares\u003C\u002Fspan>(rank.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>)))\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> turn = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> pos.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>?.\u003Cspan class=\"hljs-property\">turn\u003C\u002Fspan> ?? \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan>)\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> check = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> (pos.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? \u003Cspan class=\"hljs-title function_\">checkOf\u003C\u002Fspan>(pos.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) : \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>))\n  \u003Cspan class=\"hljs-comment\">\u002F\u002F promotions are to a queen, as on the board\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> legal = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> {\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> p = pos.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!p || !ops) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> []\n    \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> [...p.\u003Cspan class=\"hljs-title function_\">allDests\u003C\u002Fspan>()].\u003Cspan class=\"hljs-title function_\">flatMap\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">[\u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan>, tos]\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> [...tos].\u003Cspan class=\"hljs-title function_\">map\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">to\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> {\n      \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">m\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">NormalMove\u003C\u002Fspan> = { \u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan>, to, ...(p.\u003Cspan class=\"hljs-property\">board\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">get\u003C\u002Fspan>(\u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan>)?.\u003Cspan class=\"hljs-property\">role\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;pawn&#x27;\u003C\u002Fspan> &amp;&amp; (to &gt;&gt; \u003Cspan class=\"hljs-number\">3\u003C\u002Fspan> === \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan> || to &gt;&gt; \u003Cspan class=\"hljs-number\">3\u003C\u002Fspan> === \u003Cspan class=\"hljs-number\">7\u003C\u002Fspan>) ? { \u003Cspan class=\"hljs-attr\">promotion\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;queen&#x27;\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">as\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> } : {}) }\n      \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> { \u003Cspan class=\"hljs-attr\">uci\u003C\u002Fspan>: ops!.\u003Cspan class=\"hljs-title function_\">makeUci\u003C\u002Fspan>(m), \u003Cspan class=\"hljs-attr\">san\u003C\u002Fspan>: ops!.\u003Cspan class=\"hljs-title function_\">makeSan\u003C\u002Fspan>(p, m), \u003Cspan class=\"hljs-attr\">move\u003C\u002Fspan>: m }\n    }))\n  })\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">positionAt\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">\u003Cspan class=\"hljs-attr\">k\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan>\u003C\u002Fspan>) =&gt; (k &gt;= plies.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> ? pos.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> : plies.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>[k]!.\u003Cspan class=\"hljs-property\">before\u003C\u002Fspan>)\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">squaresAt\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">\u003Cspan class=\"hljs-attr\">k\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan>\u003C\u002Fspan>) =&gt; { \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> p = \u003Cspan class=\"hljs-title function_\">positionAt\u003C\u002Fspan>(k); \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> p ? \u003Cspan class=\"hljs-title function_\">squaresOf\u003C\u002Fspan>(p) : \u003Cspan class=\"hljs-title function_\">startSquares\u003C\u002Fspan>(rank.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) }\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">checkAt\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">\u003Cspan class=\"hljs-attr\">k\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan>\u003C\u002Fspan>) =&gt; { \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> p = \u003Cspan class=\"hljs-title function_\">positionAt\u003C\u002Fspan>(k); \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> p ? \u003Cspan class=\"hljs-title function_\">checkOf\u003C\u002Fspan>(p) : \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan> }\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">sanAt\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">\u003Cspan class=\"hljs-attr\">k\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">uci\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">string\u003C\u002Fspan>\u003C\u002Fspan>) =&gt; { \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> p = \u003Cspan class=\"hljs-title function_\">positionAt\u003C\u002Fspan>(k), m = ops?.\u003Cspan class=\"hljs-title function_\">parseUci\u003C\u002Fspan>(uci); \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> p &amp;&amp; ops &amp;&amp; m ? ops.\u003Cspan class=\"hljs-title function_\">makeSan\u003C\u002Fspan>(p, m) : uci }\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">fenAt\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">\u003Cspan class=\"hljs-attr\">k\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan>\u003C\u002Fspan>) =&gt; { \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> p = \u003Cspan class=\"hljs-title function_\">positionAt\u003C\u002Fspan>(k); \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> p &amp;&amp; ops ? ops.\u003Cspan class=\"hljs-title function_\">makeFen\u003C\u002Fspan>(p.\u003Cspan class=\"hljs-title function_\">toSetup\u003C\u002Fspan>()) : \u003Cspan class=\"hljs-title function_\">startFen\u003C\u002Fspan>(rank.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) }\n\n  \u003Cspan class=\"hljs-comment\">\u002F\u002F chessops castles king onto rook; the king&#x27;s final square is accepted too, since that is what people click\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">targets\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">\u003Cspan class=\"hljs-attr\">from\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan>\u003C\u002Fspan>): \u003Cspan class=\"hljs-title class_\">Map\u003C\u002Fspan>&lt;\u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan>, \u003Cspan class=\"hljs-title class_\">NormalMove\u003C\u002Fspan>&gt; {\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> p = pos.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, out = \u003Cspan class=\"hljs-keyword\">new\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Map\u003C\u002Fspan>&lt;\u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan>, \u003Cspan class=\"hljs-title class_\">NormalMove\u003C\u002Fspan>&gt;()\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!p || !ops) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> out\n    \u003Cspan class=\"hljs-keyword\">for\u003C\u002Fspan> (\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> to \u003Cspan class=\"hljs-keyword\">of\u003C\u002Fspan> p.\u003Cspan class=\"hljs-title function_\">dests\u003C\u002Fspan>(\u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan>)) {\n      \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> move = { \u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan>, to }\n      out.\u003Cspan class=\"hljs-title function_\">set\u003C\u002Fspan>(to, move)\n      \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> side = ops.\u003Cspan class=\"hljs-title function_\">castlingSide\u003C\u002Fspan>(p, move)\n      \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (side) {\n        \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> kingTo = ops.\u003Cspan class=\"hljs-title function_\">kingCastlesTo\u003C\u002Fspan>(p.\u003Cspan class=\"hljs-property\">turn\u003C\u002Fspan>, side)\n        \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!out.\u003Cspan class=\"hljs-title function_\">has\u003C\u002Fspan>(kingTo) &amp;&amp; !p.\u003Cspan class=\"hljs-title function_\">dests\u003C\u002Fspan>(\u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan>).\u003Cspan class=\"hljs-title function_\">has\u003C\u002Fspan>(kingTo)) out.\u003Cspan class=\"hljs-title function_\">set\u003C\u002Fspan>(kingTo, move)\n      }\n    }\n    \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> out\n  }\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">needsPromotion\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">\u003Cspan class=\"hljs-attr\">move\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">NormalMove\u003C\u002Fspan>\u003C\u002Fspan>) =&gt; {\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> p = pos.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> !!p &amp;&amp; p.\u003Cspan class=\"hljs-property\">board\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">get\u003C\u002Fspan>(move.\u003Cspan class=\"hljs-property\">from\u003C\u002Fspan>)?.\u003Cspan class=\"hljs-property\">role\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;pawn&#x27;\u003C\u002Fspan> &amp;&amp; (move.\u003Cspan class=\"hljs-property\">to\u003C\u002Fspan> &gt;&gt; \u003Cspan class=\"hljs-number\">3\u003C\u002Fspan> === \u003Cspan class=\"hljs-number\">7\u003C\u002Fspan> || move.\u003Cspan class=\"hljs-property\">to\u003C\u002Fspan> &gt;&gt; \u003Cspan class=\"hljs-number\">3\u003C\u002Fspan> === \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>)\n  }\n\n  \u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">play\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">\u003Cspan class=\"hljs-attr\">move\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">NormalMove\u003C\u002Fspan>\u003C\u002Fspan>): \u003Cspan class=\"hljs-title class_\">Ply\u003C\u002Fspan> | \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan> {\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> p = pos.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!p || !ops || !p.\u003Cspan class=\"hljs-title function_\">isLegal\u003C\u002Fspan>(move)) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> before = p.\u003Cspan class=\"hljs-title function_\">clone\u003C\u002Fspan>()\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> side = ops.\u003Cspan class=\"hljs-title function_\">castlingSide\u003C\u002Fspan>(p, move)\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> back = p.\u003Cspan class=\"hljs-property\">turn\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan> ? \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan> : \u003Cspan class=\"hljs-number\">56\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> castle = side ? { \u003Cspan class=\"hljs-attr\">kingTo\u003C\u002Fspan>: back + (side === \u003Cspan class=\"hljs-string\">&#x27;h&#x27;\u003C\u002Fspan> ? \u003Cspan class=\"hljs-number\">6\u003C\u002Fspan> : \u003Cspan class=\"hljs-number\">2\u003C\u002Fspan>), \u003Cspan class=\"hljs-attr\">rookFrom\u003C\u002Fspan>: move.\u003Cspan class=\"hljs-property\">to\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">rookTo\u003C\u002Fspan>: back + (side === \u003Cspan class=\"hljs-string\">&#x27;h&#x27;\u003C\u002Fspan> ? \u003Cspan class=\"hljs-number\">5\u003C\u002Fspan> : \u003Cspan class=\"hljs-number\">3\u003C\u002Fspan>) } : \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> next = p.\u003Cspan class=\"hljs-title function_\">clone\u003C\u002Fspan>()\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> san = ops.\u003Cspan class=\"hljs-title function_\">makeSanAndPlay\u003C\u002Fspan>(next, move)\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">ply\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">Ply\u003C\u002Fspan> = { move, san, before, castle }\n    pos.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = next\n    plies.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = [...plies.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, ply]\n    \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> ply\n  }\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> moves = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> {\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> plies_ = plies.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> \u003Cspan class=\"hljs-comment\">\u002F\u002F read first, so it tracks the game before chessops loads\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> ops ? plies_.\u003Cspan class=\"hljs-title function_\">map\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">p\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> ops!.\u003Cspan class=\"hljs-title function_\">makeUci\u003C\u002Fspan>(p.\u003Cspan class=\"hljs-property\">move\u003C\u002Fspan>)) : []\n  })\n  \u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">replay\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">\u003Cspan class=\"hljs-attr\">ucis\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">string\u003C\u002Fspan>[]\u003C\u002Fspan>) {\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!ops) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-title function_\">reset\u003C\u002Fspan>()\n    \u003Cspan class=\"hljs-keyword\">for\u003C\u002Fspan> (\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> uci \u003Cspan class=\"hljs-keyword\">of\u003C\u002Fspan> ucis) {\n      \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> m = ops.\u003Cspan class=\"hljs-title function_\">parseUci\u003C\u002Fspan>(uci) \u003Cspan class=\"hljs-keyword\">as\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">NormalMove\u003C\u002Fspan> | \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>\n      \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!m || !\u003Cspan class=\"hljs-title function_\">play\u003C\u002Fspan>(m)) \u003Cspan class=\"hljs-keyword\">break\u003C\u002Fspan>\n    }\n  }\n  \u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">undo\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">\u003C\u002Fspan>) {\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> last = plies.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">at\u003C\u002Fspan>(-\u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>)\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!last) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n    pos.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = last.\u003Cspan class=\"hljs-property\">before\u003C\u002Fspan>\n    plies.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = plies.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">slice\u003C\u002Fspan>(\u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>, -\u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>)\n  }\n\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> outcome = computed&lt;\u003Cspan class=\"hljs-title class_\">Outcome\u003C\u002Fspan> | \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>&gt;(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> {\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> p = pos.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!p) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (p.\u003Cspan class=\"hljs-title function_\">isCheckmate\u003C\u002Fspan>()) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> { \u003Cspan class=\"hljs-attr\">winner\u003C\u002Fspan>: p.\u003Cspan class=\"hljs-property\">turn\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;black&#x27;\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">reason\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Checkmate&#x27;\u003C\u002Fspan> }\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (p.\u003Cspan class=\"hljs-title function_\">isStalemate\u003C\u002Fspan>()) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> { \u003Cspan class=\"hljs-attr\">reason\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Stalemate&#x27;\u003C\u002Fspan> }\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (p.\u003Cspan class=\"hljs-title function_\">isInsufficientMaterial\u003C\u002Fspan>()) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> { \u003Cspan class=\"hljs-attr\">reason\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Insufficient material&#x27;\u003C\u002Fspan> }\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (p.\u003Cspan class=\"hljs-property\">halfmoves\u003C\u002Fspan> &gt;= \u003Cspan class=\"hljs-number\">100\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> { \u003Cspan class=\"hljs-attr\">reason\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Fifty-move rule&#x27;\u003C\u002Fspan> }\n    \u003Cspan class=\"hljs-comment\">\u002F\u002F chessops leaves move history to the caller, so threefold repetition is counted here\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (ops) {\n      \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">key\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">\u003Cspan class=\"hljs-attr\">x\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">Chess\u003C\u002Fspan>\u003C\u002Fspan>) =&gt; ops!.\u003Cspan class=\"hljs-title function_\">makeFen\u003C\u002Fspan>(x.\u003Cspan class=\"hljs-title function_\">toSetup\u003C\u002Fspan>()).\u003Cspan class=\"hljs-title function_\">split\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27; &#x27;\u003C\u002Fspan>).\u003Cspan class=\"hljs-title function_\">slice\u003C\u002Fspan>(\u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>, \u003Cspan class=\"hljs-number\">4\u003C\u002Fspan>).\u003Cspan class=\"hljs-title function_\">join\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27; &#x27;\u003C\u002Fspan>)\n      \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> now = \u003Cspan class=\"hljs-title function_\">key\u003C\u002Fspan>(p)\n      \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (plies.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">filter\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">ply\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">key\u003C\u002Fspan>(ply.\u003Cspan class=\"hljs-property\">before\u003C\u002Fspan>) === now).\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> &gt;= \u003Cspan class=\"hljs-number\">2\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> { \u003Cspan class=\"hljs-attr\">reason\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Threefold repetition&#x27;\u003C\u002Fspan> }\n    }\n    \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n  })\n\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> fen = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> (pos.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> &amp;&amp; ops ? ops.\u003Cspan class=\"hljs-title function_\">makeFen\u003C\u002Fspan>(pos.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">toSetup\u003C\u002Fspan>()) : \u003Cspan class=\"hljs-title function_\">startFen\u003C\u002Fspan>(rank.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>)))\n  \u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">pgnText\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">\u003Cspan class=\"hljs-attr\">notes\u003C\u002Fspan>: { marks?: \u003Cspan class=\"hljs-built_in\">string\u003C\u002Fspan>[]; comments?: Record&lt;\u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan>, \u003Cspan class=\"hljs-built_in\">string\u003C\u002Fspan>&gt;; tags?: Record&lt;\u003Cspan class=\"hljs-built_in\">string\u003C\u002Fspan>, \u003Cspan class=\"hljs-built_in\">string\u003C\u002Fspan>&gt; } = {}\u003C\u002Fspan>) {\n    \u003Cspan class=\"hljs-comment\">\u002F\u002F read first, so a computed calling this tracks the game while chessops loads\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> plies_ = plies.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, o = outcome.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!pos.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> || !ops) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> { pgn } = ops\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> game = pgn.\u003Cspan class=\"hljs-property\">defaultGame\u003C\u002Fspan>&lt;\u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;chessops\u002Fpgn&#x27;\u003C\u002Fspan>).\u003Cspan class=\"hljs-property\">PgnNodeData\u003C\u002Fspan>&gt;(pgn.\u003Cspan class=\"hljs-property\">emptyHeaders\u003C\u002Fspan>)\n    \u003Cspan class=\"hljs-comment\">\u002F\u002F the page&#x27;s tags first, in the order of PGN&#x27;s own roster\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">for\u003C\u002Fspan> (\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> [k, v] \u003Cspan class=\"hljs-keyword\">of\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Object\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">entries\u003C\u002Fspan>(notes.\u003Cspan class=\"hljs-property\">tags\u003C\u002Fspan> ?? {})) game.\u003Cspan class=\"hljs-property\">headers\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">set\u003C\u002Fspan>(k, v)\n    \u003Cspan class=\"hljs-comment\">\u002F\u002F chessops drops the Variant header for standard rules, so a Chess960 game sets it after the start position\u003C\u002Fspan>\n    pgn.\u003Cspan class=\"hljs-title function_\">setStartingPosition\u003C\u002Fspan>(game.\u003Cspan class=\"hljs-property\">headers\u003C\u002Fspan>, ops.\u003Cspan class=\"hljs-property\">Chess\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">fromSetup\u003C\u002Fspan>(ops.\u003Cspan class=\"hljs-title function_\">parseFen\u003C\u002Fspan>(\u003Cspan class=\"hljs-title function_\">startFen\u003C\u002Fspan>(rank.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>)).\u003Cspan class=\"hljs-title function_\">unwrap\u003C\u002Fspan>()).\u003Cspan class=\"hljs-title function_\">unwrap\u003C\u002Fspan>())\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (rank.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> !== \u003Cspan class=\"hljs-string\">&#x27;RNBQKBNR&#x27;\u003C\u002Fspan>) game.\u003Cspan class=\"hljs-property\">headers\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">set\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;Variant&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;Chess960&#x27;\u003C\u002Fspan>)\n    game.\u003Cspan class=\"hljs-property\">headers\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">set\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;Result&#x27;\u003C\u002Fspan>, pgn.\u003Cspan class=\"hljs-title function_\">makeOutcome\u003C\u002Fspan>(o ? { \u003Cspan class=\"hljs-attr\">winner\u003C\u002Fspan>: o.\u003Cspan class=\"hljs-property\">winner\u003C\u002Fspan> } : \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>))\n    \u003Cspan class=\"hljs-keyword\">let\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">node\u003C\u002Fspan>: \u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;chessops\u002Fpgn&#x27;\u003C\u002Fspan>).\u003Cspan class=\"hljs-property\">Node\u003C\u002Fspan>&lt;\u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;chessops\u002Fpgn&#x27;\u003C\u002Fspan>).\u003Cspan class=\"hljs-property\">PgnNodeData\u003C\u002Fspan>&gt; = game.\u003Cspan class=\"hljs-property\">moves\u003C\u002Fspan>\n    plies_.\u003Cspan class=\"hljs-title function_\">forEach\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">ply, i\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> {\n      \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> comment = notes.\u003Cspan class=\"hljs-property\">comments\u003C\u002Fspan>?.[i]\n      \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> child = \u003Cspan class=\"hljs-keyword\">new\u003C\u002Fspan> pgn.\u003Cspan class=\"hljs-title class_\">ChildNode\u003C\u002Fspan>({ \u003Cspan class=\"hljs-attr\">san\u003C\u002Fspan>: ply.\u003Cspan class=\"hljs-property\">san\u003C\u002Fspan> + (notes.\u003Cspan class=\"hljs-property\">marks\u003C\u002Fspan>?.[i] ?? \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan>), \u003Cspan class=\"hljs-attr\">comments\u003C\u002Fspan>: comment ? [comment] : \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan> })\n      node.\u003Cspan class=\"hljs-property\">children\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">push\u003C\u002Fspan>(child)\n      node = child\n    })\n    \u003Cspan class=\"hljs-comment\">\u002F\u002F one move number per line: PGN allows a line break between any two tokens, so it still copies as valid PGN\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> [tags, movetext = \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan>] = pgn.\u003Cspan class=\"hljs-title function_\">makePgn\u003C\u002Fspan>(game).\u003Cspan class=\"hljs-title function_\">trim\u003C\u002Fspan>().\u003Cspan class=\"hljs-title function_\">split\u003C\u002Fspan>(\u003Cspan class=\"hljs-regexp\">\u002F\\n\\n\u002F\u003C\u002Fspan>)\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> lines = movetext.\u003Cspan class=\"hljs-title function_\">replace\u003C\u002Fspan>(\u003Cspan class=\"hljs-regexp\">\u002F\\s+\u002Fg\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27; &#x27;\u003C\u002Fspan>).\u003Cspan class=\"hljs-title function_\">trim\u003C\u002Fspan>().\u003Cspan class=\"hljs-title function_\">replace\u003C\u002Fspan>(\u003Cspan class=\"hljs-regexp\">\u002F (?=\\d+\\. )\u002Fg\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;\\n&#x27;\u003C\u002Fspan>).\u003Cspan class=\"hljs-title function_\">replace\u003C\u002Fspan>(\u003Cspan class=\"hljs-regexp\">\u002F (1-0|0-1|1\\\u002F2-1\\\u002F2|\\*)$\u002F\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;\\n$1&#x27;\u003C\u002Fspan>)\n    \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> lines ? \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${tags}\u003C\u002Fspan>\\n\\n\u003Cspan class=\"hljs-subst\">${lines}\u003C\u002Fspan>`\u003C\u002Fspan> : tags!\n  }\n\n  \u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">computerMove\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">\u003C\u002Fspan>): \u003Cspan class=\"hljs-title class_\">NormalMove\u003C\u002Fspan> | \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan> {\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> p = pos.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> p &amp;&amp; !outcome.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? \u003Cspan class=\"hljs-title function_\">simpleMove\u003C\u002Fspan>(p) : \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>\n  }\n\n  \u003Cspan class=\"hljs-comment\">\u002F\u002F A late answer (the position changed meanwhile) is never played.\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">async\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">engineMove\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">\u003Cspan class=\"hljs-attr\">engine\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">Exclude\u003C\u002Fspan>&lt;\u003Cspan class=\"hljs-title class_\">Player\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;human&#x27;\u003C\u002Fspan>&gt;, minMs = \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">level\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;easy&#x27;\u003C\u002Fspan> | \u003Cspan class=\"hljs-string\">&#x27;normal&#x27;\u003C\u002Fspan> | \u003Cspan class=\"hljs-string\">&#x27;hard&#x27;\u003C\u002Fspan> = \u003Cspan class=\"hljs-string\">&#x27;hard&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">onDecided\u003C\u002Fspan>?: (d: EngineDecision) =&gt; \u003Cspan class=\"hljs-built_in\">void\u003C\u002Fspan>, fallback = \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>\u003C\u002Fspan>): \u003Cspan class=\"hljs-title class_\">Promise\u003C\u002Fspan>&lt;\u003Cspan class=\"hljs-title class_\">EngineDecision\u003C\u002Fspan> | \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>&gt; {\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> p = pos.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!p || !ops || outcome.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> at = plies.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan>, t0 = performance.\u003Cspan class=\"hljs-title function_\">now\u003C\u002Fspan>()\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> local = (\u003Cspan class=\"hljs-attr\">note\u003C\u002Fspan>?: \u003Cspan class=\"hljs-built_in\">string\u003C\u002Fspan>): { \u003Cspan class=\"hljs-attr\">move\u003C\u002Fspan>?: \u003Cspan class=\"hljs-title class_\">NormalMove\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">decision\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">EngineDecision\u003C\u002Fspan> } =&gt; {\n      \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> move = \u003Cspan class=\"hljs-title function_\">computerMove\u003C\u002Fspan>()\n      \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> { move, \u003Cspan class=\"hljs-attr\">decision\u003C\u002Fspan>: { \u003Cspan class=\"hljs-attr\">engine\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;simple&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">san\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">ms\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">Math\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">round\u003C\u002Fspan>(performance.\u003Cspan class=\"hljs-title function_\">now\u003C\u002Fspan>() - t0), note } }\n    }\n    \u003Cspan class=\"hljs-keyword\">let\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">move\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">NormalMove\u003C\u002Fspan> | \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">decision\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">EngineDecision\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (engine === \u003Cspan class=\"hljs-string\">&#x27;jev&#x27;\u003C\u002Fspan>) {\n      \u003Cspan class=\"hljs-keyword\">try\u003C\u002Fspan> {\n        \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> r = \u003Cspan class=\"hljs-keyword\">await\u003C\u002Fspan> $fetch&lt;{ \u003Cspan class=\"hljs-attr\">uci\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">string\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">san\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">string\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">candidates\u003C\u002Fspan>: { \u003Cspan class=\"hljs-attr\">uci\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">string\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">san\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">string\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">p\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan> }[]; \u003Cspan class=\"hljs-attr\">confidence\u003C\u002Fspan>?: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">model\u003C\u002Fspan>?: \u003Cspan class=\"hljs-built_in\">string\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">ms\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">options\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">offered\u003C\u002Fspan>?: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">forced\u003C\u002Fspan>?: \u003Cspan class=\"hljs-title class_\">EngineDecision\u003C\u002Fspan>[\u003Cspan class=\"hljs-string\">&#x27;forced&#x27;\u003C\u002Fspan>]; \u003Cspan class=\"hljs-attr\">reading\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">EngineDecision\u003C\u002Fspan>[\u003Cspan class=\"hljs-string\">&#x27;reading&#x27;\u003C\u002Fspan>] }&gt;(\u003Cspan class=\"hljs-string\">&#x27;\u002Fapi\u002Fchess\u002Fjev&#x27;\u003C\u002Fspan>, {\n          \u003Cspan class=\"hljs-attr\">method\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;POST&#x27;\u003C\u002Fspan>,\n          \u003Cspan class=\"hljs-attr\">body\u003C\u002Fspan>: { \u003Cspan class=\"hljs-attr\">start\u003C\u002Fspan>: \u003Cspan class=\"hljs-title function_\">startFen\u003C\u002Fspan>(rank.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>), \u003Cspan class=\"hljs-attr\">moves\u003C\u002Fspan>: moves.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">history\u003C\u002Fspan>: plies.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">map\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">x\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> x.\u003Cspan class=\"hljs-property\">san\u003C\u002Fspan>), \u003Cspan class=\"hljs-attr\">variant\u003C\u002Fspan>: rank.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;RNBQKBNR&#x27;\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;chess&#x27;\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;chess960&#x27;\u003C\u002Fspan>, level },\n        })\n        \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> m = ops.\u003Cspan class=\"hljs-title function_\">parseUci\u003C\u002Fspan>(r.\u003Cspan class=\"hljs-property\">uci\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">as\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">NormalMove\u003C\u002Fspan> | \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>\n        \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!m || !pos.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>?.\u003Cspan class=\"hljs-title function_\">isLegal\u003C\u002Fspan>(m)) \u003Cspan class=\"hljs-keyword\">throw\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">new\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Error\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;illegal&#x27;\u003C\u002Fspan>)\n        move = m\n        decision = { \u003Cspan class=\"hljs-attr\">engine\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;jev&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">san\u003C\u002Fspan>: r.\u003Cspan class=\"hljs-property\">san\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">ms\u003C\u002Fspan>: r.\u003Cspan class=\"hljs-property\">ms\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">candidates\u003C\u002Fspan>: r.\u003Cspan class=\"hljs-property\">candidates\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">confidence\u003C\u002Fspan>: r.\u003Cspan class=\"hljs-property\">confidence\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">model\u003C\u002Fspan>: r.\u003Cspan class=\"hljs-property\">model\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">options\u003C\u002Fspan>: r.\u003Cspan class=\"hljs-property\">options\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">forced\u003C\u002Fspan>: r.\u003Cspan class=\"hljs-property\">forced\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">offered\u003C\u002Fspan>: r.\u003Cspan class=\"hljs-property\">offered\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">reading\u003C\u002Fspan>: r.\u003Cspan class=\"hljs-property\">reading\u003C\u002Fspan> }\n      } \u003Cspan class=\"hljs-keyword\">catch\u003C\u002Fspan> (e) {\n        \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> err = e \u003Cspan class=\"hljs-keyword\">as\u003C\u002Fspan> { \u003Cspan class=\"hljs-attr\">statusCode\u003C\u002Fspan>?: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">response\u003C\u002Fspan>?: \u003Cspan class=\"hljs-title class_\">Response\u003C\u002Fspan> }\n        \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> status = err.\u003Cspan class=\"hljs-property\">statusCode\u003C\u002Fspan>\n        \u003Cspan class=\"hljs-comment\">\u002F\u002F watching, a stand-in would change the match\u003C\u002Fspan>\n        \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!fallback &amp;&amp; status === \u003Cspan class=\"hljs-number\">429\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> { \u003Cspan class=\"hljs-attr\">engine\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;jev&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">san\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">ms\u003C\u002Fspan>: \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">resting\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">Number\u003C\u002Fspan>(err.\u003Cspan class=\"hljs-property\">response\u003C\u002Fspan>?.\u003Cspan class=\"hljs-property\">headers\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">get\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;retry-after&#x27;\u003C\u002Fspan>)) || \u003Cspan class=\"hljs-number\">30\u003C\u002Fspan> }\n        ;({ move, decision } = \u003Cspan class=\"hljs-title function_\">local\u003C\u002Fspan>(status === \u003Cspan class=\"hljs-number\">429\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;Jev is resting (too many moves, or today\\&#x27;s budget is spent); the simple engine played.&#x27;\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;Jev did not answer; the simple engine played.&#x27;\u003C\u002Fspan>))\n      }\n    } \u003Cspan class=\"hljs-title function_\">else\u003C\u002Fspan> ({ move, decision } = \u003Cspan class=\"hljs-title function_\">local\u003C\u002Fspan>())\n    \u003Cspan class=\"hljs-comment\">\u002F\u002F a minimum time per move, so a fast engine can still be watched\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (plies.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> === at &amp;&amp; pos.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === p) onDecided?.(decision)\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> wait = minMs - (performance.\u003Cspan class=\"hljs-title function_\">now\u003C\u002Fspan>() - t0)\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (wait &gt; \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">await\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">new\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Promise\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">r\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-built_in\">setTimeout\u003C\u002Fspan>(r, wait))\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!move || plies.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> !== at || pos.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> !== p) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> ply = \u003Cspan class=\"hljs-title function_\">play\u003C\u002Fspan>(move)\n    \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> ply ? { ...decision, \u003Cspan class=\"hljs-attr\">san\u003C\u002Fspan>: ply.\u003Cspan class=\"hljs-property\">san\u003C\u002Fspan> } : \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>\n  }\n\n  \u003Cspan class=\"hljs-keyword\">async\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">predictReply\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">\u003C\u002Fspan>): \u003Cspan class=\"hljs-title class_\">Promise\u003C\u002Fspan>&lt;{ \u003Cspan class=\"hljs-attr\">san\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">string\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">p\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan> } | \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>&gt; {\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!pos.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> || outcome.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> $fetch&lt;{ \u003Cspan class=\"hljs-attr\">san\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">string\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">p\u003C\u002Fspan>: \u003Cspan class=\"hljs-built_in\">number\u003C\u002Fspan> }&gt;(\u003Cspan class=\"hljs-string\">&#x27;\u002Fapi\u002Fchess\u002Fjev-predict&#x27;\u003C\u002Fspan>, { \u003Cspan class=\"hljs-attr\">method\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;POST&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">body\u003C\u002Fspan>: { \u003Cspan class=\"hljs-attr\">fen\u003C\u002Fspan>: fen.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> } }).\u003Cspan class=\"hljs-title function_\">catch\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>)\n  }\n\n  \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> { \u003Cspan class=\"hljs-attr\">position\u003C\u002Fspan>: pos, load, ready, legal, squares, squaresAt, checkAt, sanAt, fenAt, turn, check, targets, needsPromotion, play, undo, reset, plies, moves, replay, outcome, fen, pgnText, engineMove, predictReply }\n}",{"path":226,"lines":227,"code":228,"html":229},"app\u002Fpages\u002Fg\u002F[id].vue",95,"\u003Cscript setup lang=\"ts\">\nimport { gameHeadline } from '@cw\u002Fchess\u002Fheadline'\nimport { materialStory } from '@cw\u002Fchess\u002Frules'\nimport { FONT_FACES, WATCH_SPEEDS } from '#core\u002Fdomain\u002Fchess-board'\n\n\u002F\u002F The server renders the final position; the rules load on mount for the positions in between.\nconst route = useRoute('g-id')\nconst { data: game, error } = await useFetch(() => `\u002Fapi\u002Fchess\u002Fgames\u002F${route.params.id}`, { key: `game-${route.params.id}` })\nif (error.value || !game.value) throw createError({ statusCode: 404, statusMessage: 'No such game', fatal: true })\nconst g = computed(() => game.value!)\n\nconst headline = computed(() => gameHeadline(g.value.white, g.value.black, g.value.winner))\nconst moves = computed(() => Math.ceil(g.value.sans.length \u002F 2))\nconst variant = computed(() => (g.value.chess960 ? `Chess960 #${g.value.n}` : 'Chess'))\nconst story = computed(() => materialStory(g.value.balance, g.value.sans, g.value.winner))\nconst score = computed(() => g.value.result.replace('1\u002F2', '½').replace('-', '–'))\nconst onBoard = computed(() => `\u002Flab\u002Fchess${g.value.chess960 ? `\u002F960\u002F${g.value.n}` : ''}?g=${g.value.moves.join('.')}`)\nconst { font, theme } = useChessSet()\n\nconst rank = computed(() => g.value.rank)\nconst play = useChessGame(rank)\nconst total = computed(() => g.value.sans.length)\nconst at = ref(total.value)\nonMounted(async () => { await play.load(); play.replay(g.value.moves) })\nconst ready = computed(() => play.plies.value.length === total.value)\nconst squares = computed(() => (ready.value ? play.squaresAt(at.value) : g.value.squares))\nconst check = computed(() => (ready.value ? play.checkAt(at.value) : at.value === total.value ? g.value.check : undefined))\nconst last = computed(() => (ready.value && at.value > 0 ? play.plies.value[at.value - 1] : undefined))\nconst go = (k: number | null) => { pause(); at.value = k === null ? total.value : Math.max(0, Math.min(total.value, k)) }\n\nconst SPEEDS = [\n  { value: 'real', label: 'Real time' },\n  { value: 'slow', label: 'Slow' },\n  { value: 'normal', label: 'Normal' },\n  { value: 'fast', label: 'Fast' },\n] as const\ntype Speed = (typeof SPEEDS)[number]['value']\nconst speeds = computed(() => (g.value.times ? SPEEDS : SPEEDS.filter((s) => s.value !== 'real')))\nconst speed = ref\u003CSpeed>(g.value.times ? 'real' : 'normal')\n\u002F\u002F capped, so a long think does not stall the replay\nconst wait = (k: number) => (speed.value === 'real' ? Math.min(10_000, g.value.times?.[k] ?? WATCH_SPEEDS.normal) : WATCH_SPEEDS[speed.value])\nconst playing = ref(false)\nconst step = useTimeoutFn(() => {\n  at.value++\n  if (at.value \u003C total.value) step.start(); else playing.value = false\n}, () => wait(at.value), { immediate: false })\nfunction pause() { playing.value = false; step.stop() }\nfunction toggle() {\n  if (playing.value) return pause()\n  if (at.value >= total.value) at.value = 0\n  playing.value = true\n  step.start()\n}\n\nuseHead({ style: [{ key: 'chess-fonts', innerHTML: FONT_FACES }] })\nconst { canonical } = usePageSeo({\n  title: () => headline.value.replace(\u002F\\.$\u002F, ''),\n  description: () => `${score.value}, ${g.value.reason.toLowerCase()} after ${moves.value} moves (${variant.value}), played at chriswijnia.com on ${formatDay(g.value.at)}.`,\n  image: () => `\u002Fog\u002Fgame\u002F${g.value.id}.png`,\n})\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Csection class=\"bg-paper py-section game\">\n    \u003Cdiv class=\"wrap game__grid\">\n      \u003CPageHead :back=\"{ to: onBoard.split('?')[0]!, label: 'Chess' }\" :rule=\"false\">\n        \u003Ctemplate #meta>\n          \u003Cspan>{{ g.chess960 ? variant : 'Standard' }}\u003C\u002Fspan>\n          \u003Cspan>{{ formatDay(g.at) }}\u003C\u002Fspan>\n        \u003C\u002Ftemplate>\n        \u003Ch1 class=\"statement-lg\">{{ headline }}\u003C\u002Fh1>\n        \u003Cp class=\"lede\">{{ score }} · {{ g.reason }} after {{ moves }} move{{ moves === 1 ? '' : 's' }}.{{ story.summary ? ` ${story.summary}` : '' }}\u003C\u002Fp>\n        \u003Cdiv class=\"game__actions\">\n          \u003CBtn :to=\"onBoard\" variant=\"ghost\" size=\"md\">Play on from here ►\u003C\u002FBtn>\n          \u003CShareBar :url=\"canonical\" :title=\"headline\" label=\"Share this game\" \u002F>\n        \u003C\u002Fdiv>\n      \u003C\u002FPageHead>\n\n      \u003CWin :title=\"`CW\u002FREPLAY · ${at} \u002F ${total}`\" as=\"figure\" label=\"The game, replayed\" :minimizable=\"false\" :draggable=\"false\" class=\"game__board\">\n        \u003CChessBoard\n          :squares=\"squares\" :font=\"font\" :theme=\"theme\" :flipped=\"false\" :interactive=\"false\"\n          :targets=\"() => new Map()\" :needs-promotion=\"() => false\" :check=\"check\" :last=\"last\" :ply-count=\"at\"\n        \u002F>\n      \u003C\u002FWin>\n\n      \u003CWin title=\"CW\u002FMOVES\" as=\"section\" label=\"The moves\" :minimizable=\"false\" :draggable=\"false\" class=\"game__moves\">\n        \u003Cdiv class=\"replay\">\n          \u003CBtn variant=\"amber\" size=\"md\" :disabled=\"!ready\" @click=\"toggle\">{{ playing ? 'Pause ║' : at >= total ? 'Replay ►' : 'Play ►' }}\u003C\u002FBtn>\n          \u003CChessToggle v-model=\"speed\" :options=\"speeds\" label=\"Replay speed\" \u002F>\n        \u003C\u002Fdiv>\n        \u003CChessMoveList :sans=\"g.sans\" :marks=\"story.marks\" :shown=\"at\" :viewing=\"true\" @go=\"go\" \u002F>\n      \u003C\u002FWin>\n    \u003C\u002Fdiv>\n  \u003C\u002Fsection>\n\u003C\u002Ftemplate>","\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">script\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">setup\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">lang\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;ts&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"language-javascript\">\n\u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan> { gameHeadline } \u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;@cw\u002Fchess\u002Fheadline&#x27;\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan> { materialStory } \u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;@cw\u002Fchess\u002Frules&#x27;\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan> { \u003Cspan class=\"hljs-variable constant_\">FONT_FACES\u003C\u002Fspan>, \u003Cspan class=\"hljs-variable constant_\">WATCH_SPEEDS\u003C\u002Fspan> } \u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;#core\u002Fdomain\u002Fchess-board&#x27;\u003C\u002Fspan>\n\n\u003Cspan class=\"hljs-comment\">\u002F\u002F The server renders the final position; the rules load on mount for the positions in between.\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> route = \u003Cspan class=\"hljs-title function_\">useRoute\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;g-id&#x27;\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> { \u003Cspan class=\"hljs-attr\">data\u003C\u002Fspan>: game, error } = \u003Cspan class=\"hljs-keyword\">await\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">useFetch\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">`\u002Fapi\u002Fchess\u002Fgames\u002F\u003Cspan class=\"hljs-subst\">${route.params.id}\u003C\u002Fspan>`\u003C\u002Fspan>, { \u003Cspan class=\"hljs-attr\">key\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">`game-\u003Cspan class=\"hljs-subst\">${route.params.id}\u003C\u002Fspan>`\u003C\u002Fspan> })\n\u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (error.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> || !game.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">throw\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">createError\u003C\u002Fspan>({ \u003Cspan class=\"hljs-attr\">statusCode\u003C\u002Fspan>: \u003Cspan class=\"hljs-number\">404\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">statusMessage\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;No such game&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">fatal\u003C\u002Fspan>: \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan> })\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> g = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> game.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>!)\n\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> headline = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">gameHeadline\u003C\u002Fspan>(g.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">white\u003C\u002Fspan>, g.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">black\u003C\u002Fspan>, g.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">winner\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> moves = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Math\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">ceil\u003C\u002Fspan>(g.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">sans\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> \u002F \u003Cspan class=\"hljs-number\">2\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> variant = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> (g.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">chess960\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">`Chess960 #\u003Cspan class=\"hljs-subst\">${g.value.n}\u003C\u002Fspan>`\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;Chess&#x27;\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> story = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">materialStory\u003C\u002Fspan>(g.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">balance\u003C\u002Fspan>, g.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">sans\u003C\u002Fspan>, g.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">winner\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> score = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> g.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">result\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">replace\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;1\u002F2&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;½&#x27;\u003C\u002Fspan>).\u003Cspan class=\"hljs-title function_\">replace\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;-&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;–&#x27;\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> onBoard = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">`\u002Flab\u002Fchess\u003Cspan class=\"hljs-subst\">${g.value.chess960 ? \u003Cspan class=\"hljs-string\">`\u002F960\u002F\u003Cspan class=\"hljs-subst\">${g.value.n}\u003C\u002Fspan>`\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan>}\u003C\u002Fspan>?g=\u003Cspan class=\"hljs-subst\">${g.value.moves.join(\u003Cspan class=\"hljs-string\">&#x27;.&#x27;\u003C\u002Fspan>)}\u003C\u002Fspan>`\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> { font, theme } = \u003Cspan class=\"hljs-title function_\">useChessSet\u003C\u002Fspan>()\n\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> rank = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> g.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">rank\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> play = \u003Cspan class=\"hljs-title function_\">useChessGame\u003C\u002Fspan>(rank)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> total = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> g.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">sans\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> at = \u003Cspan class=\"hljs-title function_\">ref\u003C\u002Fspan>(total.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-title function_\">onMounted\u003C\u002Fspan>(\u003Cspan class=\"hljs-title function_\">async\u003C\u002Fspan> () =&gt; { \u003Cspan class=\"hljs-keyword\">await\u003C\u002Fspan> play.\u003Cspan class=\"hljs-title function_\">load\u003C\u002Fspan>(); play.\u003Cspan class=\"hljs-title function_\">replay\u003C\u002Fspan>(g.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">moves\u003C\u002Fspan>) })\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> ready = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> play.\u003Cspan class=\"hljs-property\">plies\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> === total.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> squares = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> (ready.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? play.\u003Cspan class=\"hljs-title function_\">squaresAt\u003C\u002Fspan>(at.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) : g.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">squares\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> check = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> (ready.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? play.\u003Cspan class=\"hljs-title function_\">checkAt\u003C\u002Fspan>(at.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) : at.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === total.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? g.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">check\u003C\u002Fspan> : \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> last = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> (ready.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> &amp;&amp; at.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> &gt; \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan> ? play.\u003Cspan class=\"hljs-property\">plies\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>[at.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> - \u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>] : \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">go\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">k: number | \u003Cspan class=\"hljs-literal\">null\u003C\u002Fspan>\u003C\u002Fspan>) =&gt; { \u003Cspan class=\"hljs-title function_\">pause\u003C\u002Fspan>(); at.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = k === \u003Cspan class=\"hljs-literal\">null\u003C\u002Fspan> ? total.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> : \u003Cspan class=\"hljs-title class_\">Math\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">max\u003C\u002Fspan>(\u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>, \u003Cspan class=\"hljs-title class_\">Math\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">min\u003C\u002Fspan>(total.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, k)) }\n\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-variable constant_\">SPEEDS\u003C\u002Fspan> = [\n  { \u003Cspan class=\"hljs-attr\">value\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;real&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Real time&#x27;\u003C\u002Fspan> },\n  { \u003Cspan class=\"hljs-attr\">value\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;slow&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Slow&#x27;\u003C\u002Fspan> },\n  { \u003Cspan class=\"hljs-attr\">value\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;normal&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Normal&#x27;\u003C\u002Fspan> },\n  { \u003Cspan class=\"hljs-attr\">value\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;fast&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Fast&#x27;\u003C\u002Fspan> },\n] \u003Cspan class=\"hljs-keyword\">as\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan>\ntype \u003Cspan class=\"hljs-title class_\">Speed\u003C\u002Fspan> = (\u003Cspan class=\"hljs-keyword\">typeof\u003C\u002Fspan> \u003Cspan class=\"hljs-variable constant_\">SPEEDS\u003C\u002Fspan>)[number][\u003Cspan class=\"hljs-string\">&#x27;value&#x27;\u003C\u002Fspan>]\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> speeds = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> (g.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">times\u003C\u002Fspan> ? \u003Cspan class=\"hljs-variable constant_\">SPEEDS\u003C\u002Fspan> : \u003Cspan class=\"hljs-variable constant_\">SPEEDS\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">filter\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">s\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> s.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> !== \u003Cspan class=\"hljs-string\">&#x27;real&#x27;\u003C\u002Fspan>)))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> speed = ref&lt;\u003Cspan class=\"hljs-title class_\">Speed\u003C\u002Fspan>&gt;(g.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">times\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;real&#x27;\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;normal&#x27;\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-comment\">\u002F\u002F capped, so a long think does not stall the replay\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">wait\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">k: number\u003C\u002Fspan>) =&gt; (speed.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;real&#x27;\u003C\u002Fspan> ? \u003Cspan class=\"hljs-title class_\">Math\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">min\u003C\u002Fspan>(\u003Cspan class=\"hljs-number\">10_000\u003C\u002Fspan>, g.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">times\u003C\u002Fspan>?.[k] ?? \u003Cspan class=\"hljs-variable constant_\">WATCH_SPEEDS\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">normal\u003C\u002Fspan>) : \u003Cspan class=\"hljs-variable constant_\">WATCH_SPEEDS\u003C\u002Fspan>[speed.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>])\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> playing = \u003Cspan class=\"hljs-title function_\">ref\u003C\u002Fspan>(\u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> step = \u003Cspan class=\"hljs-title function_\">useTimeoutFn\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> {\n  at.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>++\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (at.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> &lt; total.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) step.\u003Cspan class=\"hljs-title function_\">start\u003C\u002Fspan>(); \u003Cspan class=\"hljs-keyword\">else\u003C\u002Fspan> playing.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>\n}, \u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">wait\u003C\u002Fspan>(at.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>), { \u003Cspan class=\"hljs-attr\">immediate\u003C\u002Fspan>: \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan> })\n\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">pause\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">\u003C\u002Fspan>) { playing.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>; step.\u003Cspan class=\"hljs-title function_\">stop\u003C\u002Fspan>() }\n\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">toggle\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">\u003C\u002Fspan>) {\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (playing.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">pause\u003C\u002Fspan>()\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (at.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> &gt;= total.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) at.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>\n  playing.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>\n  step.\u003Cspan class=\"hljs-title function_\">start\u003C\u002Fspan>()\n}\n\n\u003Cspan class=\"hljs-title function_\">useHead\u003C\u002Fspan>({ \u003Cspan class=\"hljs-attr\">style\u003C\u002Fspan>: [{ \u003Cspan class=\"hljs-attr\">key\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;chess-fonts&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">innerHTML\u003C\u002Fspan>: \u003Cspan class=\"hljs-variable constant_\">FONT_FACES\u003C\u002Fspan> }] })\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> { canonical } = \u003Cspan class=\"hljs-title function_\">usePageSeo\u003C\u002Fspan>({\n  \u003Cspan class=\"hljs-attr\">title\u003C\u002Fspan>: \u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> headline.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">replace\u003C\u002Fspan>(\u003Cspan class=\"hljs-regexp\">\u002F\\.$\u002F\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan>),\n  \u003Cspan class=\"hljs-attr\">description\u003C\u002Fspan>: \u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${score.value}\u003C\u002Fspan>, \u003Cspan class=\"hljs-subst\">${g.value.reason.toLowerCase()}\u003C\u002Fspan> after \u003Cspan class=\"hljs-subst\">${moves.value}\u003C\u002Fspan> moves (\u003Cspan class=\"hljs-subst\">${variant.value}\u003C\u002Fspan>), played at chriswijnia.com on \u003Cspan class=\"hljs-subst\">${formatDay(g.value.at)}\u003C\u002Fspan>.`\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">image\u003C\u002Fspan>: \u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">`\u002Fog\u002Fgame\u002F\u003Cspan class=\"hljs-subst\">${g.value.id}\u003C\u002Fspan>.png`\u003C\u002Fspan>,\n})\n\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">script\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n\n\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">section\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;bg-paper py-section game&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;wrap game__grid&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n      \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">PageHead\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:back\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;{ to: onBoard.split(&#x27;?&#x27;)[0]!, label: &#x27;Chess&#x27; }&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:rule\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;false&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n        \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan> #\u003Cspan class=\"hljs-attr\">meta\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n          \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ g.chess960 ? variant : &#x27;Standard&#x27; }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n          \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ formatDay(g.at) }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n        \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n        \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">h1\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;statement-lg&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ headline }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">h1\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n        \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;lede&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ score }} · {{ g.reason }} after {{ moves }} move{{ moves === 1 ? &#x27;&#x27; : &#x27;s&#x27; }}.{{ story.summary ? ` ${story.summary}` : &#x27;&#x27; }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n        \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;game__actions&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n          \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">Btn\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:to\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;onBoard&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">variant\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;ghost&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">size\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;md&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>Play on from here ►\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">Btn\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n          \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">ShareBar\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:url\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;canonical&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:title\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;headline&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;Share this game&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\n        \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n      \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">PageHead\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n\n      \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">Win\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:title\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;`CW\u002FREPLAY · ${at} \u002F ${total}`&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">as\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;figure&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;The game, replayed&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:minimizable\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;false&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:draggable\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;false&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;game__board&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n        \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">ChessBoard\u003C\u002Fspan>\n          \u003Cspan class=\"hljs-attr\">:squares\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;squares&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:font\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;font&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:theme\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;theme&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:flipped\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;false&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:interactive\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;false&quot;\u003C\u002Fspan>\n          \u003Cspan class=\"hljs-attr\">:targets\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;() =&gt; new Map()&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:needs-promotion\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;() =&gt; false&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:check\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;check&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:last\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;last&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:ply-count\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;at&quot;\u003C\u002Fspan>\n        \u002F&gt;\u003C\u002Fspan>\n      \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">Win\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n\n      \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">Win\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">title\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;CW\u002FMOVES&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">as\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;section&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;The moves&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:minimizable\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;false&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:draggable\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;false&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;game__moves&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n        \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;replay&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n          \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">Btn\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">variant\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;amber&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">size\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;md&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:disabled\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;!ready&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">click\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;toggle&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ playing ? &#x27;Pause ║&#x27; : at &gt;= total ? &#x27;Replay ►&#x27; : &#x27;Play ►&#x27; }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">Btn\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n          \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">ChessToggle\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-model\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;speed&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:options\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;speeds&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;Replay speed&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\n        \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n        \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">ChessMoveList\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:sans\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;g.sans&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:marks\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;story.marks&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:shown\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;at&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:viewing\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;true&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">go\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;go&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\n      \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">Win\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">section\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan>&gt;\u003C\u002Fspan>",{"path":231,"lines":232,"code":233,"html":234},"app\u002Fpages\u002Flab\u002Fchess\u002F[...pos].vue",734,"\u003Cscript setup lang=\"ts\">\nimport { backRank, startFen, materialBalance, materialStory, isPositionId, POSITIONS, setup, STANDARD } from '@cw\u002Fchess\u002Frules'\nimport { BOARD_THEMES, CHESS_SETS, FONT_FACES, WATCH_SPEEDS, pieceGlyph, squareGlyph, type BoardTheme } from '#core\u002Fdomain\u002Fchess-board'\nimport type { GameMode as Mode } from '@cw\u002Fchess'\nimport { PhShuffle } from '@phosphor-icons\u002Fvue'\nimport { fill, pickLine } from '@cw\u002Fjevvie'\nimport companion from '~~\u002Fcontent\u002Fcompanion.json'\nimport type { EngineDecision, Player } from '~\u002Fcomposables\u002FuseChessGame'\nimport type { CoachVerdict } from '~\u002Fcomponents\u002Flab\u002FChessCoach.vue'\n\n\u002F\u002F one page instance across positions: switching swaps the board in place\ndefinePageMeta({ keepScroll: true, key: 'chess', jevvie: 'pawn' })\n\n\u002F\u002F \u002F960 picks a random position, and \u002F960\u002F518 is plain chess, so it goes to \u002Flab\u002Fchess.\nconst BASE = '\u002Flab\u002Fchess'\nconst route = useRoute()\nconst path = computed(() => ([] as string[]).concat(route.params.pos ?? []).filter(Boolean))\nconst href = (i: number) => { const k = (i + POSITIONS) % POSITIONS; return k === STANDARD ? BASE : `${BASE}\u002F960\u002F${k}` }\n\u002F\u002F skips 518, which is standard chess\nconst step = (d: number) => { let k = (n.value + d + POSITIONS) % POSITIONS; if (k === STANDARD) k = (k + d + POSITIONS) % POSITIONS; return href(k) }\nconst random960 = () => { let k = STANDARD; while (k === STANDARD) k = Math.floor(Math.random() * POSITIONS); return href(k) }\nconst parse = (p: string[]) => (!p.length ? STANDARD : p[0] === '960' && p.length === 2 && \u002F^\\d{1,3}$\u002F.test(p[1]!) ? Number(p[1]) : NaN)\nconst redirect = (p: string[]) => (p.length === 1 && p[0] === '960' ? random960() : p.length === 2 && parse(p) === STANDARD ? BASE : undefined)\nconst first = redirect(path.value)\nif (first) await navigateTo(first, { redirectCode: path.value.length === 1 ? 302 : 301, replace: true })\nif (!first && !isPositionId(parse(path.value))) throw createError({ statusCode: 404, statusMessage: 'No such Chess960 position', fatal: true })\nwatch(path, (p) => { const to = redirect(p); if (to) void navigateTo(to, { replace: true }) })\nconst n = computed(() => { const k = parse(path.value); return isPositionId(k) ? k : STANDARD })\nconst is960 = computed(() => n.value !== STANDARD)\n\nconst rank = computed(() => backRank(n.value))\nconst flipped = useStored('chessFlipped', false, oneOf(true, false))\nconst { set, font, theme } = useChessSet()\nconst swatch = (t: BoardTheme) => ({ background: `var(--color-${BOARD_THEMES[t].ground})`, color: `var(--color-${BOARD_THEMES[t].ink})` })\nconst family = computed(() => `'Chess ${font.value}', var(--font-mono)`)\n\u002F\u002F Declared on this page only: a browser fetches a face only when text uses it, so a visitor downloads just the set on screen.\nuseHead({ link: [{ rel: 'preload', href: '\u002Ffonts\u002Fchess\u002Fmerida.woff2', as: 'font', type: 'font\u002Fwoff2', crossorigin: '' }], style: [{ key: 'chess-fonts', innerHTML: FONT_FACES }] })\n\nconst presence = usePresence('chess')\nconst boardTitle = computed(() => `${is960.value ? `CW\u002FCHESS960 · ${rank.value}` : 'CW\u002FCHESS'}${presence.value?.here ? ` · ${presence.value.here} here` : ''}`)\nconst game = useChessGame(rank)\nconst MODES: { value: Mode; label: string; note: string; featured?: boolean }[] = [\n  { value: 'jev-jev', label: 'Watch Jev vs Jev', note: 'the model against itself', featured: true },\n  { value: 'jev-simple', label: 'Watch Jev vs engine', note: 'sides swap each game' },\n  { value: 'jev', label: 'Play Jev', note: 'you against the model' },\n  { value: 'simple', label: 'Play the engine', note: 'quick, grabs material' },\n  { value: 'friend', label: 'Play a friend', note: 'two players, one board' },\n]\nconst mode = useStored\u003CMode>('chessMode', 'jev-jev', oneOf\u003CMode>('jev', 'simple', 'friend', 'jev-jev', 'jev-simple'))\n\u002F\u002F the seats are kept, so a reload finds the same sides\nconst colour = useStored\u003C'white' | 'black' | 'random'>('chessColour', 'white', oneOf('white', 'black', 'random'))\nconst yours = useStored\u003C'white' | 'black'>('chessYours', 'white', oneOf('white', 'black'))\nconst jevSide = useStored\u003C'white' | 'black'>('chessJevSide', 'white', oneOf('white', 'black'))\nconst other = (c: 'white' | 'black') => (c === 'white' ? 'black' : 'white')\nfunction seat() {\n  if (mode.value === 'jev' || mode.value === 'simple') {\n    yours.value = colour.value === 'random' ? (Math.random() \u003C 0.5 ? 'white' : 'black') : colour.value\n    flipped.value = yours.value === 'black'\n  }\n  if (mode.value === 'jev-simple') jevSide.value = other(jevSide.value)\n}\nconst players = computed\u003C{ white: Player; black: Player }>(() => {\n  const m = mode.value\n  if (m === 'friend') return { white: 'human', black: 'human' }\n  if (m === 'jev-jev') return { white: 'jev', black: 'jev' }\n  if (m === 'jev-simple') return jevSide.value === 'white' ? { white: 'jev', black: 'simple' } : { white: 'simple', black: 'jev' }\n  return yours.value === 'white' ? { white: 'human', black: m } : { white: m, black: 'human' }\n})\nconst auto = computed(() => mode.value === 'jev-jev' || mode.value === 'jev-simple')\nconst jevPlays = computed(() => players.value.white === 'jev' || players.value.black === 'jev')\nfunction choose(m: Mode) { mode.value = m; newGame() }\nconst modeLabel = computed(() => MODES.find((m) => m.value === mode.value)?.label)\nconst cap = (s: string) => s[0]!.toUpperCase() + s.slice(1)\nconst options = \u003CT extends string>(values: readonly T[]) => values.map((value) => ({ value, label: cap(value) }))\nconst COLOURS = options(['white', 'black', 'random'] as const)\nconst LEVELS = options(['easy', 'normal', 'hard'] as const)\nconst PACES = options(['slow', 'normal', 'fast'] as const)\nconst COACH = [{ value: false, label: 'Off' }, { value: true, label: 'On' }]\nconst VARIANTS = computed(() => [{ value: 'standard', label: 'Standard', to: BASE }, { value: 'chess960', label: 'Chess960', to: is960.value ? href(n.value) : `${BASE}\u002F960` }])\nconst settingsOpen = ref(false)\nconst settingsSummary = computed(() => [\n  modeLabel.value,\n  mode.value === 'jev' || mode.value === 'simple' ? cap(colour.value) : '',\n  jevPlays.value ? `Jev ${level.value}` : '',\n  coach.value && humanSides.value.length ? 'Coach' : '',\n  auto.value ? cap(speed.value) : '',\n  is960.value ? `Chess960 #${n.value}` : 'Standard',\n].filter(Boolean).join(' · '))\n\u002F\u002F A watch never starts by itself, so Jev is only called for someone who is watching.\nconst paused = ref(true)\nconst idle = computed(() => auto.value && paused.value && !resting.value && !game.plies.value.length && game.ready.value)\n\u002F\u002F a wait of hours is the site's daily budget, and the watch stays paused\nconst resting = ref(false)\nconst spent = ref(false)\nlet restTimer = 0\nfunction rest(seconds: number) {\n  paused.value = true\n  resting.value = true\n  spent.value = seconds > 5 * 60\n  clearTimeout(restTimer)\n  if (!spent.value) restTimer = window.setTimeout(() => { resting.value = false; paused.value = false }, seconds * 1000)\n}\nwatch(paused, (p) => { if (!p) { resting.value = false; clearTimeout(restTimer) } })\nonBeforeUnmount(() => clearTimeout(restTimer))\n\u002F\u002F counted when an engine's move ends a game here, so reloading a finished game never counts it twice\ntype Tally = { a: number; b: number; draws: number }\ntype Watch = 'jev-jev' | 'jev-simple'\nconst SCORE_NAMES: Record\u003CWatch, [string, string]> = { 'jev-jev': ['White', 'Black'], 'jev-simple': ['Jev', 'Engine'] }\nconst isTally = (v: unknown): v is Tally => !!v && typeof v === 'object' && ['a', 'b', 'draws'].every((k) => Number.isInteger((v as Record\u003Cstring, unknown>)[k]))\nconst scores = useStored\u003CRecord\u003CWatch, Tally>>('chessScores', { 'jev-jev': { a: 0, b: 0, draws: 0 }, 'jev-simple': { a: 0, b: 0, draws: 0 } }, (v): v is Record\u003CWatch, Tally> => !!v && typeof v === 'object' && isTally((v as Record\u003Cstring, unknown>)['jev-jev']) && isTally((v as Record\u003Cstring, unknown>)['jev-simple']))\nconst watchKey = computed(() => (auto.value ? (mode.value as Watch) : undefined))\nfunction tally(o: { winner?: 'white' | 'black' } | undefined) {\n  const k = watchKey.value\n  if (!o || !k) return\n  \u002F\u002F read the stored score afresh, so games finished in other tabs are not overwritten\n  const latest = readStore\u003CRecord\u003CWatch, Tally>>('chessScores')\n  const base = latest && isTally(latest[k]) ? latest : scores.value\n  const t = { ...base[k] }\n  if (!o.winner) t.draws++\n  else if (k === 'jev-jev' ? o.winner === 'white' : players.value[o.winner] === 'jev') t.a++\n  else t.b++\n  scores.value = { ...base, [k]: t }\n}\nconst scoreScope = ref\u003C'everyone' | 'browser'>('everyone')\nconst everyone = ref\u003CRecord\u003CWatch, Tally>>()\nasync function fetchScores() { try { everyone.value = await $fetch\u003CRecord\u003CWatch, Tally>>('\u002Fapi\u002Fchess\u002Fscores') } catch {} }\nconst scoreRows = computed(() => {\n  const k = watchKey.value\n  const t = k && (scoreScope.value === 'everyone' ? everyone.value?.[k] : scores.value[k])\n  if (!k || !t) return []\n  return [{ label: SCORE_NAMES[k][0], n: t.a }, { label: SCORE_NAMES[k][1], n: t.b }, { label: 'Draws', n: t.draws }]\n})\nconst games = computed(() => scoreRows.value.reduce((k, r) => k + r.n, 0))\nfunction resetScore() { const k = watchKey.value; if (k) scores.value = { ...scores.value, [k]: { a: 0, b: 0, draws: 0 } } }\nconst level = useStored\u003C'easy' | 'normal' | 'hard'>('chessLevel', 'normal', oneOf('easy', 'normal', 'hard'))\nconst speed = useStored\u003Ckeyof typeof WATCH_SPEEDS>('chessSpeed', 'normal', oneOf('slow', 'normal', 'fast'))\nconst engineTurn = computed(() => players.value[game.turn.value] !== 'human')\nconst thinking = ref\u003CExclude\u003CPlayer, 'human'>>()\nconst decision = ref\u003CEngineDecision>()\nconst considering = ref\u003CEngineDecision['candidates']>()\n\u002F\u002F by ply, so looking back shows what Jev thought at that point\nconst decisions = ref\u003CRecord\u003Cnumber, EngineDecision>>({})\nwatch(() => game.plies.value.length, (len) => {\n  if (Object.keys(decisions.value).some((k) => Number(k) >= len)) decisions.value = Object.fromEntries(Object.entries(decisions.value).filter(([k]) => Number(k) \u003C len))\n})\n\u002F\u002F Jev's latest up to the move shown, so the engine's replies in a watch keep what Jev last thought\nconst shownDecision = computed(() => {\n  for (let k = shown.value - 1; k >= 0; k--) if (decisions.value[k]?.engine === 'jev') return decisions.value[k]\n  return undefined\n})\nconst toArrows = (cands?: EngineDecision['candidates']) => cands?.flatMap((c) => (c.uci ? [{ from: square(c.uci.slice(0, 2)), to: square(c.uci.slice(2, 4)), p: c.p }] : []))\nconst arrows = computed(() => (viewing.value ? toArrows(shownDecision.value?.candidates) : toArrows(considering.value)))\nconst square = (name: string) => 'abcdefgh'.indexOf(name[0]!) + 8 * (Number(name[1]) - 1)\nconst playable = computed(() => game.ready.value && !game.outcome.value && !engineTurn.value && !thinking.value)\nconst premove = ref\u003C{ from: number; to: number }>()\n\u002F\u002F `view` is the move shown (0 is the start), null is live. Looking back is read-only, and nothing plays meanwhile.\nconst view = ref\u003Cnumber | null>(null)\nconst shown = computed(() => view.value ?? game.plies.value.length)\nconst viewing = computed(() => view.value !== null)\nfunction goTo(k: number | null) { view.value = k === null ? null : Math.max(0, Math.min(game.plies.value.length, k)) }\nconst shownLast = computed(() => (viewing.value ? game.plies.value[shown.value - 1] : game.plies.value.at(-1)))\ntype SavedGame = { n: number; moves: string[] }\n\u002F\u002F Per tab, so two tabs never overwrite each other's game; the latest also goes to localStorage for a new tab.\nlet restored = false\n\u002F\u002F A shared game (?g=e2e4.e7e5…) opens looking back, so no engine moves until Live.\nconst UCI = \u002F^[a-h][1-8][a-h][1-8][qrbn]?$\u002F\nonMounted(async () => {\n  const shared = typeof route.query.g === 'string' ? route.query.g.split('.').filter((u) => UCI.test(u)) : []\n  const saved = readSession\u003CSavedGame>('chessGame') ?? readStore\u003CSavedGame>('chessGame')\n  await game.load()\n  if (shared.length) {\n    game.replay(shared)\n    view.value = game.plies.value.length\n    void navigateTo({ path: route.path, query: {} }, { replace: true })\n  } else if (saved?.n === n.value && Array.isArray(saved.moves)) game.replay(saved.moves)\n  restored = true\n})\nwatch(game.moves, (moves) => {\n  if (!restored) return\n  const g: SavedGame = { n: n.value, moves }\n  writeSession('chessGame', g)\n  writeStore('chessGame', g)\n})\nfunction move(m: Parameters\u003Ctypeof game.play>[0]) { premove.value = undefined; game.play(m) }\n\nconst yourTurn = computed(() => players.value[game.turn.value] === 'human' && !game.outcome.value && view.value === null)\nconst boardGrid = () => document.querySelector('.board__grid')\nuseSiteTool(() => ({\n  name: 'chess_move',\n  description: 'Play a chess move for the person’s side, when it is their turn',\n  arg: { name: 'move', description: 'The move, in SAN (e4, Nf3, O-O)', values: yourTurn.value ? game.legal.value.map((l) => ({ value: l.san, label: l.san })) : [] },\n  doing: (label) => `playing ${label}`,\n  target: boardGrid,\n  run: (value) => {\n    const l = game.legal.value.find((x) => x.san === value)\n    if (!l) return\n    move(l.move)\n    return game.outcome.value ? `${game.outcome.value.reason}.` : `${cap(game.turn.value)} to move.`\n  },\n}))\nuseSiteTool(() => ({\n  name: 'chess_state',\n  description: 'Read the chess game: who plays, whose turn, the position (FEN), the moves so far and the legal moves',\n  doing: () => 'reading the board',\n  run: () => [\n    `Mode: ${modeLabel.value}.`,\n    `${cap(game.turn.value)} to move${yourTurn.value ? ' (the person’s turn)' : ''}.`,\n    `FEN: ${game.fen.value}`,\n    `Moves: ${game.plies.value.map((p) => p.san).join(' ') || 'none yet'}`,\n    `Legal: ${game.legal.value.map((l) => l.san).join(' ')}`,\n  ].join('\\n'),\n  readOnly: true,\n  agentOnly: true,\n}))\nuseSiteTool(() => ({\n  name: 'chess_mode',\n  description: 'Choose who plays: watch Jev play itself or the engine, play Jev, play the simple engine, or play a friend',\n  arg: { name: 'mode', description: 'Who plays', values: MODES.map((m) => ({ value: m.value, label: m.label })) },\n  doing: (label) => `choosing “${label}”`,\n  target: () => document.querySelector('[aria-label=\"What to do\"]'),\n  \u002F\u002F asking to watch is pressing Play\n  run: (value) => { choose(value as Mode); if (auto.value) paused.value = false },\n  readOnly: true,\n}))\nuseSiteTool(() => ({\n  name: 'chess_flip',\n  description: 'Turn the chess board around',\n  doing: () => 'flipping the board',\n  target: boardGrid,\n  run: () => { flipped.value = !flipped.value },\n  readOnly: true,\n}))\nuseSiteTool(() => ({\n  name: 'chess_coach',\n  description: 'Turn the chess coach (Stockfish, which suggests moves) on or off',\n  arg: { name: 'state', description: 'On or off', values: [{ value: 'on', label: 'on' }, { value: 'off', label: 'off' }] },\n  doing: (label) => `turning the coach ${label}`,\n  run: (value) => { coach.value = value === 'on' },\n  readOnly: true,\n}))\nuseSiteTool(() => ({\n  name: 'chess_hint',\n  description: 'Ask the coach (Stockfish) which move it would play now, on the person’s turn',\n  doing: () => 'asking the coach',\n  target: boardGrid,\n  run: async () => {\n    if (!yourTurn.value) return 'It isn’t your move.'\n    const k = game.plies.value.length\n    coach.value = true\n    await until(() => scored.value[k]).toBeTruthy({ timeout: 10_000 })\n    const best = scored.value[k]?.best\n    return best ? fill(companion.coach.hint, { best: game.sanAt(k, best) }) : 'The coach has no answer yet.'\n  },\n  readOnly: true,\n}))\nuseSiteTool(() => ({\n  name: 'chess_new_game',\n  description: 'Start a new chess game',\n  doing: () => 'starting a new game',\n  target: boardGrid,\n  run: newGame,\n  readOnly: true,\n}))\n\n\u002F\u002F Only a game played out on this page is kept: one opened from a link or restored after a reload is not.\n\u002F\u002F The outcome is read after the moves' watcher has run (flush: post), so `playedHere` is current.\nconst kept = ref\u003Cstring>()\nlet playedHere = false\nlet times: number[] = [], lastMoveAt = 0\nwatch(game.moves, (now, before) => {\n  playedHere = restored && now.length === (before?.length ?? 0) + 1\n  if (playedHere) { times = [...times.slice(0, now.length - 1), lastMoveAt ? Date.now() - lastMoveAt : 0]; lastMoveAt = Date.now() } else if (now.length \u003C times.length) times = times.slice(0, now.length)\n  if (!now.length) { times = []; lastMoveAt = Date.now() }\n  if (now.length \u003C (before?.length ?? 0)) kept.value = undefined\n})\nwatch(game.outcome, async (o) => {\n  if (!o || !playedHere || kept.value) return\n  const { white, black } = players.value\n  try {\n    kept.value = (await $fetch\u003C{ id: string }>('\u002Fapi\u002Fchess\u002Fgames', { method: 'POST', body: { n: n.value, moves: game.moves.value, mode: mode.value, white, black, device: deviceId(), times: times.length === game.moves.value.length ? times : undefined } })).id\n    track('chess_game_end', { mode: mode.value, result: o.winner ?? 'draw', reason: o.reason, plies: game.moves.value.length, variant: is960.value ? 'chess960' : 'chess' })\n    if (railTab.value === 'score') void fetchScores()\n  } catch {}\n}, { flush: 'post' })\n\n\u002F\u002F a new game moves it on, so a turn still waiting on an old answer ends quietly\nlet turn = 0\nasync function runEngine() {\n  const side = players.value[game.turn.value]\n  if (side === 'human' || game.outcome.value || !game.ready.value || thinking.value || viewing.value || (auto.value && paused.value)) return\n  const mine = ++turn\n  thinking.value = side\n  const d = await game.engineMove(side, WATCH_SPEEDS[speed.value], level.value, (d) => { considering.value = d.candidates }, !auto.value)\n  if (mine !== turn) return\n  considering.value = undefined\n  thinking.value = undefined\n  if (d?.resting) { rest(d.resting); return }\n  if (d) { decision.value = d; decisions.value = { ...decisions.value, [game.plies.value.length - 1]: d } }\n  if (d?.engine === 'jev' && !d.forced) {\n    jevTimes.value = [...jevTimes.value.slice(1 - SPARK), d.ms]\n    jevTimeBy.value = { ...jevTimeBy.value, [other(game.turn.value)]: d.ms }\n  }\n  if (d?.engine === 'jev' && d.candidates?.length) jevNotes.value = { ...jevNotes.value, [game.plies.value.length - 1]: `Jev: ${d.candidates.slice(0, 3).map((c) => `${c.san} ${pct(c.p)}`).join(', ')}` }\n  if (d && auto.value) tally(game.outcome.value)\n  if (d?.reading?.eval !== undefined && !coach.value) evalShare.value = d.reading.eval\n  if (d?.engine === 'jev') sayPlan(d.reading?.plan)\n  if (d?.engine === 'jev' && players.value[game.turn.value] === 'human') {\n    const atPly = game.plies.value.length\n    void game.predictReply().then((g) => { if (g && game.plies.value.length === atPly) guess.value = { atPly, ...g } })\n  }\n  const pm = premove.value\n  premove.value = undefined\n  if (pm && players.value[game.turn.value] === 'human') {\n    const m = game.targets(pm.from).get(pm.to)\n    if (m) game.play(game.needsPromotion(m) ? { ...m, promotion: 'queen' } : m)\n  }\n  \u002F\u002F the move above re-ran the watcher while this turn still counted as thinking\n  void nextTick(runEngine)\n}\nwatch([engineTurn, () => game.plies.value.length, paused, () => game.ready.value, players, viewing], () => { void runEngine() })\nfunction undo() {\n  premove.value = undefined\n  if (auto.value) { paused.value = true; game.undo(); return }\n  game.undo()\n  while (game.plies.value.length && players.value[game.turn.value] !== 'human') game.undo()\n}\nfunction newGame() { track('chess_new_game', { mode: mode.value, variant: is960.value ? 'chess960' : 'chess' }); turn++; seat(); view.value = null; jevTimeBy.value = {}; scored.value = {}; verdict.value = undefined; jevNotes.value = {}; jevTimes.value = []; lastPlan = undefined; planAt = -PLAN_GAP; thinking.value = undefined; considering.value = undefined; premove.value = undefined; decision.value = undefined; decisions.value = {}; evalShare.value = undefined; guess.value = undefined; reveal.value = undefined; reviewing.value = false; if (auto.value) paused.value = true; game.reset(); void nextTick(runEngine); void nextTick(coachTurn) }\n\nconst coach = useStored('chessCoach', false, oneOf(true, false))\nconst stockfish = useStockfish()\nconst scored = ref\u003CRecord\u003Cnumber, Analysis>>({})\nconst verdict = ref\u003CCoachVerdict>()\nconst coachThinking = ref(false)\nconst GRADES: [number, string][] = [[20, 'Best'], [50, 'Good'], [100, 'Inaccuracy'], [250, 'Mistake'], [Infinity, 'Blunder']]\nasync function coachTurn() {\n  if (!coach.value || !game.ready.value || viewing.value) return\n  const k = game.plies.value.length, key = game.moves.value.join('.')\n  if (!scored.value[k]) {\n    coachThinking.value = true\n    const a = await stockfish.analyse(game.fenAt(k))\n    coachThinking.value = false\n    if (!a || game.moves.value.join('.') !== key) return\n    scored.value = { ...scored.value, [k]: a }\n  }\n  const now = scored.value[k]!\n  evalShare.value = chancesFromCp(now.cp)\n  const ply = game.plies.value[k - 1], before = scored.value[k - 1]\n  if (!ply || !before || verdict.value?.ply === k - 1) return\n  const mover = k % 2 === 1 ? 'white' : 'black'\n  if (players.value[mover] !== 'human') return\n  const sign = mover === 'white' ? 1 : -1\n  const loss = Math.max(0, sign * (before.cp - now.cp))\n  const bestUci = before.best, playedUci = game.moves.value[k - 1]\n  const grade = bestUci === playedUci ? 'Best' : GRADES.find(([max]) => loss \u003C= max)![1]\n  const v: CoachVerdict = { ply: k - 1, san: ply.san, grade, loss, best: bestUci && bestUci !== playedUci ? game.sanAt(k - 1, bestUci) : undefined }\n  verdict.value = v\n  if (grade === 'Best' || grade === 'Good') return coachSays(v)\n  const r = await $fetch\u003C{ label?: string; tip?: string }>('\u002Fapi\u002Fchess\u002Fcoach', { method: 'POST', body: { fen: game.fenAt(k - 1), played: ply.san, best: v.best, loss, grade } }).catch(() => undefined)\n  \u002F\u002F a ref holds a reactive copy, so compare by move, not by object\n  if (verdict.value?.ply !== v.ply || game.moves.value.length !== k) return\n  if (r?.label) verdict.value = { ...v, lesson: r.label, tip: r.tip }\n  coachSays(verdict.value)\n}\n\u002F\u002F Jevvie says Jev's plan when it changes, not more than once every few moves, and not over the coach\nconst PLAN_GAP = 6\nlet lastPlan: string | undefined, planAt = -PLAN_GAP\nfunction sayPlan(plan?: string) {\n  const lines = plan && companion.plans[plan as keyof typeof companion.plans]\n  const at = game.plies.value.length\n  if (!lines || plan === lastPlan || at - planAt \u003C PLAN_GAP || coach.value) return\n  lastPlan = plan; planAt = at\n  jevvieSay({ text: pickLine(lines), mood: plan === 'attack' ? 'surprised' : 'think' })\n}\nconst COACH_FACE = { Best: ['love', 'jump'], Good: ['happy'], Inaccuracy: ['think'], Mistake: ['confused'], Blunder: ['surprised'], mate: ['surprised'] } as const\nfunction coachSays(v: CoachVerdict) {\n  const key = v.loss >= 5000 ? 'mate' : (v.grade as keyof typeof companion.coach)\n  const lines = companion.coach[key]\n  if (!Array.isArray(lines)) return\n  const pawns = (v.loss \u002F 100).toFixed(1)\n  const text = fill(pickLine(lines), { san: v.san, best: v.best ?? '', pawns: `${pawns} pawn${pawns === '1.0' ? '' : 's'}` })\n  const [mood, trick] = COACH_FACE[key as keyof typeof COACH_FACE] ?? ['happy']\n  jevvieSay({ text: v.tip ? `${text} ${v.tip}` : text, mood, trick })\n}\nwatch([coach, () => game.plies.value.length, () => game.ready.value, viewing], () => { void coachTurn() })\nwatch(coach, (on) => { if (!on) { stockfish.stop(); verdict.value = undefined; scored.value = {} } })\n\nconst evalShare = ref\u003Cnumber>()\n\u002F\u002F the coach's Stockfish score has no history\nconst evalShown = computed(() => (viewing.value && !coach.value ? shownDecision.value?.reading?.eval : evalShare.value))\nconst guess = ref\u003C{ atPly: number; san: string; p: number }>()\nconst reveal = ref\u003C{ expected: string; p: number; played: string; hit: boolean }>()\nwatch(() => game.plies.value.length, (len) => {\n  const g = guess.value\n  if (g && len === g.atPly + 1) {\n    const played = game.plies.value.at(-1)!.san\n    reveal.value = { expected: g.san, p: g.p, played, hit: played === g.san }\n  }\n  if (!g || len !== g.atPly) guess.value = undefined\n})\nconst pct = (p?: number) => `${Math.round((p ?? 0) * 100)}%`\n\u002F\u002F always five rows, so nothing below the panel moves\nconst jevDecision = computed(() => (shownDecision.value?.engine === 'jev' ? shownDecision.value : undefined))\nconst FORCED = { legal: 'its only legal move', safe: 'the only move that loses nothing, so it was not asked', mate: 'the rules found mate, so it was not asked' } as const\nconst FORCED_NOTE = { legal: 'Its only legal move', safe: 'Its only safe move', mate: 'Mate, found by the rules' } as const\nconst narration = computed(() => {\n  const d = shownDecision.value\n  if (!d || d.engine !== 'jev' || !d.candidates?.length) return\n  if (d.forced) return `Jev played ${d.san}: ${FORCED[d.forced]}.`\n  const share = d.candidates.find((c) => c.san === d.san)?.p ?? 0\n  const c = d.confidence ?? 0\n  const mood = c \u003C 0.25 ? 'and it was torn' : c \u003C 0.55 ? 'and it leaned that way' : 'and it was sure'\n  const offered = d.offered && d.offered \u003C (d.options ?? 0) ? ` It was offered the ${d.offered} moves that lose nothing.` : ''\n  return `Jev played ${d.san}: ${pct(share)} of its belief went there, ${mood} (${pct(c)} confident overall).${offered}`\n})\nconst readingLine = computed(() => {\n  const r = shownDecision.value?.reading\n  if (!r) return\n  const sharp = r.sharpness === undefined ? undefined : r.sharpness \u003C 0.34 ? 'quiet' : r.sharpness \u003C 0.67 ? 'tense' : 'sharp'\n  return [\n    r.kingRisk !== undefined ? `King risk ${pct(r.kingRisk)}` : '',\n    sharp ? `Position ${sharp}` : '',\n    r.plan ? `Plan ${r.plan}` : '',\n  ].filter(Boolean)\n})\nconst jevNotes = ref\u003CRecord\u003Cnumber, string>>({})\nconst PLAYER_NAME: Record\u003CPlayer, string> = { human: 'You', jev: 'Jev', simple: 'Simple engine' }\nconst jevTimeBy = ref\u003C{ white?: number; black?: number }>({})\nconst seatLine = (c: 'white' | 'black') => {\n  const who = players.value[c]\n  const lead = (balance.value.at(-1) ?? 0) * (c === 'white' ? 1 : -1)\n  return {\n    colour: c,\n    name: mode.value === 'friend' ? cap(c) : `${PLAYER_NAME[who]} · ${cap(c)}`,\n    toMove: !game.outcome.value && game.turn.value === c,\n    thinking: thinking.value !== undefined && game.turn.value === c,\n    note: [lead > 0 ? `+${lead}` : '', who === 'jev' && jevTimeBy.value[c] ? `${jevTimeBy.value[c]} ms` : ''].filter(Boolean).join(' · '),\n  }\n}\nconst seats = computed(() => (flipped.value ? { top: seatLine('white'), bottom: seatLine('black') } : { top: seatLine('black'), bottom: seatLine('white') }))\nconst pgn = computed(() => game.pgnText({\n  marks: story.value?.marks,\n  comments: jevNotes.value,\n  tags: {\n    Event: is960.value ? `Chess960 #${n.value}` : 'Chess',\n    Site: 'chriswijnia.com',\n    Date: new Date().toISOString().slice(0, 10).replaceAll('-', '.'),\n    White: mode.value === 'friend' ? 'White' : PLAYER_NAME[players.value.white],\n    Black: mode.value === 'friend' ? 'Black' : PLAYER_NAME[players.value.black],\n  },\n}))\nconst reviewing = ref(false)\nwatch(() => game.plies.value.length, () => { reviewing.value = false })\nconst balance = computed(() => {\n  const plies = game.plies.value, now = game.position.value\n  return now ? [...plies.map((p) => materialBalance(p.before)), materialBalance(now)] : []\n})\nconst story = computed(() => (balance.value.length ? materialStory(balance.value, game.plies.value.map((p) => p.san), game.outcome.value?.winner) : undefined))\nconst jevTimes = ref\u003Cnumber[]>([])\nconst SPARK = 24\nconst over = computed(() => {\n  const o = game.outcome.value\n  if (!o) return\n  const who = (c: 'white' | 'black') => (players.value[c] === 'human' ? cap(c) : `${PLAYER_NAME[players.value[c]]} (${cap(c)})`)\n  const line = !o.winner ? 'Nobody wins' : `${who(o.winner)} wins`\n  return { reason: o.reason, score: !o.winner ? '½–½' : o.winner === 'white' ? '1–0' : '0–1', line, summary: story.value?.summary }\n})\nconst status = computed(() => {\n  const o = game.outcome.value\n  if (!game.ready.value) return 'Setting up the rules…'\n  if (viewing.value) return `Move ${Math.ceil(shown.value \u002F 2)} of ${Math.ceil(game.plies.value.length \u002F 2)}, looking back.`\n  if (o) return o.winner ? `${o.reason}. ${cap(o.winner)} wins.` : `${o.reason}. Draw.`\n  const side = cap(game.turn.value)\n  if (thinking.value) return `${thinking.value === 'jev' ? 'Jev' : 'Simple'} thinking…`\n  if (resting.value && spent.value) return 'Jev has used today\\'s budget. Back after midnight (UTC).'\n  if (resting.value) return 'Jev is resting a moment. The watch goes on by itself.'\n  if (idle.value) return 'Ready: press Play.'\n  if (auto.value && paused.value) return 'Paused.'\n  return `${side} to move${game.check.value !== undefined ? ', in check' : ''}.`\n})\nconst pieces = computed(() => setup(rank.value))\nconst files = computed(() => (flipped.value ? [...'hgfedcba'] : [...'abcdefgh']))\nconst ranks = computed(() => (flipped.value ? [...'12345678'] : [...'87654321']))\n\nconst humanSides = computed(() => (['white', 'black'] as const).filter((c) => players.value[c] === 'human'))\n\u002F\u002F one rail: playing first, then what a game leaves behind, then how the board looks\nconst RAIL_TABS = computed(() => [\n  { id: 'play', label: 'Play' },\n  ...(humanSides.value.length ? [{ id: 'review', label: 'Review' }] : []),\n  ...(auto.value ? [{ id: 'score', label: 'Score' }] : []),\n  { id: 'export', label: 'Export' },\n  ...(is960.value ? [{ id: 'setup', label: 'Setup' }] : []),\n  { id: 'set', label: 'Set' },\n])\ntype ReviewItem = { ply: number; san: string; type: string; label: string; advice: string }\nconst review = ref\u003C{ key: string; items: ReviewItem[] }>()\nconst reviewLoading = ref(false)\nconst reviewKey = () => `${n.value}:${humanSides.value.join(',')}:${game.moves.value.join('.')}`\nasync function loadReview() {\n  const moves = game.moves.value, sides = humanSides.value, key = reviewKey()\n  if (!moves.length || !sides.length || review.value?.key === key) return\n  reviewLoading.value = true\n  try {\n    const r = await $fetch\u003C{ items: ReviewItem[] }>('\u002Fapi\u002Fchess\u002Freview', { method: 'POST', body: { start: startFen(rank.value), moves, sides } })\n    if (reviewKey() === key) review.value = { key, items: r.items }\n  } catch {} finally { reviewLoading.value = false }\n}\nconst railTab = ref\u003Cstring>('play')\nwatch([railTab, () => game.moves.value.length], () => { if (railTab.value === 'review') void loadReview() })\nwatch(railTab, (t) => { if (t === 'score') void fetchScores() })\nconst EXPORTS = [{ value: 'pgn', label: 'PGN' }, { value: 'fen', label: 'FEN' }] as const\nconst exportKind = ref\u003C'pgn' | 'fen'>('pgn')\nconst exported = computed(() => {\n  if (railTab.value !== 'export') return undefined\n  if (exportKind.value === 'pgn' && pgn.value) return { label: 'PGN', value: pgn.value }\n  return { label: 'FEN', value: game.fen.value }\n})\nconst copied = refAutoReset('', 1600)\nasync function copy(label: string, value: string) {\n  try { await navigator.clipboard.writeText(value); copied.value = label } catch { copied.value = '' }\n}\n\nconst draft = ref(String(n.value))\nwatch(n, (v) => { draft.value = String(v) })\nconst invalid = ref(false)\nconst go = () => {\n  const next = Number(draft.value)\n  invalid.value = !isPositionId(next)\n  if (!invalid.value) void navigateTo(href(next))\n}\nconst random = () => navigateTo(random960())\n\nconst { canonical } = usePageSeo({\n  title: () => (is960.value ? `Chess960 #${n.value}: ${rank.value}` : 'Chess'),\n  description: () => (is960.value\n    ? `Chess960 starting position ${n.value} of 960: ${rank.value}. Play Jev, an engine or a friend from it, or watch Jev play.`\n    : 'Play chess against Jev, TypeSafe AI’s System One model, a simple engine or a friend, or watch Jev play itself, with its thinking on show.'),\n  image: '\u002Flab\u002Fchess.png',\n  screenshot: true,\n})\nconst keptUrl = computed(() => kept.value && new URL(`\u002Fg\u002F${kept.value}`, useRuntimeConfig().public.siteUrl).href)\nconst url = computed(() => keptUrl.value || (game.moves.value.length ? `${canonical.value}?g=${game.moves.value.join('.')}` : canonical.value))\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003Carticle class=\"lab-stage bg-paper\">\n      \u003Cdiv class=\"chess\">\n        \u003CWin :title=\"boardTitle\" as=\"figure\" label=\"Board\" class=\"board-win\" data-shot :draggable=\"false\" :minimizable=\"false\">\n          \u003Ctemplate #meta>\n            \u003CGlyphStatus v-if=\"!game.ready.value\" active label=\"Setting up the rules\" set=\"shade\" \u002F>\n            \u003CGlyphStatus v-else-if=\"thinking\" active :label=\"`${thinking === 'jev' ? 'Jev' : 'Simple'} thinking`\" \u002F>\n            \u003Ctemplate v-else>{{ status }}\u003C\u002Ftemplate>\n          \u003C\u002Ftemplate>\n          \u003Cdiv class=\"board\" :class=\"{ 'is-flipped': flipped }\">\n            \u003Cp v-for=\"(s, at) in seats\" :key=\"at\" class=\"board__seat mono-label\" :class=\"[`board__seat--${at}`, { 'is-to-move': s.toMove }]\">\n              \u003Cspan class=\"board__seat-mark\" aria-hidden=\"true\">\u003CGlyphSpinner v-if=\"s.thinking\" \u002F>\u003Ctemplate v-else>{{ s.toMove ? '■' : '□' }}\u003C\u002Ftemplate>\u003C\u002Fspan>\n              \u003Cspan class=\"board__seat-name\">{{ s.name }}\u003Cspan v-if=\"s.toMove\" class=\"visually-hidden\">, to move\u003C\u002Fspan>\u003C\u002Fspan>\n              \u003Cspan class=\"board__seat-note\">{{ s.note }}\u003C\u002Fspan>\n            \u003C\u002Fp>\n            \u003Cspan class=\"board__ranks mono-label\" aria-hidden=\"true\">\u003Cspan v-for=\"r in ranks\" :key=\"r\">{{ r }}\u003C\u002Fspan>\u003C\u002Fspan>\n            \u003CChessBoard\n              class=\"board__squares\" :squares=\"viewing ? game.squaresAt(shown) : game.squares.value\" :font=\"font\" :theme=\"theme\" :flipped=\"flipped\" :interactive=\"playable && !viewing\"\n              :targets=\"game.targets\" :needs-promotion=\"game.needsPromotion\" :check=\"viewing ? game.checkAt(shown) : game.check.value\" :last=\"shownLast\" :ply-count=\"shown\"\n              :premove-color=\"thinking ? humanSides[0] : undefined\" :premove=\"premove\" :arrows=\"arrows\"\n              @move=\"move\" @premove=\"premove = $event\" @cancel-premove=\"premove = undefined\"\n            \u002F>\n            \u003Cdiv v-if=\"idle && !viewing\" class=\"over start\">\n              \u003CBtn variant=\"amber\" @click=\"paused = false\">{{ modeLabel }} ►\u003C\u002FBtn>\n            \u003C\u002Fdiv>\n            \u003Cdiv v-if=\"over && !reviewing && !viewing\" class=\"over\" role=\"status\">\n              \u003CChessGameOver :over=\"over\" :kept=\"kept\" :kept-url=\"keptUrl\" @new-game=\"newGame\" @hide=\"reviewing = true\" \u002F>\n            \u003C\u002Fdiv>\n            \u003Cspan v-if=\"evalShown !== undefined\" class=\"board__eval\" role=\"img\" :aria-label=\"`Jev's reading: White ${pct(evalShown)}`\" :style=\"{ '--white': flipped ? 1 - evalShown : evalShown }\" \u002F>\n            \u003Cspan class=\"board__files mono-label\" aria-hidden=\"true\">\u003Cspan v-for=\"f in files\" :key=\"f\">{{ f }}\u003C\u002Fspan>\u003C\u002Fspan>\n          \u003C\u002Fdiv>\n        \u003C\u002FWin>\n        \u003Cp class=\"visually-hidden\" role=\"status\" aria-live=\"polite\">{{ status }}\u003C\u002Fp>\n\n        \u003CWin v-model:tab=\"railTab\" title=\"CW\u002FGAME\" as=\"section\" label=\"Game\" :tabs=\"RAIL_TABS\" persist=\"chess-rail\" :draggable=\"false\" :minimizable=\"false\" class=\"rail\">\n          \u003Ctemplate #meta>\n            \u003Cbutton v-if=\"exported\" type=\"button\" class=\"bar-btn bare\" @click=\"copy(exported.label, exported.value)\">{{ copied === exported.label ? 'Copied' : 'Copy' }}\u003C\u002Fbutton>\n            \u003Cbutton v-else-if=\"railTab === 'score' && scoreScope === 'browser'\" type=\"button\" class=\"bar-btn bare\" :disabled=\"!games\" @click=\"resetScore\">Reset\u003C\u002Fbutton>\n            \u003Cbutton v-else-if=\"railTab === 'setup'\" type=\"button\" class=\"bar-btn bare\" @click=\"copy('Back rank', rank)\">{{ copied === 'Back rank' ? 'Copied' : rank }}\u003C\u002Fbutton>\n            \u003Ctemplate v-else-if=\"jevTimes.length\">\u003CGlyphSparkline :values=\"jevTimes\" :min=\"0\" label=\"Jev's time per move\" live \u002F> {{ jevTimes.at(-1) }} ms\u003C\u002Ftemplate>\n          \u003C\u002Ftemplate>\n          \u003Ctemplate #default=\"{ tab }\">\n            \u003Ctemplate v-if=\"tab === 'set'\">\n              \u003Cul class=\"sets\" role=\"radiogroup\" aria-label=\"Chess set\">\n                \u003Cli v-for=\"(s, id) in CHESS_SETS\" :key=\"id\">\n                  \u003Cbutton type=\"button\" role=\"radio\" class=\"sets__one bare\" :aria-checked=\"set === id\" @click=\"set = id\">\n                    \u003Cspan class=\"sets__sample\" :style=\"{ ...swatch(s.theme), fontFamily: `'Chess ${s.font}', var(--font-mono)` }\">{{ squareGlyph('N', true, s.font) }}{{ squareGlyph('q', false, s.font) }}\u003C\u002Fspan>\n                    \u003Cspan class=\"mono-label\">{{ s.name }}\u003C\u002Fspan>\n                  \u003C\u002Fbutton>\n                \u003C\u002Fli>\n              \u003C\u002Ful>\n            \u003C\u002Ftemplate>\n            \u003Ctemplate v-else-if=\"tab === 'setup' && is960\">\n              \u003Ctable class=\"setup mono-label\">\n                \u003Ccaption class=\"visually-hidden\">Where each piece goes\u003C\u002Fcaption>\n                \u003Cthead>\u003Ctr>\u003Cth scope=\"col\" \u002F>\u003Cth scope=\"col\">Piece\u003C\u002Fth>\u003Cth scope=\"col\">White\u003C\u002Fth>\u003Cth scope=\"col\">Black\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\n                \u003Ctbody>\n                  \u003Ctr v-for=\"p in pieces\" :key=\"p.white\">\n                    \u003Ctd class=\"setup__glyph\" aria-hidden=\"true\" :style=\"{ fontFamily: family }\">{{ pieceGlyph(p.piece, font) }}\u003C\u002Ftd>\n                    \u003Ctd>{{ p.name }}\u003C\u002Ftd>\n                    \u003Ctd>{{ p.white }}\u003C\u002Ftd>\n                    \u003Ctd>{{ p.black }}\u003C\u002Ftd>\n                  \u003C\u002Ftr>\n                \u003C\u002Ftbody>\n              \u003C\u002Ftable>\n            \u003C\u002Ftemplate>\n            \u003Ctemplate v-else-if=\"tab === 'score' && watchKey\">\n              \u003CChessScore v-model:scope=\"scoreScope\" :rows=\"scoreRows\" :loaded=\"!!everyone\" \u002F>\n            \u003C\u002Ftemplate>\n            \u003Ctemplate v-else-if=\"tab === 'review'\">\n              \u003Cp v-if=\"!game.plies.value.length\" class=\"panel__note mono-label\">Play a few moves. The review looks at yours: each mistake, what kind, and what was better.\u003C\u002Fp>\n              \u003Cp v-else-if=\"reviewLoading && !review\" class=\"panel__note mono-label\">\u003CGlyphSpinner \u002F> Reviewing your moves\u003C\u002Fp>\n              \u003Col v-else-if=\"review?.items.length\" class=\"review mono-label\" data-lenis-prevent>\n                \u003Cli v-for=\"it in review.items\" :key=\"it.ply\">\n                  \u003Cbutton type=\"button\" class=\"play__move bare\" @click=\"goTo(it.ply + 1); railTab = 'play'\">{{ Math.floor(it.ply \u002F 2) + 1 }}{{ it.ply % 2 ? '…' : '.' }} {{ it.san }}\u003C\u002Fbutton>\n                  \u003Cspan class=\"review__type\">{{ it.label }}\u003C\u002Fspan>\n                  \u003Cspan class=\"review__advice\">{{ it.advice }}\u003C\u002Fspan>\n                \u003C\u002Fli>\n              \u003C\u002Fol>\n              \u003Cp v-else-if=\"review\" class=\"panel__note mono-label\">No mistakes in your moves so far: nothing left hanging, no mate missed or allowed.\u003C\u002Fp>\n            \u003C\u002Ftemplate>\n            \u003Ctemplate v-else-if=\"tab === 'export'\">\n              \u003CChessToggle v-model=\"exportKind\" :options=\"EXPORTS\" label=\"Export as\" \u002F>\n              \u003CCodeView v-if=\"exported?.label === 'PGN'\" :html=\"pgnHtml(exported.value)\" theme=\"light\" :padded=\"false\" wrap class=\"export__pgn\" \u002F>\n              \u003Cpre v-else-if=\"exported\" class=\"export__text mono-label\">{{ exported.value }}\u003C\u002Fpre>\n              \u003Cspan class=\"visually-hidden\" aria-live=\"polite\">{{ copied ? `${copied} copied to clipboard` : '' }}\u003C\u002Fspan>\n            \u003C\u002Ftemplate>\n            \u003Ctemplate v-else>\n              \u003Cbutton type=\"button\" class=\"game__summary mono-label\" :aria-expanded=\"settingsOpen\" aria-controls=\"chess-settings\" @click=\"settingsOpen = !settingsOpen\">\n                \u003Cspan>{{ settingsSummary }}\u003C\u002Fspan>\u003Cspan aria-hidden=\"true\">{{ settingsOpen ? '▲' : '▼' }}\u003C\u002Fspan>\n              \u003C\u002Fbutton>\n              \u003Cdiv id=\"chess-settings\" class=\"game__settings\" :class=\"{ 'is-open': settingsOpen }\">\n                \u003Clabel class=\"mode mono-label\">\n                  \u003Cspan class=\"visually-hidden\">What to do\u003C\u002Fspan>\n                  \u003Cselect :value=\"mode\" class=\"mode__select\" @change=\"choose(($event.target as HTMLSelectElement).value as Mode)\">\n                    \u003Coption v-for=\"m in MODES\" :key=\"m.value\" :value=\"m.value\">{{ m.label }} · {{ m.note }}\u003C\u002Foption>\n                  \u003C\u002Fselect>\n                  \u003Cspan class=\"mode__caret\" aria-hidden=\"true\">▾\u003C\u002Fspan>\n                \u003C\u002Flabel>\n                \u003Cdiv class=\"fields mono-label\">\n                  \u003Cp v-if=\"mode === 'jev' || mode === 'simple'\" class=\"seed\">\u003Cspan>You play\u003C\u002Fspan>\u003CChessToggle v-model=\"colour\" :options=\"COLOURS\" label=\"You play\" @pick=\"newGame\" \u002F>\u003C\u002Fp>\n                  \u003Cp v-if=\"jevPlays\" class=\"seed\">\u003Cspan>Jev’s level\u003C\u002Fspan>\u003CChessToggle v-model=\"level\" :options=\"LEVELS\" label=\"Jev’s level\" \u002F>\u003C\u002Fp>\n                  \u003Cp v-if=\"auto\" class=\"seed\">\u003Cspan>Speed\u003C\u002Fspan>\u003CChessToggle v-model=\"speed\" :options=\"PACES\" label=\"Speed\" \u002F>\u003C\u002Fp>\n                  \u003Cp class=\"seed\">\u003Cspan>Board\u003C\u002Fspan>\u003CChessToggle :model-value=\"is960 ? 'chess960' : 'standard'\" :options=\"VARIANTS\" label=\"Variant\" \u002F>\u003C\u002Fp>\n                  \u003Cp v-if=\"is960\" class=\"seed\">\n                    \u003Clabel for=\"chess-n\">Position\u003C\u002Flabel>\n                    \u003Cspan class=\"pos\">\n                      \u003CNuxtLink :to=\"step(-1)\" class=\"pos__step\" aria-label=\"Previous position\">◄\u003C\u002FNuxtLink>\n                      \u003Cinput id=\"chess-n\" v-model=\"draft\" class=\"seed__input\" inputmode=\"numeric\" maxlength=\"3\" :aria-invalid=\"invalid\" @keydown.enter.prevent=\"go\" @blur=\"draft = String(n); invalid = false\">\n                      \u003CNuxtLink :to=\"step(1)\" class=\"pos__step\" aria-label=\"Next position\">►\u003C\u002FNuxtLink>\n                      \u003Cbutton type=\"button\" class=\"pos__step bare\" aria-label=\"A random position\" title=\"A random position\" @click=\"random\">\u003CPhShuffle :size=\"14\" weight=\"bold\" aria-hidden=\"true\" \u002F>\u003C\u002Fbutton>\n                    \u003C\u002Fspan>\n                  \u003C\u002Fp>\n                  \u003Cp v-if=\"humanSides.length\" class=\"seed\">\u003Cspan>Coach\u003C\u002Fspan>\u003CChessToggle v-model=\"coach\" :options=\"COACH\" label=\"Coach\" \u002F>\u003C\u002Fp>\n                \u003C\u002Fdiv>\n              \u003C\u002Fdiv>\n              \u003Cdiv class=\"actions\">\n                \u003CBtn v-if=\"auto && !game.outcome.value\" variant=\"amber\" size=\"md\" @click=\"paused = !paused\">{{ paused ? '► Play' : '║ Pause' }}\u003C\u002FBtn>\n                \u003CBtn v-else variant=\"amber\" size=\"md\" @click=\"newGame\">+ New game\u003C\u002FBtn>\n                \u003Cspan class=\"actions__links mono-label\">\n                  \u003Cbutton v-if=\"auto && !game.outcome.value\" type=\"button\" class=\"bare\" :disabled=\"!game.plies.value.length\" @click=\"newGame\">Reset\u003C\u002Fbutton>\n                  \u003Cbutton v-if=\"!auto\" type=\"button\" class=\"bare\" :disabled=\"!game.plies.value.length\" @click=\"undo\">Undo\u003C\u002Fbutton>\n                  \u003Cbutton type=\"button\" class=\"bare\" :aria-pressed=\"flipped\" @click=\"flipped = !flipped\">Flip\u003C\u002Fbutton>\n                \u003C\u002Fspan>\n              \u003C\u002Fdiv>\n              \u003CChessCoach v-if=\"coach && humanSides.length\" :verdict=\"verdict\" :thinking=\"coachThinking\" \u002F>\n              \u003Csection v-if=\"jevPlays && jevDecision\" class=\"reading\" aria-label=\"Jev\">\n                \u003Cp class=\"jev__head\">\n                  \u003Cspan class=\"jev__move\">{{ jevDecision.san }}\u003C\u002Fspan>\n                  \u003Cspan class=\"engine__note mono-label\">{{ jevDecision.forced ? FORCED_NOTE[jevDecision.forced] : `${jevDecision.options} legal moves · ${jevDecision.ms} ms` }}\u003C\u002Fspan>\n                \u003C\u002Fp>\n                \u003Cp class=\"jev__say\">{{ (!viewing && decision?.note) || narration }}\u003C\u002Fp>\n                \u003Col v-if=\"!jevDecision.forced\" class=\"engine__cands\" aria-label=\"Jev's top candidate moves\">\n                  \u003Cli v-for=\"(c, i) in jevDecision.candidates?.slice(0, 3)\" :key=\"i\" :class=\"{ 'is-picked': c.san === jevDecision.san }\">\n                    \u003Cspan>{{ c.san }}\u003C\u002Fspan>\u003CGlyphBar :value=\"c.p\" \u002F>\u003Cspan>{{ pct(c.p) }}\u003C\u002Fspan>\n                  \u003C\u002Fli>\n                \u003C\u002Fol>\n                \u003Cp v-if=\"readingLine?.length\" class=\"engine__meta mono-label\">{{ readingLine.join(' · ') }}\u003C\u002Fp>\n                \u003Cp v-if=\"!auto && (guess || reveal)\" class=\"engine__meta mono-label\" :class=\"{ 'is-hit': !guess && reveal?.hit }\">\n                  \u003Ctemplate v-if=\"guess\">Jev has guessed your reply. It shows once you move.\u003C\u002Ftemplate>\n                  \u003Ctemplate v-else-if=\"reveal\">Jev expected {{ reveal.expected }} ({{ pct(reveal.p) }}). You played {{ reveal.played }}{{ reveal.hit ? ' ■' : '' }}.\u003C\u002Ftemplate>\n                \u003C\u002Fp>\n              \u003C\u002Fsection>\n              \u003Cp v-else-if=\"jevPlays && !viewing\" class=\"panel__note mono-label\">{{ decision?.note || 'Jev’s reading shows here once it moves: its pick, how sure it was, and its plan.' }}\u003C\u002Fp>\n              \u003Cdiv class=\"moves\">\n                \u003Cp class=\"moves__head mono-label\">\n                  \u003Cspan>Moves\u003C\u002Fspan>\n                  \u003Cspan v-if=\"game.plies.value.length > 1\">\u003CGlyphSparkline :values=\"balance.slice(-SPARK)\" label=\"White's material lead over the last moves\" \u002F> {{ Math.ceil(game.plies.value.length \u002F 2) }}\u003C\u002Fspan>\n                \u003C\u002Fp>\n                \u003CChessMoveList :sans=\"game.plies.value.map((p) => p.san)\" :marks=\"story?.marks\" :shown=\"shown\" :viewing=\"viewing\" @go=\"goTo\" \u002F>\n              \u003C\u002Fdiv>\n            \u003C\u002Ftemplate>\n          \u003C\u002Ftemplate>\n        \u003C\u002FWin>\n      \u003C\u002Fdiv>\n    \u003C\u002Farticle>\n\n    \u003Csection class=\"bg-paper pb-section\">\n      \u003Cdiv class=\"wrap grid gap-head\">\n        \u003CPageHead :back=\"{ to: '\u002Flab', label: 'Lab' }\" :rule=\"false\">\n          \u003Ctemplate #meta>\n            \u003Cspan>{{ is960 ? 'Chess960' : 'Chess' }}\u003C\u002Fspan>\n            \u003Cspan v-if=\"is960\">{{ String(n).padStart(3, '0') }} \u002F {{ POSITIONS - 1 }}\u003C\u002Fspan>\n          \u003C\u002Ftemplate>\n          \u003Ch1 v-if=\"is960\" class=\"statement-lg\">Chess960 \u003CAccentText :text=\"`#${n}`\" :accent=\"`#${n}`\" \u002F>\u003C\u002Fh1>\n          \u003Ch1 v-else class=\"statement-lg\">A game of \u003CAccentText text=\"chess.\" accent=\"chess.\" \u002F>\u003C\u002Fh1>\n          \u003Cp v-if=\"is960\" class=\"lede\">One of the 960 Fischer random starting positions. Pawns stay put; the back rank is shuffled so the bishops sit on opposite colours and the king stands between the rooks.\u003C\u002Fp>\n          \u003Cp v-else class=\"lede\">Play Jev, TypeSafe AI’s System One model, a simple engine or a friend, or watch Jev play itself. Each turn Jev weighs every legal move at once, as one typed Choice, and shows how sure it is. Chess960 shuffles the back rank into one of 960 starting positions.\u003C\u002Fp>\n          \u003Cdiv class=\"chess-head__actions\">\n            \u003CShareBar :url=\"url\" :title=\"is960 ? `Chess960 #${n}: ${rank}` : 'Chess, with Jev'\" \u002F>\n            \u003CBtn to=\"\u002Flab\u002Fchess\u002Fsource\" variant=\"ghost\" size=\"md\">{ } Source\u003C\u002FBtn>\n          \u003C\u002Fdiv>\n        \u003C\u002FPageHead>\n        \u003Cp class=\"credit mono-label\">\n          Piece sets by Armando H. Marroquín, Utrecht by Hans L. Bodlaender, from Eric Bentzen’s\n          \u003Ca href=\"https:\u002F\u002Fctan.org\u002Ftex-archive\u002Ffonts\u002Fchess\u002Fenpassant\" rel=\"noopener\">En Passant collection\u003C\u002Fa>\n          (\u003Ca href=\"https:\u002F\u002Fwww.chessvariants.com\u002Fd.font\u002F\" rel=\"noopener\">more on the fonts\u003C\u002Fa>); Arcade and Console by\n          \u003Ca href=\"https:\u002F\u002Fspicygame.itch.io\u002Fchess-pieces\" rel=\"noopener\">SpicyGame\u003C\u002Fa> (CC0).\n          Rules by \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fniklasf\u002Fchessops\" rel=\"noopener\">chessops\u003C\u002Fa>, by Niklas Fiekas, the library behind Lichess, licensed under the\n          \u003Ca href=\"https:\u002F\u002Fwww.gnu.org\u002Flicenses\u002Fgpl-3.0.html\" rel=\"noopener\">GPL-3.0\u003C\u002Fa>, and so is\n          \u003CNuxtLink to=\"\u002Flab\u002Fchess\u002Fsource\">this experiment’s source\u003C\u002FNuxtLink>.\n          Jev is \u003Ca href=\"https:\u002F\u002Ftypesafe.ai\" rel=\"noopener\">TypeSafe AI\u003C\u002Fa>’s System One model, called through Vercel’s AI Gateway.\n          The coach is \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fofficial-stockfish\u002FStockfish\" rel=\"noopener\">Stockfish\u003C\u002Fa>, as\n          \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fnmrugg\u002Fstockfish.js\" rel=\"noopener\">stockfish.js\u003C\u002Fa> (GPL-3.0), loaded only when the coach is on.\n        \u003C\u002Fp>\n      \u003C\u002Fdiv>\n    \u003C\u002Fsection>\n    \u003CExperimentPager current=\"\u002Flab\u002Fchess\" \u002F>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>","\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">script\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">setup\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">lang\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;ts&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"language-javascript\">\n\u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan> { backRank, startFen, materialBalance, materialStory, isPositionId, \u003Cspan class=\"hljs-variable constant_\">POSITIONS\u003C\u002Fspan>, setup, \u003Cspan class=\"hljs-variable constant_\">STANDARD\u003C\u002Fspan> } \u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;@cw\u002Fchess\u002Frules&#x27;\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan> { \u003Cspan class=\"hljs-variable constant_\">BOARD_THEMES\u003C\u002Fspan>, \u003Cspan class=\"hljs-variable constant_\">CHESS_SETS\u003C\u002Fspan>, \u003Cspan class=\"hljs-variable constant_\">FONT_FACES\u003C\u002Fspan>, \u003Cspan class=\"hljs-variable constant_\">WATCH_SPEEDS\u003C\u002Fspan>, pieceGlyph, squareGlyph, type \u003Cspan class=\"hljs-title class_\">BoardTheme\u003C\u002Fspan> } \u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;#core\u002Fdomain\u002Fchess-board&#x27;\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan> type { \u003Cspan class=\"hljs-title class_\">GameMode\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">as\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Mode\u003C\u002Fspan> } \u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;@cw\u002Fchess&#x27;\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan> { \u003Cspan class=\"hljs-title class_\">PhShuffle\u003C\u002Fspan> } \u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;@phosphor-icons\u002Fvue&#x27;\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan> { fill, pickLine } \u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;@cw\u002Fjevvie&#x27;\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan> companion \u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;~~\u002Fcontent\u002Fcompanion.json&#x27;\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan> type { \u003Cspan class=\"hljs-title class_\">EngineDecision\u003C\u002Fspan>, \u003Cspan class=\"hljs-title class_\">Player\u003C\u002Fspan> } \u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;~\u002Fcomposables\u002FuseChessGame&#x27;\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">import\u003C\u002Fspan> type { \u003Cspan class=\"hljs-title class_\">CoachVerdict\u003C\u002Fspan> } \u003Cspan class=\"hljs-keyword\">from\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;~\u002Fcomponents\u002Flab\u002FChessCoach.vue&#x27;\u003C\u002Fspan>\n\n\u003Cspan class=\"hljs-comment\">\u002F\u002F one page instance across positions: switching swaps the board in place\u003C\u002Fspan>\n\u003Cspan class=\"hljs-title function_\">definePageMeta\u003C\u002Fspan>({ \u003Cspan class=\"hljs-attr\">keepScroll\u003C\u002Fspan>: \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">key\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;chess&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">jevvie\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;pawn&#x27;\u003C\u002Fspan> })\n\n\u003Cspan class=\"hljs-comment\">\u002F\u002F \u002F960 picks a random position, and \u002F960\u002F518 is plain chess, so it goes to \u002Flab\u002Fchess.\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-variable constant_\">BASE\u003C\u002Fspan> = \u003Cspan class=\"hljs-string\">&#x27;\u002Flab\u002Fchess&#x27;\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> route = \u003Cspan class=\"hljs-title function_\">useRoute\u003C\u002Fspan>()\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> path = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> ([] \u003Cspan class=\"hljs-keyword\">as\u003C\u002Fspan> string[]).\u003Cspan class=\"hljs-title function_\">concat\u003C\u002Fspan>(route.\u003Cspan class=\"hljs-property\">params\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">pos\u003C\u002Fspan> ?? []).\u003Cspan class=\"hljs-title function_\">filter\u003C\u002Fspan>(\u003Cspan class=\"hljs-title class_\">Boolean\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">href\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">i: number\u003C\u002Fspan>) =&gt; { \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> k = (i + \u003Cspan class=\"hljs-variable constant_\">POSITIONS\u003C\u002Fspan>) % \u003Cspan class=\"hljs-variable constant_\">POSITIONS\u003C\u002Fspan>; \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> k === \u003Cspan class=\"hljs-variable constant_\">STANDARD\u003C\u002Fspan> ? \u003Cspan class=\"hljs-variable constant_\">BASE\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${BASE}\u003C\u002Fspan>\u002F960\u002F\u003Cspan class=\"hljs-subst\">${k}\u003C\u002Fspan>`\u003C\u002Fspan> }\n\u003Cspan class=\"hljs-comment\">\u002F\u002F skips 518, which is standard chess\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">step\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">d: number\u003C\u002Fspan>) =&gt; { \u003Cspan class=\"hljs-keyword\">let\u003C\u002Fspan> k = (n.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> + d + \u003Cspan class=\"hljs-variable constant_\">POSITIONS\u003C\u002Fspan>) % \u003Cspan class=\"hljs-variable constant_\">POSITIONS\u003C\u002Fspan>; \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (k === \u003Cspan class=\"hljs-variable constant_\">STANDARD\u003C\u002Fspan>) k = (k + d + \u003Cspan class=\"hljs-variable constant_\">POSITIONS\u003C\u002Fspan>) % \u003Cspan class=\"hljs-variable constant_\">POSITIONS\u003C\u002Fspan>; \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">href\u003C\u002Fspan>(k) }\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">random960\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">\u003C\u002Fspan>) =&gt; { \u003Cspan class=\"hljs-keyword\">let\u003C\u002Fspan> k = \u003Cspan class=\"hljs-variable constant_\">STANDARD\u003C\u002Fspan>; \u003Cspan class=\"hljs-keyword\">while\u003C\u002Fspan> (k === \u003Cspan class=\"hljs-variable constant_\">STANDARD\u003C\u002Fspan>) k = \u003Cspan class=\"hljs-title class_\">Math\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">floor\u003C\u002Fspan>(\u003Cspan class=\"hljs-title class_\">Math\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">random\u003C\u002Fspan>() * \u003Cspan class=\"hljs-variable constant_\">POSITIONS\u003C\u002Fspan>); \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">href\u003C\u002Fspan>(k) }\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">parse\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">p: string[]\u003C\u002Fspan>) =&gt; (!p.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> ? \u003Cspan class=\"hljs-variable constant_\">STANDARD\u003C\u002Fspan> : p[\u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>] === \u003Cspan class=\"hljs-string\">&#x27;960&#x27;\u003C\u002Fspan> &amp;&amp; p.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> === \u003Cspan class=\"hljs-number\">2\u003C\u002Fspan> &amp;&amp; \u003Cspan class=\"hljs-regexp\">\u002F^\\d{1,3}$\u002F\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">test\u003C\u002Fspan>(p[\u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>]!) ? \u003Cspan class=\"hljs-title class_\">Number\u003C\u002Fspan>(p[\u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>]) : \u003Cspan class=\"hljs-title class_\">NaN\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">redirect\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">p: string[]\u003C\u002Fspan>) =&gt; (p.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> === \u003Cspan class=\"hljs-number\">1\u003C\u002Fspan> &amp;&amp; p[\u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>] === \u003Cspan class=\"hljs-string\">&#x27;960&#x27;\u003C\u002Fspan> ? \u003Cspan class=\"hljs-title function_\">random960\u003C\u002Fspan>() : p.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> === \u003Cspan class=\"hljs-number\">2\u003C\u002Fspan> &amp;&amp; \u003Cspan class=\"hljs-title function_\">parse\u003C\u002Fspan>(p) === \u003Cspan class=\"hljs-variable constant_\">STANDARD\u003C\u002Fspan> ? \u003Cspan class=\"hljs-variable constant_\">BASE\u003C\u002Fspan> : \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> first = \u003Cspan class=\"hljs-title function_\">redirect\u003C\u002Fspan>(path.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (first) \u003Cspan class=\"hljs-keyword\">await\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">navigateTo\u003C\u002Fspan>(first, { \u003Cspan class=\"hljs-attr\">redirectCode\u003C\u002Fspan>: path.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> === \u003Cspan class=\"hljs-number\">1\u003C\u002Fspan> ? \u003Cspan class=\"hljs-number\">302\u003C\u002Fspan> : \u003Cspan class=\"hljs-number\">301\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">replace\u003C\u002Fspan>: \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan> })\n\u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!first &amp;&amp; !\u003Cspan class=\"hljs-title function_\">isPositionId\u003C\u002Fspan>(\u003Cspan class=\"hljs-title function_\">parse\u003C\u002Fspan>(path.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>))) \u003Cspan class=\"hljs-keyword\">throw\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">createError\u003C\u002Fspan>({ \u003Cspan class=\"hljs-attr\">statusCode\u003C\u002Fspan>: \u003Cspan class=\"hljs-number\">404\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">statusMessage\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;No such Chess960 position&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">fatal\u003C\u002Fspan>: \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan> })\n\u003Cspan class=\"hljs-title function_\">watch\u003C\u002Fspan>(path, \u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">p\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> { \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> to = \u003Cspan class=\"hljs-title function_\">redirect\u003C\u002Fspan>(p); \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (to) \u003Cspan class=\"hljs-keyword\">void\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">navigateTo\u003C\u002Fspan>(to, { \u003Cspan class=\"hljs-attr\">replace\u003C\u002Fspan>: \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan> }) })\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> n = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> { \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> k = \u003Cspan class=\"hljs-title function_\">parse\u003C\u002Fspan>(path.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>); \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">isPositionId\u003C\u002Fspan>(k) ? k : \u003Cspan class=\"hljs-variable constant_\">STANDARD\u003C\u002Fspan> })\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> is960 = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> n.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> !== \u003Cspan class=\"hljs-variable constant_\">STANDARD\u003C\u002Fspan>)\n\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> rank = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">backRank\u003C\u002Fspan>(n.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> flipped = \u003Cspan class=\"hljs-title function_\">useStored\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;chessFlipped&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>, \u003Cspan class=\"hljs-title function_\">oneOf\u003C\u002Fspan>(\u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>, \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> { set, font, theme } = \u003Cspan class=\"hljs-title function_\">useChessSet\u003C\u002Fspan>()\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">swatch\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">t: BoardTheme\u003C\u002Fspan>) =&gt; ({ \u003Cspan class=\"hljs-attr\">background\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">`var(--color-\u003Cspan class=\"hljs-subst\">${BOARD_THEMES[t].ground}\u003C\u002Fspan>)`\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">color\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">`var(--color-\u003Cspan class=\"hljs-subst\">${BOARD_THEMES[t].ink}\u003C\u002Fspan>)`\u003C\u002Fspan> })\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> family = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">`&#x27;Chess \u003Cspan class=\"hljs-subst\">${font.value}\u003C\u002Fspan>&#x27;, var(--font-mono)`\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-comment\">\u002F\u002F Declared on this page only: a browser fetches a face only when text uses it, so a visitor downloads just the set on screen.\u003C\u002Fspan>\n\u003Cspan class=\"hljs-title function_\">useHead\u003C\u002Fspan>({ \u003Cspan class=\"hljs-attr\">link\u003C\u002Fspan>: [{ \u003Cspan class=\"hljs-attr\">rel\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;preload&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">href\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;\u002Ffonts\u002Fchess\u002Fmerida.woff2&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">as\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;font&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">type\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;font\u002Fwoff2&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">crossorigin\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan> }], \u003Cspan class=\"hljs-attr\">style\u003C\u002Fspan>: [{ \u003Cspan class=\"hljs-attr\">key\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;chess-fonts&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">innerHTML\u003C\u002Fspan>: \u003Cspan class=\"hljs-variable constant_\">FONT_FACES\u003C\u002Fspan> }] })\n\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> presence = \u003Cspan class=\"hljs-title function_\">usePresence\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;chess&#x27;\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> boardTitle = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${is960.value ? \u003Cspan class=\"hljs-string\">`CW\u002FCHESS960 · \u003Cspan class=\"hljs-subst\">${rank.value}\u003C\u002Fspan>`\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;CW\u002FCHESS&#x27;\u003C\u002Fspan>}\u003C\u002Fspan>\u003Cspan class=\"hljs-subst\">${presence.value?.here ? \u003Cspan class=\"hljs-string\">` · \u003Cspan class=\"hljs-subst\">${presence.value.here}\u003C\u002Fspan> here`\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan>}\u003C\u002Fspan>`\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> game = \u003Cspan class=\"hljs-title function_\">useChessGame\u003C\u002Fspan>(rank)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">MODES\u003C\u002Fspan>: { \u003Cspan class=\"hljs-attr\">value\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">Mode\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: string; \u003Cspan class=\"hljs-attr\">note\u003C\u002Fspan>: string; featured?: boolean }[] = [\n  { \u003Cspan class=\"hljs-attr\">value\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;jev-jev&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Watch Jev vs Jev&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">note\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;the model against itself&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">featured\u003C\u002Fspan>: \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan> },\n  { \u003Cspan class=\"hljs-attr\">value\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;jev-simple&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Watch Jev vs engine&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">note\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;sides swap each game&#x27;\u003C\u002Fspan> },\n  { \u003Cspan class=\"hljs-attr\">value\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;jev&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Play Jev&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">note\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;you against the model&#x27;\u003C\u002Fspan> },\n  { \u003Cspan class=\"hljs-attr\">value\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;simple&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Play the engine&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">note\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;quick, grabs material&#x27;\u003C\u002Fspan> },\n  { \u003Cspan class=\"hljs-attr\">value\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;friend&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Play a friend&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">note\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;two players, one board&#x27;\u003C\u002Fspan> },\n]\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> mode = useStored&lt;\u003Cspan class=\"hljs-title class_\">Mode\u003C\u002Fspan>&gt;(\u003Cspan class=\"hljs-string\">&#x27;chessMode&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;jev-jev&#x27;\u003C\u002Fspan>, oneOf&lt;\u003Cspan class=\"hljs-title class_\">Mode\u003C\u002Fspan>&gt;(\u003Cspan class=\"hljs-string\">&#x27;jev&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;simple&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;friend&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;jev-jev&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;jev-simple&#x27;\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-comment\">\u002F\u002F the seats are kept, so a reload finds the same sides\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> colour = useStored&lt;\u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan> | \u003Cspan class=\"hljs-string\">&#x27;black&#x27;\u003C\u002Fspan> | \u003Cspan class=\"hljs-string\">&#x27;random&#x27;\u003C\u002Fspan>&gt;(\u003Cspan class=\"hljs-string\">&#x27;chessColour&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-title function_\">oneOf\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;black&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;random&#x27;\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> yours = useStored&lt;\u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan> | \u003Cspan class=\"hljs-string\">&#x27;black&#x27;\u003C\u002Fspan>&gt;(\u003Cspan class=\"hljs-string\">&#x27;chessYours&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-title function_\">oneOf\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;black&#x27;\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> jevSide = useStored&lt;\u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan> | \u003Cspan class=\"hljs-string\">&#x27;black&#x27;\u003C\u002Fspan>&gt;(\u003Cspan class=\"hljs-string\">&#x27;chessJevSide&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-title function_\">oneOf\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;black&#x27;\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">other\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">c: \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan> | \u003Cspan class=\"hljs-string\">&#x27;black&#x27;\u003C\u002Fspan>\u003C\u002Fspan>) =&gt; (c === \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;black&#x27;\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">seat\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">\u003C\u002Fspan>) {\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (mode.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;jev&#x27;\u003C\u002Fspan> || mode.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;simple&#x27;\u003C\u002Fspan>) {\n    yours.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = colour.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;random&#x27;\u003C\u002Fspan> ? (\u003Cspan class=\"hljs-title class_\">Math\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">random\u003C\u002Fspan>() &lt; \u003Cspan class=\"hljs-number\">0.5\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;black&#x27;\u003C\u002Fspan>) : colour.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>\n    flipped.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = yours.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;black&#x27;\u003C\u002Fspan>\n  }\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (mode.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;jev-simple&#x27;\u003C\u002Fspan>) jevSide.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-title function_\">other\u003C\u002Fspan>(jevSide.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>)\n}\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> players = computed&lt;{ \u003Cspan class=\"hljs-attr\">white\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">Player\u003C\u002Fspan>; \u003Cspan class=\"hljs-attr\">black\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">Player\u003C\u002Fspan> }&gt;(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> {\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> m = mode.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (m === \u003Cspan class=\"hljs-string\">&#x27;friend&#x27;\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> { \u003Cspan class=\"hljs-attr\">white\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;human&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">black\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;human&#x27;\u003C\u002Fspan> }\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (m === \u003Cspan class=\"hljs-string\">&#x27;jev-jev&#x27;\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> { \u003Cspan class=\"hljs-attr\">white\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;jev&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">black\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;jev&#x27;\u003C\u002Fspan> }\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (m === \u003Cspan class=\"hljs-string\">&#x27;jev-simple&#x27;\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> jevSide.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan> ? { \u003Cspan class=\"hljs-attr\">white\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;jev&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">black\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;simple&#x27;\u003C\u002Fspan> } : { \u003Cspan class=\"hljs-attr\">white\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;simple&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">black\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;jev&#x27;\u003C\u002Fspan> }\n  \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> yours.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan> ? { \u003Cspan class=\"hljs-attr\">white\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;human&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">black\u003C\u002Fspan>: m } : { \u003Cspan class=\"hljs-attr\">white\u003C\u002Fspan>: m, \u003Cspan class=\"hljs-attr\">black\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;human&#x27;\u003C\u002Fspan> }\n})\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> auto = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> mode.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;jev-jev&#x27;\u003C\u002Fspan> || mode.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;jev-simple&#x27;\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> jevPlays = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> players.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">white\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;jev&#x27;\u003C\u002Fspan> || players.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">black\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;jev&#x27;\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">choose\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">m: Mode\u003C\u002Fspan>) { mode.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = m; \u003Cspan class=\"hljs-title function_\">newGame\u003C\u002Fspan>() }\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> modeLabel = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-variable constant_\">MODES\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">find\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">m\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> m.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === mode.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>)?.\u003Cspan class=\"hljs-property\">label\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">cap\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">s: string\u003C\u002Fspan>) =&gt; s[\u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>]!.\u003Cspan class=\"hljs-title function_\">toUpperCase\u003C\u002Fspan>() + s.\u003Cspan class=\"hljs-title function_\">slice\u003C\u002Fspan>(\u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> options = &lt;T \u003Cspan class=\"hljs-keyword\">extends\u003C\u002Fspan> string&gt;\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">values: readonly T[]\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> values.\u003Cspan class=\"hljs-title function_\">map\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">value\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> ({ value, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-title function_\">cap\u003C\u002Fspan>(value) }))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-variable constant_\">COLOURS\u003C\u002Fspan> = \u003Cspan class=\"hljs-title function_\">options\u003C\u002Fspan>([\u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;black&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;random&#x27;\u003C\u002Fspan>] \u003Cspan class=\"hljs-keyword\">as\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-variable constant_\">LEVELS\u003C\u002Fspan> = \u003Cspan class=\"hljs-title function_\">options\u003C\u002Fspan>([\u003Cspan class=\"hljs-string\">&#x27;easy&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;normal&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;hard&#x27;\u003C\u002Fspan>] \u003Cspan class=\"hljs-keyword\">as\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-variable constant_\">PACES\u003C\u002Fspan> = \u003Cspan class=\"hljs-title function_\">options\u003C\u002Fspan>([\u003Cspan class=\"hljs-string\">&#x27;slow&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;normal&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;fast&#x27;\u003C\u002Fspan>] \u003Cspan class=\"hljs-keyword\">as\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-variable constant_\">COACH\u003C\u002Fspan> = [{ \u003Cspan class=\"hljs-attr\">value\u003C\u002Fspan>: \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Off&#x27;\u003C\u002Fspan> }, { \u003Cspan class=\"hljs-attr\">value\u003C\u002Fspan>: \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;On&#x27;\u003C\u002Fspan> }]\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-variable constant_\">VARIANTS\u003C\u002Fspan> = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> [{ \u003Cspan class=\"hljs-attr\">value\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;standard&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Standard&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">to\u003C\u002Fspan>: \u003Cspan class=\"hljs-variable constant_\">BASE\u003C\u002Fspan> }, { \u003Cspan class=\"hljs-attr\">value\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;chess960&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Chess960&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">to\u003C\u002Fspan>: is960.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? \u003Cspan class=\"hljs-title function_\">href\u003C\u002Fspan>(n.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) : \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${BASE}\u003C\u002Fspan>\u002F960`\u003C\u002Fspan> }])\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> settingsOpen = \u003Cspan class=\"hljs-title function_\">ref\u003C\u002Fspan>(\u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> settingsSummary = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> [\n  modeLabel.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>,\n  mode.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;jev&#x27;\u003C\u002Fspan> || mode.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;simple&#x27;\u003C\u002Fspan> ? \u003Cspan class=\"hljs-title function_\">cap\u003C\u002Fspan>(colour.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) : \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan>,\n  jevPlays.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">`Jev \u003Cspan class=\"hljs-subst\">${level.value}\u003C\u002Fspan>`\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan>,\n  coach.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> &amp;&amp; humanSides.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;Coach&#x27;\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan>,\n  auto.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? \u003Cspan class=\"hljs-title function_\">cap\u003C\u002Fspan>(speed.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) : \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan>,\n  is960.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">`Chess960 #\u003Cspan class=\"hljs-subst\">${n.value}\u003C\u002Fspan>`\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;Standard&#x27;\u003C\u002Fspan>,\n].\u003Cspan class=\"hljs-title function_\">filter\u003C\u002Fspan>(\u003Cspan class=\"hljs-title class_\">Boolean\u003C\u002Fspan>).\u003Cspan class=\"hljs-title function_\">join\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27; · &#x27;\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-comment\">\u002F\u002F A watch never starts by itself, so Jev is only called for someone who is watching.\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> paused = \u003Cspan class=\"hljs-title function_\">ref\u003C\u002Fspan>(\u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> idle = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> auto.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> &amp;&amp; paused.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> &amp;&amp; !resting.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> &amp;&amp; !game.\u003Cspan class=\"hljs-property\">plies\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> &amp;&amp; game.\u003Cspan class=\"hljs-property\">ready\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-comment\">\u002F\u002F a wait of hours is the site&#x27;s daily budget, and the watch stays paused\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> resting = \u003Cspan class=\"hljs-title function_\">ref\u003C\u002Fspan>(\u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> spent = \u003Cspan class=\"hljs-title function_\">ref\u003C\u002Fspan>(\u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">let\u003C\u002Fspan> restTimer = \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">rest\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">seconds: number\u003C\u002Fspan>) {\n  paused.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>\n  resting.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>\n  spent.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = seconds &gt; \u003Cspan class=\"hljs-number\">5\u003C\u002Fspan> * \u003Cspan class=\"hljs-number\">60\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-built_in\">clearTimeout\u003C\u002Fspan>(restTimer)\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!spent.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) restTimer = \u003Cspan class=\"hljs-variable language_\">window\u003C\u002Fspan>.\u003Cspan class=\"hljs-built_in\">setTimeout\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> { resting.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>; paused.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan> }, seconds * \u003Cspan class=\"hljs-number\">1000\u003C\u002Fspan>)\n}\n\u003Cspan class=\"hljs-title function_\">watch\u003C\u002Fspan>(paused, \u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">p\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> { \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!p) { resting.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>; \u003Cspan class=\"hljs-built_in\">clearTimeout\u003C\u002Fspan>(restTimer) } })\n\u003Cspan class=\"hljs-title function_\">onBeforeUnmount\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-built_in\">clearTimeout\u003C\u002Fspan>(restTimer))\n\u003Cspan class=\"hljs-comment\">\u002F\u002F counted when an engine&#x27;s move ends a game here, so reloading a finished game never counts it twice\u003C\u002Fspan>\ntype \u003Cspan class=\"hljs-title class_\">Tally\u003C\u002Fspan> = { \u003Cspan class=\"hljs-attr\">a\u003C\u002Fspan>: number; \u003Cspan class=\"hljs-attr\">b\u003C\u002Fspan>: number; \u003Cspan class=\"hljs-attr\">draws\u003C\u002Fspan>: number }\ntype \u003Cspan class=\"hljs-title class_\">Watch\u003C\u002Fspan> = \u003Cspan class=\"hljs-string\">&#x27;jev-jev&#x27;\u003C\u002Fspan> | \u003Cspan class=\"hljs-string\">&#x27;jev-simple&#x27;\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">SCORE_NAMES\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">Record\u003C\u002Fspan>&lt;\u003Cspan class=\"hljs-title class_\">Watch\u003C\u002Fspan>, [string, string]&gt; = { \u003Cspan class=\"hljs-string\">&#x27;jev-jev&#x27;\u003C\u002Fspan>: [\u003Cspan class=\"hljs-string\">&#x27;White&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;Black&#x27;\u003C\u002Fspan>], \u003Cspan class=\"hljs-string\">&#x27;jev-simple&#x27;\u003C\u002Fspan>: [\u003Cspan class=\"hljs-string\">&#x27;Jev&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;Engine&#x27;\u003C\u002Fspan>] }\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> isTally = (\u003Cspan class=\"hljs-attr\">v\u003C\u002Fspan>: unknown): v is \u003Cspan class=\"hljs-title class_\">Tally\u003C\u002Fspan> =&gt; !!v &amp;&amp; \u003Cspan class=\"hljs-keyword\">typeof\u003C\u002Fspan> v === \u003Cspan class=\"hljs-string\">&#x27;object&#x27;\u003C\u002Fspan> &amp;&amp; [\u003Cspan class=\"hljs-string\">&#x27;a&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;b&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;draws&#x27;\u003C\u002Fspan>].\u003Cspan class=\"hljs-title function_\">every\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">k\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Number\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">isInteger\u003C\u002Fspan>((v \u003Cspan class=\"hljs-keyword\">as\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Record\u003C\u002Fspan>&lt;string, unknown&gt;)[k]))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> scores = useStored&lt;\u003Cspan class=\"hljs-title class_\">Record\u003C\u002Fspan>&lt;\u003Cspan class=\"hljs-title class_\">Watch\u003C\u002Fspan>, \u003Cspan class=\"hljs-title class_\">Tally\u003C\u002Fspan>&gt;&gt;(\u003Cspan class=\"hljs-string\">&#x27;chessScores&#x27;\u003C\u002Fspan>, { \u003Cspan class=\"hljs-string\">&#x27;jev-jev&#x27;\u003C\u002Fspan>: { \u003Cspan class=\"hljs-attr\">a\u003C\u002Fspan>: \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">b\u003C\u002Fspan>: \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">draws\u003C\u002Fspan>: \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan> }, \u003Cspan class=\"hljs-string\">&#x27;jev-simple&#x27;\u003C\u002Fspan>: { \u003Cspan class=\"hljs-attr\">a\u003C\u002Fspan>: \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">b\u003C\u002Fspan>: \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">draws\u003C\u002Fspan>: \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan> } }, (v): v is \u003Cspan class=\"hljs-title class_\">Record\u003C\u002Fspan>&lt;\u003Cspan class=\"hljs-title class_\">Watch\u003C\u002Fspan>, \u003Cspan class=\"hljs-title class_\">Tally\u003C\u002Fspan>&gt; =&gt; !!v &amp;&amp; \u003Cspan class=\"hljs-keyword\">typeof\u003C\u002Fspan> v === \u003Cspan class=\"hljs-string\">&#x27;object&#x27;\u003C\u002Fspan> &amp;&amp; \u003Cspan class=\"hljs-title function_\">isTally\u003C\u002Fspan>((v \u003Cspan class=\"hljs-keyword\">as\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Record\u003C\u002Fspan>&lt;string, unknown&gt;)[\u003Cspan class=\"hljs-string\">&#x27;jev-jev&#x27;\u003C\u002Fspan>]) &amp;&amp; \u003Cspan class=\"hljs-title function_\">isTally\u003C\u002Fspan>((v \u003Cspan class=\"hljs-keyword\">as\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Record\u003C\u002Fspan>&lt;string, unknown&gt;)[\u003Cspan class=\"hljs-string\">&#x27;jev-simple&#x27;\u003C\u002Fspan>]))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> watchKey = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> (auto.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? (mode.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">as\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Watch\u003C\u002Fspan>) : \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">tally\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">o: { winner?: \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan> | \u003Cspan class=\"hljs-string\">&#x27;black&#x27;\u003C\u002Fspan> } | \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>\u003C\u002Fspan>) {\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> k = watchKey.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!o || !k) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-comment\">\u002F\u002F read the stored score afresh, so games finished in other tabs are not overwritten\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> latest = readStore&lt;\u003Cspan class=\"hljs-title class_\">Record\u003C\u002Fspan>&lt;\u003Cspan class=\"hljs-title class_\">Watch\u003C\u002Fspan>, \u003Cspan class=\"hljs-title class_\">Tally\u003C\u002Fspan>&gt;&gt;(\u003Cspan class=\"hljs-string\">&#x27;chessScores&#x27;\u003C\u002Fspan>)\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> base = latest &amp;&amp; \u003Cspan class=\"hljs-title function_\">isTally\u003C\u002Fspan>(latest[k]) ? latest : scores.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> t = { ...base[k] }\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!o.\u003Cspan class=\"hljs-property\">winner\u003C\u002Fspan>) t.\u003Cspan class=\"hljs-property\">draws\u003C\u002Fspan>++\n  \u003Cspan class=\"hljs-keyword\">else\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (k === \u003Cspan class=\"hljs-string\">&#x27;jev-jev&#x27;\u003C\u002Fspan> ? o.\u003Cspan class=\"hljs-property\">winner\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan> : players.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>[o.\u003Cspan class=\"hljs-property\">winner\u003C\u002Fspan>] === \u003Cspan class=\"hljs-string\">&#x27;jev&#x27;\u003C\u002Fspan>) t.\u003Cspan class=\"hljs-property\">a\u003C\u002Fspan>++\n  \u003Cspan class=\"hljs-keyword\">else\u003C\u002Fspan> t.\u003Cspan class=\"hljs-property\">b\u003C\u002Fspan>++\n  scores.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = { ...base, [k]: t }\n}\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> scoreScope = ref&lt;\u003Cspan class=\"hljs-string\">&#x27;everyone&#x27;\u003C\u002Fspan> | \u003Cspan class=\"hljs-string\">&#x27;browser&#x27;\u003C\u002Fspan>&gt;(\u003Cspan class=\"hljs-string\">&#x27;everyone&#x27;\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> everyone = ref&lt;\u003Cspan class=\"hljs-title class_\">Record\u003C\u002Fspan>&lt;\u003Cspan class=\"hljs-title class_\">Watch\u003C\u002Fspan>, \u003Cspan class=\"hljs-title class_\">Tally\u003C\u002Fspan>&gt;&gt;()\n\u003Cspan class=\"hljs-keyword\">async\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">fetchScores\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">\u003C\u002Fspan>) { \u003Cspan class=\"hljs-keyword\">try\u003C\u002Fspan> { everyone.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-keyword\">await\u003C\u002Fspan> $fetch&lt;\u003Cspan class=\"hljs-title class_\">Record\u003C\u002Fspan>&lt;\u003Cspan class=\"hljs-title class_\">Watch\u003C\u002Fspan>, \u003Cspan class=\"hljs-title class_\">Tally\u003C\u002Fspan>&gt;&gt;(\u003Cspan class=\"hljs-string\">&#x27;\u002Fapi\u002Fchess\u002Fscores&#x27;\u003C\u002Fspan>) } \u003Cspan class=\"hljs-keyword\">catch\u003C\u002Fspan> {} }\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> scoreRows = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> {\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> k = watchKey.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> t = k &amp;&amp; (scoreScope.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;everyone&#x27;\u003C\u002Fspan> ? everyone.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>?.[k] : scores.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>[k])\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!k || !t) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> []\n  \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> [{ \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-variable constant_\">SCORE_NAMES\u003C\u002Fspan>[k][\u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>], \u003Cspan class=\"hljs-attr\">n\u003C\u002Fspan>: t.\u003Cspan class=\"hljs-property\">a\u003C\u002Fspan> }, { \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-variable constant_\">SCORE_NAMES\u003C\u002Fspan>[k][\u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>], \u003Cspan class=\"hljs-attr\">n\u003C\u002Fspan>: t.\u003Cspan class=\"hljs-property\">b\u003C\u002Fspan> }, { \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Draws&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">n\u003C\u002Fspan>: t.\u003Cspan class=\"hljs-property\">draws\u003C\u002Fspan> }]\n})\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> games = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> scoreRows.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">reduce\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">k, r\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> k + r.\u003Cspan class=\"hljs-property\">n\u003C\u002Fspan>, \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">resetScore\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">\u003C\u002Fspan>) { \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> k = watchKey.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>; \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (k) scores.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = { ...scores.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, [k]: { \u003Cspan class=\"hljs-attr\">a\u003C\u002Fspan>: \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">b\u003C\u002Fspan>: \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">draws\u003C\u002Fspan>: \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan> } } }\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> level = useStored&lt;\u003Cspan class=\"hljs-string\">&#x27;easy&#x27;\u003C\u002Fspan> | \u003Cspan class=\"hljs-string\">&#x27;normal&#x27;\u003C\u002Fspan> | \u003Cspan class=\"hljs-string\">&#x27;hard&#x27;\u003C\u002Fspan>&gt;(\u003Cspan class=\"hljs-string\">&#x27;chessLevel&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;normal&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-title function_\">oneOf\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;easy&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;normal&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;hard&#x27;\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> speed = useStored&lt;keyof \u003Cspan class=\"hljs-keyword\">typeof\u003C\u002Fspan> \u003Cspan class=\"hljs-variable constant_\">WATCH_SPEEDS\u003C\u002Fspan>&gt;(\u003Cspan class=\"hljs-string\">&#x27;chessSpeed&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;normal&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-title function_\">oneOf\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;slow&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;normal&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;fast&#x27;\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> engineTurn = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> players.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>[game.\u003Cspan class=\"hljs-property\">turn\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>] !== \u003Cspan class=\"hljs-string\">&#x27;human&#x27;\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> thinking = ref&lt;\u003Cspan class=\"hljs-title class_\">Exclude\u003C\u002Fspan>&lt;\u003Cspan class=\"hljs-title class_\">Player\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;human&#x27;\u003C\u002Fspan>&gt;&gt;()\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> decision = ref&lt;\u003Cspan class=\"hljs-title class_\">EngineDecision\u003C\u002Fspan>&gt;()\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> considering = ref&lt;\u003Cspan class=\"hljs-title class_\">EngineDecision\u003C\u002Fspan>[\u003Cspan class=\"hljs-string\">&#x27;candidates&#x27;\u003C\u002Fspan>]&gt;()\n\u003Cspan class=\"hljs-comment\">\u002F\u002F by ply, so looking back shows what Jev thought at that point\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> decisions = ref&lt;\u003Cspan class=\"hljs-title class_\">Record\u003C\u002Fspan>&lt;number, \u003Cspan class=\"hljs-title class_\">EngineDecision\u003C\u002Fspan>&gt;&gt;({})\n\u003Cspan class=\"hljs-title function_\">watch\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> game.\u003Cspan class=\"hljs-property\">plies\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan>, \u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">len\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> {\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (\u003Cspan class=\"hljs-title class_\">Object\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">keys\u003C\u002Fspan>(decisions.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>).\u003Cspan class=\"hljs-title function_\">some\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">k\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Number\u003C\u002Fspan>(k) &gt;= len)) decisions.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-title class_\">Object\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">fromEntries\u003C\u002Fspan>(\u003Cspan class=\"hljs-title class_\">Object\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">entries\u003C\u002Fspan>(decisions.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>).\u003Cspan class=\"hljs-title function_\">filter\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">[k]\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Number\u003C\u002Fspan>(k) &lt; len))\n})\n\u003Cspan class=\"hljs-comment\">\u002F\u002F Jev&#x27;s latest up to the move shown, so the engine&#x27;s replies in a watch keep what Jev last thought\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> shownDecision = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> {\n  \u003Cspan class=\"hljs-keyword\">for\u003C\u002Fspan> (\u003Cspan class=\"hljs-keyword\">let\u003C\u002Fspan> k = shown.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> - \u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>; k &gt;= \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>; k--) \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (decisions.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>[k]?.\u003Cspan class=\"hljs-property\">engine\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;jev&#x27;\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> decisions.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>[k]\n  \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>\n})\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">toArrows\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">cands?: EngineDecision[\u003Cspan class=\"hljs-string\">&#x27;candidates&#x27;\u003C\u002Fspan>]\u003C\u002Fspan>) =&gt; cands?.\u003Cspan class=\"hljs-title function_\">flatMap\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">c\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> (c.\u003Cspan class=\"hljs-property\">uci\u003C\u002Fspan> ? [{ \u003Cspan class=\"hljs-attr\">from\u003C\u002Fspan>: \u003Cspan class=\"hljs-title function_\">square\u003C\u002Fspan>(c.\u003Cspan class=\"hljs-property\">uci\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">slice\u003C\u002Fspan>(\u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>, \u003Cspan class=\"hljs-number\">2\u003C\u002Fspan>)), \u003Cspan class=\"hljs-attr\">to\u003C\u002Fspan>: \u003Cspan class=\"hljs-title function_\">square\u003C\u002Fspan>(c.\u003Cspan class=\"hljs-property\">uci\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">slice\u003C\u002Fspan>(\u003Cspan class=\"hljs-number\">2\u003C\u002Fspan>, \u003Cspan class=\"hljs-number\">4\u003C\u002Fspan>)), \u003Cspan class=\"hljs-attr\">p\u003C\u002Fspan>: c.\u003Cspan class=\"hljs-property\">p\u003C\u002Fspan> }] : []))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> arrows = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> (viewing.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? \u003Cspan class=\"hljs-title function_\">toArrows\u003C\u002Fspan>(shownDecision.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>?.\u003Cspan class=\"hljs-property\">candidates\u003C\u002Fspan>) : \u003Cspan class=\"hljs-title function_\">toArrows\u003C\u002Fspan>(considering.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>)))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">square\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">name: string\u003C\u002Fspan>) =&gt; \u003Cspan class=\"hljs-string\">&#x27;abcdefgh&#x27;\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">indexOf\u003C\u002Fspan>(name[\u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>]!) + \u003Cspan class=\"hljs-number\">8\u003C\u002Fspan> * (\u003Cspan class=\"hljs-title class_\">Number\u003C\u002Fspan>(name[\u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>]) - \u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> playable = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> game.\u003Cspan class=\"hljs-property\">ready\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> &amp;&amp; !game.\u003Cspan class=\"hljs-property\">outcome\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> &amp;&amp; !engineTurn.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> &amp;&amp; !thinking.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> premove = ref&lt;{ \u003Cspan class=\"hljs-attr\">from\u003C\u002Fspan>: number; \u003Cspan class=\"hljs-attr\">to\u003C\u002Fspan>: number }&gt;()\n\u003Cspan class=\"hljs-comment\">\u002F\u002F `view` is the move shown (0 is the start), null is live. Looking back is read-only, and nothing plays meanwhile.\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> view = ref&lt;number | \u003Cspan class=\"hljs-literal\">null\u003C\u002Fspan>&gt;(\u003Cspan class=\"hljs-literal\">null\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> shown = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> view.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ?? game.\u003Cspan class=\"hljs-property\">plies\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> viewing = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> view.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> !== \u003Cspan class=\"hljs-literal\">null\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">goTo\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">k: number | \u003Cspan class=\"hljs-literal\">null\u003C\u002Fspan>\u003C\u002Fspan>) { view.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = k === \u003Cspan class=\"hljs-literal\">null\u003C\u002Fspan> ? \u003Cspan class=\"hljs-literal\">null\u003C\u002Fspan> : \u003Cspan class=\"hljs-title class_\">Math\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">max\u003C\u002Fspan>(\u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>, \u003Cspan class=\"hljs-title class_\">Math\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">min\u003C\u002Fspan>(game.\u003Cspan class=\"hljs-property\">plies\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan>, k)) }\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> shownLast = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> (viewing.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? game.\u003Cspan class=\"hljs-property\">plies\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>[shown.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> - \u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>] : game.\u003Cspan class=\"hljs-property\">plies\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">at\u003C\u002Fspan>(-\u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>)))\ntype \u003Cspan class=\"hljs-title class_\">SavedGame\u003C\u002Fspan> = { \u003Cspan class=\"hljs-attr\">n\u003C\u002Fspan>: number; \u003Cspan class=\"hljs-attr\">moves\u003C\u002Fspan>: string[] }\n\u003Cspan class=\"hljs-comment\">\u002F\u002F Per tab, so two tabs never overwrite each other&#x27;s game; the latest also goes to localStorage for a new tab.\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">let\u003C\u002Fspan> restored = \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>\n\u003Cspan class=\"hljs-comment\">\u002F\u002F A shared game (?g=e2e4.e7e5…) opens looking back, so no engine moves until Live.\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-variable constant_\">UCI\u003C\u002Fspan> = \u003Cspan class=\"hljs-regexp\">\u002F^[a-h][1-8][a-h][1-8][qrbn]?$\u002F\u003C\u002Fspan>\n\u003Cspan class=\"hljs-title function_\">onMounted\u003C\u002Fspan>(\u003Cspan class=\"hljs-title function_\">async\u003C\u002Fspan> () =&gt; {\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> shared = \u003Cspan class=\"hljs-keyword\">typeof\u003C\u002Fspan> route.\u003Cspan class=\"hljs-property\">query\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">g\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;string&#x27;\u003C\u002Fspan> ? route.\u003Cspan class=\"hljs-property\">query\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">g\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">split\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;.&#x27;\u003C\u002Fspan>).\u003Cspan class=\"hljs-title function_\">filter\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">u\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-variable constant_\">UCI\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">test\u003C\u002Fspan>(u)) : []\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> saved = readSession&lt;\u003Cspan class=\"hljs-title class_\">SavedGame\u003C\u002Fspan>&gt;(\u003Cspan class=\"hljs-string\">&#x27;chessGame&#x27;\u003C\u002Fspan>) ?? readStore&lt;\u003Cspan class=\"hljs-title class_\">SavedGame\u003C\u002Fspan>&gt;(\u003Cspan class=\"hljs-string\">&#x27;chessGame&#x27;\u003C\u002Fspan>)\n  \u003Cspan class=\"hljs-keyword\">await\u003C\u002Fspan> game.\u003Cspan class=\"hljs-title function_\">load\u003C\u002Fspan>()\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (shared.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan>) {\n    game.\u003Cspan class=\"hljs-title function_\">replay\u003C\u002Fspan>(shared)\n    view.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = game.\u003Cspan class=\"hljs-property\">plies\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">void\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">navigateTo\u003C\u002Fspan>({ \u003Cspan class=\"hljs-attr\">path\u003C\u002Fspan>: route.\u003Cspan class=\"hljs-property\">path\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">query\u003C\u002Fspan>: {} }, { \u003Cspan class=\"hljs-attr\">replace\u003C\u002Fspan>: \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan> })\n  } \u003Cspan class=\"hljs-keyword\">else\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (saved?.\u003Cspan class=\"hljs-property\">n\u003C\u002Fspan> === n.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> &amp;&amp; \u003Cspan class=\"hljs-title class_\">Array\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">isArray\u003C\u002Fspan>(saved.\u003Cspan class=\"hljs-property\">moves\u003C\u002Fspan>)) game.\u003Cspan class=\"hljs-title function_\">replay\u003C\u002Fspan>(saved.\u003Cspan class=\"hljs-property\">moves\u003C\u002Fspan>)\n  restored = \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>\n})\n\u003Cspan class=\"hljs-title function_\">watch\u003C\u002Fspan>(game.\u003Cspan class=\"hljs-property\">moves\u003C\u002Fspan>, \u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">moves\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> {\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!restored) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">g\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">SavedGame\u003C\u002Fspan> = { \u003Cspan class=\"hljs-attr\">n\u003C\u002Fspan>: n.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, moves }\n  \u003Cspan class=\"hljs-title function_\">writeSession\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;chessGame&#x27;\u003C\u002Fspan>, g)\n  \u003Cspan class=\"hljs-title function_\">writeStore\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;chessGame&#x27;\u003C\u002Fspan>, g)\n})\n\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">move\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">m: Parameters&lt;\u003Cspan class=\"hljs-keyword\">typeof\u003C\u002Fspan> game.play&gt;[\u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>]\u003C\u002Fspan>) { premove.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>; game.\u003Cspan class=\"hljs-title function_\">play\u003C\u002Fspan>(m) }\n\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> yourTurn = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> players.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>[game.\u003Cspan class=\"hljs-property\">turn\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>] === \u003Cspan class=\"hljs-string\">&#x27;human&#x27;\u003C\u002Fspan> &amp;&amp; !game.\u003Cspan class=\"hljs-property\">outcome\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> &amp;&amp; view.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-literal\">null\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">boardGrid\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">\u003C\u002Fspan>) =&gt; \u003Cspan class=\"hljs-variable language_\">document\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">querySelector\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;.board__grid&#x27;\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-title function_\">useSiteTool\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> ({\n  \u003Cspan class=\"hljs-attr\">name\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;chess_move&#x27;\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">description\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Play a chess move for the person’s side, when it is their turn&#x27;\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">arg\u003C\u002Fspan>: { \u003Cspan class=\"hljs-attr\">name\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;move&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">description\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;The move, in SAN (e4, Nf3, O-O)&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">values\u003C\u002Fspan>: yourTurn.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? game.\u003Cspan class=\"hljs-property\">legal\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">map\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">l\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> ({ \u003Cspan class=\"hljs-attr\">value\u003C\u002Fspan>: l.\u003Cspan class=\"hljs-property\">san\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: l.\u003Cspan class=\"hljs-property\">san\u003C\u002Fspan> })) : [] },\n  \u003Cspan class=\"hljs-attr\">doing\u003C\u002Fspan>: \u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">label\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">`playing \u003Cspan class=\"hljs-subst\">${label}\u003C\u002Fspan>`\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">target\u003C\u002Fspan>: boardGrid,\n  \u003Cspan class=\"hljs-attr\">run\u003C\u002Fspan>: \u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">value\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> {\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> l = game.\u003Cspan class=\"hljs-property\">legal\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">find\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">x\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> x.\u003Cspan class=\"hljs-property\">san\u003C\u002Fspan> === value)\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!l) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-title function_\">move\u003C\u002Fspan>(l.\u003Cspan class=\"hljs-property\">move\u003C\u002Fspan>)\n    \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> game.\u003Cspan class=\"hljs-property\">outcome\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${game.outcome.value.reason}\u003C\u002Fspan>.`\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${cap(game.turn.value)}\u003C\u002Fspan> to move.`\u003C\u002Fspan>\n  },\n}))\n\u003Cspan class=\"hljs-title function_\">useSiteTool\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> ({\n  \u003Cspan class=\"hljs-attr\">name\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;chess_state&#x27;\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">description\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Read the chess game: who plays, whose turn, the position (FEN), the moves so far and the legal moves&#x27;\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">doing\u003C\u002Fspan>: \u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;reading the board&#x27;\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">run\u003C\u002Fspan>: \u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> [\n    \u003Cspan class=\"hljs-string\">`Mode: \u003Cspan class=\"hljs-subst\">${modeLabel.value}\u003C\u002Fspan>.`\u003C\u002Fspan>,\n    \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${cap(game.turn.value)}\u003C\u002Fspan> to move\u003Cspan class=\"hljs-subst\">${yourTurn.value ? \u003Cspan class=\"hljs-string\">&#x27; (the person’s turn)&#x27;\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan>}\u003C\u002Fspan>.`\u003C\u002Fspan>,\n    \u003Cspan class=\"hljs-string\">`FEN: \u003Cspan class=\"hljs-subst\">${game.fen.value}\u003C\u002Fspan>`\u003C\u002Fspan>,\n    \u003Cspan class=\"hljs-string\">`Moves: \u003Cspan class=\"hljs-subst\">${game.plies.value.map((p) =&gt; p.san).join(\u003Cspan class=\"hljs-string\">&#x27; &#x27;\u003C\u002Fspan>) || \u003Cspan class=\"hljs-string\">&#x27;none yet&#x27;\u003C\u002Fspan>}\u003C\u002Fspan>`\u003C\u002Fspan>,\n    \u003Cspan class=\"hljs-string\">`Legal: \u003Cspan class=\"hljs-subst\">${game.legal.value.map((l) =&gt; l.san).join(\u003Cspan class=\"hljs-string\">&#x27; &#x27;\u003C\u002Fspan>)}\u003C\u002Fspan>`\u003C\u002Fspan>,\n  ].\u003Cspan class=\"hljs-title function_\">join\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;\\n&#x27;\u003C\u002Fspan>),\n  \u003Cspan class=\"hljs-attr\">readOnly\u003C\u002Fspan>: \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">agentOnly\u003C\u002Fspan>: \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>,\n}))\n\u003Cspan class=\"hljs-title function_\">useSiteTool\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> ({\n  \u003Cspan class=\"hljs-attr\">name\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;chess_mode&#x27;\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">description\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Choose who plays: watch Jev play itself or the engine, play Jev, play the simple engine, or play a friend&#x27;\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">arg\u003C\u002Fspan>: { \u003Cspan class=\"hljs-attr\">name\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;mode&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">description\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Who plays&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">values\u003C\u002Fspan>: \u003Cspan class=\"hljs-variable constant_\">MODES\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">map\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">m\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> ({ \u003Cspan class=\"hljs-attr\">value\u003C\u002Fspan>: m.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: m.\u003Cspan class=\"hljs-property\">label\u003C\u002Fspan> })) },\n  \u003Cspan class=\"hljs-attr\">doing\u003C\u002Fspan>: \u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">label\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">`choosing “\u003Cspan class=\"hljs-subst\">${label}\u003C\u002Fspan>”`\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">target\u003C\u002Fspan>: \u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-variable language_\">document\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">querySelector\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;[aria-label=&quot;What to do&quot;]&#x27;\u003C\u002Fspan>),\n  \u003Cspan class=\"hljs-comment\">\u002F\u002F asking to watch is pressing Play\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-attr\">run\u003C\u002Fspan>: \u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">value\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> { \u003Cspan class=\"hljs-title function_\">choose\u003C\u002Fspan>(value \u003Cspan class=\"hljs-keyword\">as\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Mode\u003C\u002Fspan>); \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (auto.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) paused.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan> },\n  \u003Cspan class=\"hljs-attr\">readOnly\u003C\u002Fspan>: \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>,\n}))\n\u003Cspan class=\"hljs-title function_\">useSiteTool\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> ({\n  \u003Cspan class=\"hljs-attr\">name\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;chess_flip&#x27;\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">description\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Turn the chess board around&#x27;\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">doing\u003C\u002Fspan>: \u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;flipping the board&#x27;\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">target\u003C\u002Fspan>: boardGrid,\n  \u003Cspan class=\"hljs-attr\">run\u003C\u002Fspan>: \u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> { flipped.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = !flipped.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> },\n  \u003Cspan class=\"hljs-attr\">readOnly\u003C\u002Fspan>: \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>,\n}))\n\u003Cspan class=\"hljs-title function_\">useSiteTool\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> ({\n  \u003Cspan class=\"hljs-attr\">name\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;chess_coach&#x27;\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">description\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Turn the chess coach (Stockfish, which suggests moves) on or off&#x27;\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">arg\u003C\u002Fspan>: { \u003Cspan class=\"hljs-attr\">name\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;state&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">description\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;On or off&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">values\u003C\u002Fspan>: [{ \u003Cspan class=\"hljs-attr\">value\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;on&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;on&#x27;\u003C\u002Fspan> }, { \u003Cspan class=\"hljs-attr\">value\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;off&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;off&#x27;\u003C\u002Fspan> }] },\n  \u003Cspan class=\"hljs-attr\">doing\u003C\u002Fspan>: \u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">label\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">`turning the coach \u003Cspan class=\"hljs-subst\">${label}\u003C\u002Fspan>`\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">run\u003C\u002Fspan>: \u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">value\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> { coach.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = value === \u003Cspan class=\"hljs-string\">&#x27;on&#x27;\u003C\u002Fspan> },\n  \u003Cspan class=\"hljs-attr\">readOnly\u003C\u002Fspan>: \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>,\n}))\n\u003Cspan class=\"hljs-title function_\">useSiteTool\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> ({\n  \u003Cspan class=\"hljs-attr\">name\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;chess_hint&#x27;\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">description\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Ask the coach (Stockfish) which move it would play now, on the person’s turn&#x27;\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">doing\u003C\u002Fspan>: \u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;asking the coach&#x27;\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">target\u003C\u002Fspan>: boardGrid,\n  \u003Cspan class=\"hljs-attr\">run\u003C\u002Fspan>: \u003Cspan class=\"hljs-title function_\">async\u003C\u002Fspan> () =&gt; {\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!yourTurn.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;It isn’t your move.&#x27;\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> k = game.\u003Cspan class=\"hljs-property\">plies\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan>\n    coach.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">await\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">until\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> scored.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>[k]).\u003Cspan class=\"hljs-title function_\">toBeTruthy\u003C\u002Fspan>({ \u003Cspan class=\"hljs-attr\">timeout\u003C\u002Fspan>: \u003Cspan class=\"hljs-number\">10_000\u003C\u002Fspan> })\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> best = scored.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>[k]?.\u003Cspan class=\"hljs-property\">best\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> best ? \u003Cspan class=\"hljs-title function_\">fill\u003C\u002Fspan>(companion.\u003Cspan class=\"hljs-property\">coach\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">hint\u003C\u002Fspan>, { \u003Cspan class=\"hljs-attr\">best\u003C\u002Fspan>: game.\u003Cspan class=\"hljs-title function_\">sanAt\u003C\u002Fspan>(k, best) }) : \u003Cspan class=\"hljs-string\">&#x27;The coach has no answer yet.&#x27;\u003C\u002Fspan>\n  },\n  \u003Cspan class=\"hljs-attr\">readOnly\u003C\u002Fspan>: \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>,\n}))\n\u003Cspan class=\"hljs-title function_\">useSiteTool\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> ({\n  \u003Cspan class=\"hljs-attr\">name\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;chess_new_game&#x27;\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">description\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Start a new chess game&#x27;\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">doing\u003C\u002Fspan>: \u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;starting a new game&#x27;\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">target\u003C\u002Fspan>: boardGrid,\n  \u003Cspan class=\"hljs-attr\">run\u003C\u002Fspan>: newGame,\n  \u003Cspan class=\"hljs-attr\">readOnly\u003C\u002Fspan>: \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>,\n}))\n\n\u003Cspan class=\"hljs-comment\">\u002F\u002F Only a game played out on this page is kept: one opened from a link or restored after a reload is not.\u003C\u002Fspan>\n\u003Cspan class=\"hljs-comment\">\u002F\u002F The outcome is read after the moves&#x27; watcher has run (flush: post), so `playedHere` is current.\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> kept = ref&lt;string&gt;()\n\u003Cspan class=\"hljs-keyword\">let\u003C\u002Fspan> playedHere = \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">let\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">times\u003C\u002Fspan>: number[] = [], lastMoveAt = \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>\n\u003Cspan class=\"hljs-title function_\">watch\u003C\u002Fspan>(game.\u003Cspan class=\"hljs-property\">moves\u003C\u002Fspan>, \u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">now, before\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> {\n  playedHere = restored &amp;&amp; now.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> === (before?.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> ?? \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>) + \u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (playedHere) { times = [...times.\u003Cspan class=\"hljs-title function_\">slice\u003C\u002Fspan>(\u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>, now.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> - \u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>), lastMoveAt ? \u003Cspan class=\"hljs-title class_\">Date\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">now\u003C\u002Fspan>() - lastMoveAt : \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>]; lastMoveAt = \u003Cspan class=\"hljs-title class_\">Date\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">now\u003C\u002Fspan>() } \u003Cspan class=\"hljs-keyword\">else\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (now.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> &lt; times.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan>) times = times.\u003Cspan class=\"hljs-title function_\">slice\u003C\u002Fspan>(\u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>, now.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan>)\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!now.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan>) { times = []; lastMoveAt = \u003Cspan class=\"hljs-title class_\">Date\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">now\u003C\u002Fspan>() }\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (now.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> &lt; (before?.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> ?? \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>)) kept.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>\n})\n\u003Cspan class=\"hljs-title function_\">watch\u003C\u002Fspan>(game.\u003Cspan class=\"hljs-property\">outcome\u003C\u002Fspan>, \u003Cspan class=\"hljs-title function_\">async\u003C\u002Fspan> (o) =&gt; {\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!o || !playedHere || kept.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> { white, black } = players.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">try\u003C\u002Fspan> {\n    kept.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = (\u003Cspan class=\"hljs-keyword\">await\u003C\u002Fspan> $fetch&lt;{ \u003Cspan class=\"hljs-attr\">id\u003C\u002Fspan>: string }&gt;(\u003Cspan class=\"hljs-string\">&#x27;\u002Fapi\u002Fchess\u002Fgames&#x27;\u003C\u002Fspan>, { \u003Cspan class=\"hljs-attr\">method\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;POST&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">body\u003C\u002Fspan>: { \u003Cspan class=\"hljs-attr\">n\u003C\u002Fspan>: n.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">moves\u003C\u002Fspan>: game.\u003Cspan class=\"hljs-property\">moves\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">mode\u003C\u002Fspan>: mode.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, white, black, \u003Cspan class=\"hljs-attr\">device\u003C\u002Fspan>: \u003Cspan class=\"hljs-title function_\">deviceId\u003C\u002Fspan>(), \u003Cspan class=\"hljs-attr\">times\u003C\u002Fspan>: times.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> === game.\u003Cspan class=\"hljs-property\">moves\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> ? times : \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan> } })).\u003Cspan class=\"hljs-property\">id\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-title function_\">track\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;chess_game_end&#x27;\u003C\u002Fspan>, { \u003Cspan class=\"hljs-attr\">mode\u003C\u002Fspan>: mode.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">result\u003C\u002Fspan>: o.\u003Cspan class=\"hljs-property\">winner\u003C\u002Fspan> ?? \u003Cspan class=\"hljs-string\">&#x27;draw&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">reason\u003C\u002Fspan>: o.\u003Cspan class=\"hljs-property\">reason\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">plies\u003C\u002Fspan>: game.\u003Cspan class=\"hljs-property\">moves\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">variant\u003C\u002Fspan>: is960.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;chess960&#x27;\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;chess&#x27;\u003C\u002Fspan> })\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (railTab.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;score&#x27;\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">void\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">fetchScores\u003C\u002Fspan>()\n  } \u003Cspan class=\"hljs-keyword\">catch\u003C\u002Fspan> {}\n}, { \u003Cspan class=\"hljs-attr\">flush\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;post&#x27;\u003C\u002Fspan> })\n\n\u003Cspan class=\"hljs-comment\">\u002F\u002F a new game moves it on, so a turn still waiting on an old answer ends quietly\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">let\u003C\u002Fspan> turn = \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">async\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">runEngine\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">\u003C\u002Fspan>) {\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> side = players.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>[game.\u003Cspan class=\"hljs-property\">turn\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>]\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (side === \u003Cspan class=\"hljs-string\">&#x27;human&#x27;\u003C\u002Fspan> || game.\u003Cspan class=\"hljs-property\">outcome\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> || !game.\u003Cspan class=\"hljs-property\">ready\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> || thinking.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> || viewing.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> || (auto.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> &amp;&amp; paused.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>)) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> mine = ++turn\n  thinking.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = side\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> d = \u003Cspan class=\"hljs-keyword\">await\u003C\u002Fspan> game.\u003Cspan class=\"hljs-title function_\">engineMove\u003C\u002Fspan>(side, \u003Cspan class=\"hljs-variable constant_\">WATCH_SPEEDS\u003C\u002Fspan>[speed.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>], level.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, \u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">d\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> { considering.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = d.\u003Cspan class=\"hljs-property\">candidates\u003C\u002Fspan> }, !auto.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>)\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (mine !== turn) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n  considering.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>\n  thinking.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (d?.\u003Cspan class=\"hljs-property\">resting\u003C\u002Fspan>) { \u003Cspan class=\"hljs-title function_\">rest\u003C\u002Fspan>(d.\u003Cspan class=\"hljs-property\">resting\u003C\u002Fspan>); \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> }\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (d) { decision.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = d; decisions.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = { ...decisions.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, [game.\u003Cspan class=\"hljs-property\">plies\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> - \u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>]: d } }\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (d?.\u003Cspan class=\"hljs-property\">engine\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;jev&#x27;\u003C\u002Fspan> &amp;&amp; !d.\u003Cspan class=\"hljs-property\">forced\u003C\u002Fspan>) {\n    jevTimes.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = [...jevTimes.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">slice\u003C\u002Fspan>(\u003Cspan class=\"hljs-number\">1\u003C\u002Fspan> - \u003Cspan class=\"hljs-variable constant_\">SPARK\u003C\u002Fspan>), d.\u003Cspan class=\"hljs-property\">ms\u003C\u002Fspan>]\n    jevTimeBy.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = { ...jevTimeBy.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, [\u003Cspan class=\"hljs-title function_\">other\u003C\u002Fspan>(game.\u003Cspan class=\"hljs-property\">turn\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>)]: d.\u003Cspan class=\"hljs-property\">ms\u003C\u002Fspan> }\n  }\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (d?.\u003Cspan class=\"hljs-property\">engine\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;jev&#x27;\u003C\u002Fspan> &amp;&amp; d.\u003Cspan class=\"hljs-property\">candidates\u003C\u002Fspan>?.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan>) jevNotes.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = { ...jevNotes.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, [game.\u003Cspan class=\"hljs-property\">plies\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> - \u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>]: \u003Cspan class=\"hljs-string\">`Jev: \u003Cspan class=\"hljs-subst\">${d.candidates.slice(\u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>, \u003Cspan class=\"hljs-number\">3\u003C\u002Fspan>).map((c) =&gt; \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${c.san}\u003C\u002Fspan> \u003Cspan class=\"hljs-subst\">${pct(c.p)}\u003C\u002Fspan>`\u003C\u002Fspan>).join(\u003Cspan class=\"hljs-string\">&#x27;, &#x27;\u003C\u002Fspan>)}\u003C\u002Fspan>`\u003C\u002Fspan> }\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (d &amp;&amp; auto.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) \u003Cspan class=\"hljs-title function_\">tally\u003C\u002Fspan>(game.\u003Cspan class=\"hljs-property\">outcome\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>)\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (d?.\u003Cspan class=\"hljs-property\">reading\u003C\u002Fspan>?.\u003Cspan class=\"hljs-property\">eval\u003C\u002Fspan> !== \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan> &amp;&amp; !coach.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) evalShare.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = d.\u003Cspan class=\"hljs-property\">reading\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">eval\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (d?.\u003Cspan class=\"hljs-property\">engine\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;jev&#x27;\u003C\u002Fspan>) \u003Cspan class=\"hljs-title function_\">sayPlan\u003C\u002Fspan>(d.\u003Cspan class=\"hljs-property\">reading\u003C\u002Fspan>?.\u003Cspan class=\"hljs-property\">plan\u003C\u002Fspan>)\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (d?.\u003Cspan class=\"hljs-property\">engine\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;jev&#x27;\u003C\u002Fspan> &amp;&amp; players.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>[game.\u003Cspan class=\"hljs-property\">turn\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>] === \u003Cspan class=\"hljs-string\">&#x27;human&#x27;\u003C\u002Fspan>) {\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> atPly = game.\u003Cspan class=\"hljs-property\">plies\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">void\u003C\u002Fspan> game.\u003Cspan class=\"hljs-title function_\">predictReply\u003C\u002Fspan>().\u003Cspan class=\"hljs-title function_\">then\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">g\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> { \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (g &amp;&amp; game.\u003Cspan class=\"hljs-property\">plies\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> === atPly) guess.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = { atPly, ...g } })\n  }\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> pm = premove.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>\n  premove.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (pm &amp;&amp; players.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>[game.\u003Cspan class=\"hljs-property\">turn\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>] === \u003Cspan class=\"hljs-string\">&#x27;human&#x27;\u003C\u002Fspan>) {\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> m = game.\u003Cspan class=\"hljs-title function_\">targets\u003C\u002Fspan>(pm.\u003Cspan class=\"hljs-property\">from\u003C\u002Fspan>).\u003Cspan class=\"hljs-title function_\">get\u003C\u002Fspan>(pm.\u003Cspan class=\"hljs-property\">to\u003C\u002Fspan>)\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (m) game.\u003Cspan class=\"hljs-title function_\">play\u003C\u002Fspan>(game.\u003Cspan class=\"hljs-title function_\">needsPromotion\u003C\u002Fspan>(m) ? { ...m, \u003Cspan class=\"hljs-attr\">promotion\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;queen&#x27;\u003C\u002Fspan> } : m)\n  }\n  \u003Cspan class=\"hljs-comment\">\u002F\u002F the move above re-ran the watcher while this turn still counted as thinking\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">void\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">nextTick\u003C\u002Fspan>(runEngine)\n}\n\u003Cspan class=\"hljs-title function_\">watch\u003C\u002Fspan>([engineTurn, \u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> game.\u003Cspan class=\"hljs-property\">plies\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan>, paused, \u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> game.\u003Cspan class=\"hljs-property\">ready\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, players, viewing], \u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> { \u003Cspan class=\"hljs-keyword\">void\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">runEngine\u003C\u002Fspan>() })\n\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">undo\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">\u003C\u002Fspan>) {\n  premove.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (auto.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) { paused.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>; game.\u003Cspan class=\"hljs-title function_\">undo\u003C\u002Fspan>(); \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> }\n  game.\u003Cspan class=\"hljs-title function_\">undo\u003C\u002Fspan>()\n  \u003Cspan class=\"hljs-keyword\">while\u003C\u002Fspan> (game.\u003Cspan class=\"hljs-property\">plies\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> &amp;&amp; players.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>[game.\u003Cspan class=\"hljs-property\">turn\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>] !== \u003Cspan class=\"hljs-string\">&#x27;human&#x27;\u003C\u002Fspan>) game.\u003Cspan class=\"hljs-title function_\">undo\u003C\u002Fspan>()\n}\n\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">newGame\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">\u003C\u002Fspan>) { \u003Cspan class=\"hljs-title function_\">track\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;chess_new_game&#x27;\u003C\u002Fspan>, { \u003Cspan class=\"hljs-attr\">mode\u003C\u002Fspan>: mode.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">variant\u003C\u002Fspan>: is960.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;chess960&#x27;\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;chess&#x27;\u003C\u002Fspan> }); turn++; \u003Cspan class=\"hljs-title function_\">seat\u003C\u002Fspan>(); view.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">null\u003C\u002Fspan>; jevTimeBy.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = {}; scored.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = {}; verdict.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>; jevNotes.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = {}; jevTimes.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = []; lastPlan = \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>; planAt = -\u003Cspan class=\"hljs-variable constant_\">PLAN_GAP\u003C\u002Fspan>; thinking.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>; considering.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>; premove.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>; decision.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>; decisions.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = {}; evalShare.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>; guess.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>; reveal.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>; reviewing.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>; \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (auto.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) paused.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>; game.\u003Cspan class=\"hljs-title function_\">reset\u003C\u002Fspan>(); \u003Cspan class=\"hljs-keyword\">void\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">nextTick\u003C\u002Fspan>(runEngine); \u003Cspan class=\"hljs-keyword\">void\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">nextTick\u003C\u002Fspan>(coachTurn) }\n\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> coach = \u003Cspan class=\"hljs-title function_\">useStored\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;chessCoach&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>, \u003Cspan class=\"hljs-title function_\">oneOf\u003C\u002Fspan>(\u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>, \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> stockfish = \u003Cspan class=\"hljs-title function_\">useStockfish\u003C\u002Fspan>()\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> scored = ref&lt;\u003Cspan class=\"hljs-title class_\">Record\u003C\u002Fspan>&lt;number, \u003Cspan class=\"hljs-title class_\">Analysis\u003C\u002Fspan>&gt;&gt;({})\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> verdict = ref&lt;\u003Cspan class=\"hljs-title class_\">CoachVerdict\u003C\u002Fspan>&gt;()\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> coachThinking = \u003Cspan class=\"hljs-title function_\">ref\u003C\u002Fspan>(\u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">GRADES\u003C\u002Fspan>: [number, string][] = [[\u003Cspan class=\"hljs-number\">20\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;Best&#x27;\u003C\u002Fspan>], [\u003Cspan class=\"hljs-number\">50\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;Good&#x27;\u003C\u002Fspan>], [\u003Cspan class=\"hljs-number\">100\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;Inaccuracy&#x27;\u003C\u002Fspan>], [\u003Cspan class=\"hljs-number\">250\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;Mistake&#x27;\u003C\u002Fspan>], [\u003Cspan class=\"hljs-title class_\">Infinity\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;Blunder&#x27;\u003C\u002Fspan>]]\n\u003Cspan class=\"hljs-keyword\">async\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">coachTurn\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">\u003C\u002Fspan>) {\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!coach.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> || !game.\u003Cspan class=\"hljs-property\">ready\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> || viewing.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> k = game.\u003Cspan class=\"hljs-property\">plies\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan>, key = game.\u003Cspan class=\"hljs-property\">moves\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">join\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;.&#x27;\u003C\u002Fspan>)\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!scored.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>[k]) {\n    coachThinking.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> a = \u003Cspan class=\"hljs-keyword\">await\u003C\u002Fspan> stockfish.\u003Cspan class=\"hljs-title function_\">analyse\u003C\u002Fspan>(game.\u003Cspan class=\"hljs-title function_\">fenAt\u003C\u002Fspan>(k))\n    coachThinking.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!a || game.\u003Cspan class=\"hljs-property\">moves\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">join\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;.&#x27;\u003C\u002Fspan>) !== key) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n    scored.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = { ...scored.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, [k]: a }\n  }\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> now = scored.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>[k]!\n  evalShare.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-title function_\">chancesFromCp\u003C\u002Fspan>(now.\u003Cspan class=\"hljs-property\">cp\u003C\u002Fspan>)\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> ply = game.\u003Cspan class=\"hljs-property\">plies\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>[k - \u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>], before = scored.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>[k - \u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>]\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!ply || !before || verdict.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>?.\u003Cspan class=\"hljs-property\">ply\u003C\u002Fspan> === k - \u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> mover = k % \u003Cspan class=\"hljs-number\">2\u003C\u002Fspan> === \u003Cspan class=\"hljs-number\">1\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;black&#x27;\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (players.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>[mover] !== \u003Cspan class=\"hljs-string\">&#x27;human&#x27;\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> sign = mover === \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan> ? \u003Cspan class=\"hljs-number\">1\u003C\u002Fspan> : -\u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> loss = \u003Cspan class=\"hljs-title class_\">Math\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">max\u003C\u002Fspan>(\u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>, sign * (before.\u003Cspan class=\"hljs-property\">cp\u003C\u002Fspan> - now.\u003Cspan class=\"hljs-property\">cp\u003C\u002Fspan>))\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> bestUci = before.\u003Cspan class=\"hljs-property\">best\u003C\u002Fspan>, playedUci = game.\u003Cspan class=\"hljs-property\">moves\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>[k - \u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>]\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> grade = bestUci === playedUci ? \u003Cspan class=\"hljs-string\">&#x27;Best&#x27;\u003C\u002Fspan> : \u003Cspan class=\"hljs-variable constant_\">GRADES\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">find\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">[max]\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> loss &lt;= max)![\u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>]\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">CoachVerdict\u003C\u002Fspan> = { \u003Cspan class=\"hljs-attr\">ply\u003C\u002Fspan>: k - \u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">san\u003C\u002Fspan>: ply.\u003Cspan class=\"hljs-property\">san\u003C\u002Fspan>, grade, loss, \u003Cspan class=\"hljs-attr\">best\u003C\u002Fspan>: bestUci &amp;&amp; bestUci !== playedUci ? game.\u003Cspan class=\"hljs-title function_\">sanAt\u003C\u002Fspan>(k - \u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>, bestUci) : \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan> }\n  verdict.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = v\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (grade === \u003Cspan class=\"hljs-string\">&#x27;Best&#x27;\u003C\u002Fspan> || grade === \u003Cspan class=\"hljs-string\">&#x27;Good&#x27;\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">coachSays\u003C\u002Fspan>(v)\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> r = \u003Cspan class=\"hljs-keyword\">await\u003C\u002Fspan> $fetch&lt;{ label?: string; tip?: string }&gt;(\u003Cspan class=\"hljs-string\">&#x27;\u002Fapi\u002Fchess\u002Fcoach&#x27;\u003C\u002Fspan>, { \u003Cspan class=\"hljs-attr\">method\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;POST&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">body\u003C\u002Fspan>: { \u003Cspan class=\"hljs-attr\">fen\u003C\u002Fspan>: game.\u003Cspan class=\"hljs-title function_\">fenAt\u003C\u002Fspan>(k - \u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>), \u003Cspan class=\"hljs-attr\">played\u003C\u002Fspan>: ply.\u003Cspan class=\"hljs-property\">san\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">best\u003C\u002Fspan>: v.\u003Cspan class=\"hljs-property\">best\u003C\u002Fspan>, loss, grade } }).\u003Cspan class=\"hljs-title function_\">catch\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>)\n  \u003Cspan class=\"hljs-comment\">\u002F\u002F a ref holds a reactive copy, so compare by move, not by object\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (verdict.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>?.\u003Cspan class=\"hljs-property\">ply\u003C\u002Fspan> !== v.\u003Cspan class=\"hljs-property\">ply\u003C\u002Fspan> || game.\u003Cspan class=\"hljs-property\">moves\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> !== k) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (r?.\u003Cspan class=\"hljs-property\">label\u003C\u002Fspan>) verdict.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = { ...v, \u003Cspan class=\"hljs-attr\">lesson\u003C\u002Fspan>: r.\u003Cspan class=\"hljs-property\">label\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">tip\u003C\u002Fspan>: r.\u003Cspan class=\"hljs-property\">tip\u003C\u002Fspan> }\n  \u003Cspan class=\"hljs-title function_\">coachSays\u003C\u002Fspan>(verdict.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>)\n}\n\u003Cspan class=\"hljs-comment\">\u002F\u002F Jevvie says Jev&#x27;s plan when it changes, not more than once every few moves, and not over the coach\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-variable constant_\">PLAN_GAP\u003C\u002Fspan> = \u003Cspan class=\"hljs-number\">6\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">let\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">lastPlan\u003C\u002Fspan>: string | \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>, planAt = -\u003Cspan class=\"hljs-variable constant_\">PLAN_GAP\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">sayPlan\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">plan?: string\u003C\u002Fspan>) {\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> lines = plan &amp;&amp; companion.\u003Cspan class=\"hljs-property\">plans\u003C\u002Fspan>[plan \u003Cspan class=\"hljs-keyword\">as\u003C\u002Fspan> keyof \u003Cspan class=\"hljs-keyword\">typeof\u003C\u002Fspan> companion.\u003Cspan class=\"hljs-property\">plans\u003C\u002Fspan>]\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> at = game.\u003Cspan class=\"hljs-property\">plies\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!lines || plan === lastPlan || at - planAt &lt; \u003Cspan class=\"hljs-variable constant_\">PLAN_GAP\u003C\u002Fspan> || coach.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n  lastPlan = plan; planAt = at\n  \u003Cspan class=\"hljs-title function_\">jevvieSay\u003C\u002Fspan>({ \u003Cspan class=\"hljs-attr\">text\u003C\u002Fspan>: \u003Cspan class=\"hljs-title function_\">pickLine\u003C\u002Fspan>(lines), \u003Cspan class=\"hljs-attr\">mood\u003C\u002Fspan>: plan === \u003Cspan class=\"hljs-string\">&#x27;attack&#x27;\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;surprised&#x27;\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;think&#x27;\u003C\u002Fspan> })\n}\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-variable constant_\">COACH_FACE\u003C\u002Fspan> = { \u003Cspan class=\"hljs-title class_\">Best\u003C\u002Fspan>: [\u003Cspan class=\"hljs-string\">&#x27;love&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;jump&#x27;\u003C\u002Fspan>], \u003Cspan class=\"hljs-title class_\">Good\u003C\u002Fspan>: [\u003Cspan class=\"hljs-string\">&#x27;happy&#x27;\u003C\u002Fspan>], \u003Cspan class=\"hljs-title class_\">Inaccuracy\u003C\u002Fspan>: [\u003Cspan class=\"hljs-string\">&#x27;think&#x27;\u003C\u002Fspan>], \u003Cspan class=\"hljs-title class_\">Mistake\u003C\u002Fspan>: [\u003Cspan class=\"hljs-string\">&#x27;confused&#x27;\u003C\u002Fspan>], \u003Cspan class=\"hljs-title class_\">Blunder\u003C\u002Fspan>: [\u003Cspan class=\"hljs-string\">&#x27;surprised&#x27;\u003C\u002Fspan>], \u003Cspan class=\"hljs-attr\">mate\u003C\u002Fspan>: [\u003Cspan class=\"hljs-string\">&#x27;surprised&#x27;\u003C\u002Fspan>] } \u003Cspan class=\"hljs-keyword\">as\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">coachSays\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">v: CoachVerdict\u003C\u002Fspan>) {\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> key = v.\u003Cspan class=\"hljs-property\">loss\u003C\u002Fspan> &gt;= \u003Cspan class=\"hljs-number\">5000\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;mate&#x27;\u003C\u002Fspan> : (v.\u003Cspan class=\"hljs-property\">grade\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">as\u003C\u002Fspan> keyof \u003Cspan class=\"hljs-keyword\">typeof\u003C\u002Fspan> companion.\u003Cspan class=\"hljs-property\">coach\u003C\u002Fspan>)\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> lines = companion.\u003Cspan class=\"hljs-property\">coach\u003C\u002Fspan>[key]\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!\u003Cspan class=\"hljs-title class_\">Array\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">isArray\u003C\u002Fspan>(lines)) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> pawns = (v.\u003Cspan class=\"hljs-property\">loss\u003C\u002Fspan> \u002F \u003Cspan class=\"hljs-number\">100\u003C\u002Fspan>).\u003Cspan class=\"hljs-title function_\">toFixed\u003C\u002Fspan>(\u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>)\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> text = \u003Cspan class=\"hljs-title function_\">fill\u003C\u002Fspan>(\u003Cspan class=\"hljs-title function_\">pickLine\u003C\u002Fspan>(lines), { \u003Cspan class=\"hljs-attr\">san\u003C\u002Fspan>: v.\u003Cspan class=\"hljs-property\">san\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">best\u003C\u002Fspan>: v.\u003Cspan class=\"hljs-property\">best\u003C\u002Fspan> ?? \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">pawns\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${pawns}\u003C\u002Fspan> pawn\u003Cspan class=\"hljs-subst\">${pawns === \u003Cspan class=\"hljs-string\">&#x27;1.0&#x27;\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;s&#x27;\u003C\u002Fspan>}\u003C\u002Fspan>`\u003C\u002Fspan> })\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> [mood, trick] = \u003Cspan class=\"hljs-variable constant_\">COACH_FACE\u003C\u002Fspan>[key \u003Cspan class=\"hljs-keyword\">as\u003C\u002Fspan> keyof \u003Cspan class=\"hljs-keyword\">typeof\u003C\u002Fspan> \u003Cspan class=\"hljs-variable constant_\">COACH_FACE\u003C\u002Fspan>] ?? [\u003Cspan class=\"hljs-string\">&#x27;happy&#x27;\u003C\u002Fspan>]\n  \u003Cspan class=\"hljs-title function_\">jevvieSay\u003C\u002Fspan>({ \u003Cspan class=\"hljs-attr\">text\u003C\u002Fspan>: v.\u003Cspan class=\"hljs-property\">tip\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${text}\u003C\u002Fspan> \u003Cspan class=\"hljs-subst\">${v.tip}\u003C\u002Fspan>`\u003C\u002Fspan> : text, mood, trick })\n}\n\u003Cspan class=\"hljs-title function_\">watch\u003C\u002Fspan>([coach, \u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> game.\u003Cspan class=\"hljs-property\">plies\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan>, \u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> game.\u003Cspan class=\"hljs-property\">ready\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, viewing], \u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> { \u003Cspan class=\"hljs-keyword\">void\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">coachTurn\u003C\u002Fspan>() })\n\u003Cspan class=\"hljs-title function_\">watch\u003C\u002Fspan>(coach, \u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">on\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> { \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!on) { stockfish.\u003Cspan class=\"hljs-title function_\">stop\u003C\u002Fspan>(); verdict.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>; scored.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = {} } })\n\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> evalShare = ref&lt;number&gt;()\n\u003Cspan class=\"hljs-comment\">\u002F\u002F the coach&#x27;s Stockfish score has no history\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> evalShown = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> (viewing.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> &amp;&amp; !coach.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? shownDecision.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>?.\u003Cspan class=\"hljs-property\">reading\u003C\u002Fspan>?.\u003Cspan class=\"hljs-property\">eval\u003C\u002Fspan> : evalShare.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> guess = ref&lt;{ \u003Cspan class=\"hljs-attr\">atPly\u003C\u002Fspan>: number; \u003Cspan class=\"hljs-attr\">san\u003C\u002Fspan>: string; \u003Cspan class=\"hljs-attr\">p\u003C\u002Fspan>: number }&gt;()\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> reveal = ref&lt;{ \u003Cspan class=\"hljs-attr\">expected\u003C\u002Fspan>: string; \u003Cspan class=\"hljs-attr\">p\u003C\u002Fspan>: number; \u003Cspan class=\"hljs-attr\">played\u003C\u002Fspan>: string; \u003Cspan class=\"hljs-attr\">hit\u003C\u002Fspan>: boolean }&gt;()\n\u003Cspan class=\"hljs-title function_\">watch\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> game.\u003Cspan class=\"hljs-property\">plies\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan>, \u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">len\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> {\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> g = guess.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (g &amp;&amp; len === g.\u003Cspan class=\"hljs-property\">atPly\u003C\u002Fspan> + \u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>) {\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> played = game.\u003Cspan class=\"hljs-property\">plies\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">at\u003C\u002Fspan>(-\u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>)!.\u003Cspan class=\"hljs-property\">san\u003C\u002Fspan>\n    reveal.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = { \u003Cspan class=\"hljs-attr\">expected\u003C\u002Fspan>: g.\u003Cspan class=\"hljs-property\">san\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">p\u003C\u002Fspan>: g.\u003Cspan class=\"hljs-property\">p\u003C\u002Fspan>, played, \u003Cspan class=\"hljs-attr\">hit\u003C\u002Fspan>: played === g.\u003Cspan class=\"hljs-property\">san\u003C\u002Fspan> }\n  }\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!g || len !== g.\u003Cspan class=\"hljs-property\">atPly\u003C\u002Fspan>) guess.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>\n})\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">pct\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">p?: number\u003C\u002Fspan>) =&gt; \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${\u003Cspan class=\"hljs-built_in\">Math\u003C\u002Fspan>.round((p ?? \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>) * \u003Cspan class=\"hljs-number\">100\u003C\u002Fspan>)}\u003C\u002Fspan>%`\u003C\u002Fspan>\n\u003Cspan class=\"hljs-comment\">\u002F\u002F always five rows, so nothing below the panel moves\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> jevDecision = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> (shownDecision.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>?.\u003Cspan class=\"hljs-property\">engine\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;jev&#x27;\u003C\u002Fspan> ? shownDecision.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> : \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-variable constant_\">FORCED\u003C\u002Fspan> = { \u003Cspan class=\"hljs-attr\">legal\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;its only legal move&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">safe\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;the only move that loses nothing, so it was not asked&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">mate\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;the rules found mate, so it was not asked&#x27;\u003C\u002Fspan> } \u003Cspan class=\"hljs-keyword\">as\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-variable constant_\">FORCED_NOTE\u003C\u002Fspan> = { \u003Cspan class=\"hljs-attr\">legal\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Its only legal move&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">safe\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Its only safe move&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">mate\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Mate, found by the rules&#x27;\u003C\u002Fspan> } \u003Cspan class=\"hljs-keyword\">as\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> narration = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> {\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> d = shownDecision.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!d || d.\u003Cspan class=\"hljs-property\">engine\u003C\u002Fspan> !== \u003Cspan class=\"hljs-string\">&#x27;jev&#x27;\u003C\u002Fspan> || !d.\u003Cspan class=\"hljs-property\">candidates\u003C\u002Fspan>?.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (d.\u003Cspan class=\"hljs-property\">forced\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">`Jev played \u003Cspan class=\"hljs-subst\">${d.san}\u003C\u002Fspan>: \u003Cspan class=\"hljs-subst\">${FORCED[d.forced]}\u003C\u002Fspan>.`\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> share = d.\u003Cspan class=\"hljs-property\">candidates\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">find\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">c\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> c.\u003Cspan class=\"hljs-property\">san\u003C\u002Fspan> === d.\u003Cspan class=\"hljs-property\">san\u003C\u002Fspan>)?.\u003Cspan class=\"hljs-property\">p\u003C\u002Fspan> ?? \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> c = d.\u003Cspan class=\"hljs-property\">confidence\u003C\u002Fspan> ?? \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> mood = c &lt; \u003Cspan class=\"hljs-number\">0.25\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;and it was torn&#x27;\u003C\u002Fspan> : c &lt; \u003Cspan class=\"hljs-number\">0.55\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;and it leaned that way&#x27;\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;and it was sure&#x27;\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> offered = d.\u003Cspan class=\"hljs-property\">offered\u003C\u002Fspan> &amp;&amp; d.\u003Cspan class=\"hljs-property\">offered\u003C\u002Fspan> &lt; (d.\u003Cspan class=\"hljs-property\">options\u003C\u002Fspan> ?? \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>) ? \u003Cspan class=\"hljs-string\">` It was offered the \u003Cspan class=\"hljs-subst\">${d.offered}\u003C\u002Fspan> moves that lose nothing.`\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">`Jev played \u003Cspan class=\"hljs-subst\">${d.san}\u003C\u002Fspan>: \u003Cspan class=\"hljs-subst\">${pct(share)}\u003C\u002Fspan> of its belief went there, \u003Cspan class=\"hljs-subst\">${mood}\u003C\u002Fspan> (\u003Cspan class=\"hljs-subst\">${pct(c)}\u003C\u002Fspan> confident overall).\u003Cspan class=\"hljs-subst\">${offered}\u003C\u002Fspan>`\u003C\u002Fspan>\n})\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> readingLine = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> {\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> r = shownDecision.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>?.\u003Cspan class=\"hljs-property\">reading\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!r) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> sharp = r.\u003Cspan class=\"hljs-property\">sharpness\u003C\u002Fspan> === \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan> ? \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan> : r.\u003Cspan class=\"hljs-property\">sharpness\u003C\u002Fspan> &lt; \u003Cspan class=\"hljs-number\">0.34\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;quiet&#x27;\u003C\u002Fspan> : r.\u003Cspan class=\"hljs-property\">sharpness\u003C\u002Fspan> &lt; \u003Cspan class=\"hljs-number\">0.67\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;tense&#x27;\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;sharp&#x27;\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> [\n    r.\u003Cspan class=\"hljs-property\">kingRisk\u003C\u002Fspan> !== \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">`King risk \u003Cspan class=\"hljs-subst\">${pct(r.kingRisk)}\u003C\u002Fspan>`\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan>,\n    sharp ? \u003Cspan class=\"hljs-string\">`Position \u003Cspan class=\"hljs-subst\">${sharp}\u003C\u002Fspan>`\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan>,\n    r.\u003Cspan class=\"hljs-property\">plan\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">`Plan \u003Cspan class=\"hljs-subst\">${r.plan}\u003C\u002Fspan>`\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan>,\n  ].\u003Cspan class=\"hljs-title function_\">filter\u003C\u002Fspan>(\u003Cspan class=\"hljs-title class_\">Boolean\u003C\u002Fspan>)\n})\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> jevNotes = ref&lt;\u003Cspan class=\"hljs-title class_\">Record\u003C\u002Fspan>&lt;number, string&gt;&gt;({})\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">PLAYER_NAME\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">Record\u003C\u002Fspan>&lt;\u003Cspan class=\"hljs-title class_\">Player\u003C\u002Fspan>, string&gt; = { \u003Cspan class=\"hljs-attr\">human\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;You&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">jev\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Jev&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">simple\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Simple engine&#x27;\u003C\u002Fspan> }\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> jevTimeBy = ref&lt;{ white?: number; black?: number }&gt;({})\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">seatLine\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">c: \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan> | \u003Cspan class=\"hljs-string\">&#x27;black&#x27;\u003C\u002Fspan>\u003C\u002Fspan>) =&gt; {\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> who = players.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>[c]\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> lead = (balance.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">at\u003C\u002Fspan>(-\u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>) ?? \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>) * (c === \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan> ? \u003Cspan class=\"hljs-number\">1\u003C\u002Fspan> : -\u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>)\n  \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> {\n    \u003Cspan class=\"hljs-attr\">colour\u003C\u002Fspan>: c,\n    \u003Cspan class=\"hljs-attr\">name\u003C\u002Fspan>: mode.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;friend&#x27;\u003C\u002Fspan> ? \u003Cspan class=\"hljs-title function_\">cap\u003C\u002Fspan>(c) : \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${PLAYER_NAME[who]}\u003C\u002Fspan> · \u003Cspan class=\"hljs-subst\">${cap(c)}\u003C\u002Fspan>`\u003C\u002Fspan>,\n    \u003Cspan class=\"hljs-attr\">toMove\u003C\u002Fspan>: !game.\u003Cspan class=\"hljs-property\">outcome\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> &amp;&amp; game.\u003Cspan class=\"hljs-property\">turn\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === c,\n    \u003Cspan class=\"hljs-attr\">thinking\u003C\u002Fspan>: thinking.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> !== \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan> &amp;&amp; game.\u003Cspan class=\"hljs-property\">turn\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === c,\n    \u003Cspan class=\"hljs-attr\">note\u003C\u002Fspan>: [lead &gt; \u003Cspan class=\"hljs-number\">0\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">`+\u003Cspan class=\"hljs-subst\">${lead}\u003C\u002Fspan>`\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan>, who === \u003Cspan class=\"hljs-string\">&#x27;jev&#x27;\u003C\u002Fspan> &amp;&amp; jevTimeBy.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>[c] ? \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${jevTimeBy.value[c]}\u003C\u002Fspan> ms`\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan>].\u003Cspan class=\"hljs-title function_\">filter\u003C\u002Fspan>(\u003Cspan class=\"hljs-title class_\">Boolean\u003C\u002Fspan>).\u003Cspan class=\"hljs-title function_\">join\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27; · &#x27;\u003C\u002Fspan>),\n  }\n}\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> seats = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> (flipped.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? { \u003Cspan class=\"hljs-attr\">top\u003C\u002Fspan>: \u003Cspan class=\"hljs-title function_\">seatLine\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan>), \u003Cspan class=\"hljs-attr\">bottom\u003C\u002Fspan>: \u003Cspan class=\"hljs-title function_\">seatLine\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;black&#x27;\u003C\u002Fspan>) } : { \u003Cspan class=\"hljs-attr\">top\u003C\u002Fspan>: \u003Cspan class=\"hljs-title function_\">seatLine\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;black&#x27;\u003C\u002Fspan>), \u003Cspan class=\"hljs-attr\">bottom\u003C\u002Fspan>: \u003Cspan class=\"hljs-title function_\">seatLine\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan>) }))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> pgn = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> game.\u003Cspan class=\"hljs-title function_\">pgnText\u003C\u002Fspan>({\n  \u003Cspan class=\"hljs-attr\">marks\u003C\u002Fspan>: story.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>?.\u003Cspan class=\"hljs-property\">marks\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">comments\u003C\u002Fspan>: jevNotes.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">tags\u003C\u002Fspan>: {\n    \u003Cspan class=\"hljs-title class_\">Event\u003C\u002Fspan>: is960.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">`Chess960 #\u003Cspan class=\"hljs-subst\">${n.value}\u003C\u002Fspan>`\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;Chess&#x27;\u003C\u002Fspan>,\n    \u003Cspan class=\"hljs-title class_\">Site\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;chriswijnia.com&#x27;\u003C\u002Fspan>,\n    \u003Cspan class=\"hljs-title class_\">Date\u003C\u002Fspan>: \u003Cspan class=\"hljs-keyword\">new\u003C\u002Fspan> \u003Cspan class=\"hljs-title class_\">Date\u003C\u002Fspan>().\u003Cspan class=\"hljs-title function_\">toISOString\u003C\u002Fspan>().\u003Cspan class=\"hljs-title function_\">slice\u003C\u002Fspan>(\u003Cspan class=\"hljs-number\">0\u003C\u002Fspan>, \u003Cspan class=\"hljs-number\">10\u003C\u002Fspan>).\u003Cspan class=\"hljs-title function_\">replaceAll\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;-&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;.&#x27;\u003C\u002Fspan>),\n    \u003Cspan class=\"hljs-title class_\">White\u003C\u002Fspan>: mode.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;friend&#x27;\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;White&#x27;\u003C\u002Fspan> : \u003Cspan class=\"hljs-variable constant_\">PLAYER_NAME\u003C\u002Fspan>[players.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">white\u003C\u002Fspan>],\n    \u003Cspan class=\"hljs-title class_\">Black\u003C\u002Fspan>: mode.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;friend&#x27;\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;Black&#x27;\u003C\u002Fspan> : \u003Cspan class=\"hljs-variable constant_\">PLAYER_NAME\u003C\u002Fspan>[players.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">black\u003C\u002Fspan>],\n  },\n}))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> reviewing = \u003Cspan class=\"hljs-title function_\">ref\u003C\u002Fspan>(\u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-title function_\">watch\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> game.\u003Cspan class=\"hljs-property\">plies\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan>, \u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> { reviewing.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan> })\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> balance = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> {\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> plies = game.\u003Cspan class=\"hljs-property\">plies\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, now = game.\u003Cspan class=\"hljs-property\">position\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> now ? [...plies.\u003Cspan class=\"hljs-title function_\">map\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">p\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">materialBalance\u003C\u002Fspan>(p.\u003Cspan class=\"hljs-property\">before\u003C\u002Fspan>)), \u003Cspan class=\"hljs-title function_\">materialBalance\u003C\u002Fspan>(now)] : []\n})\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> story = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> (balance.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> ? \u003Cspan class=\"hljs-title function_\">materialStory\u003C\u002Fspan>(balance.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, game.\u003Cspan class=\"hljs-property\">plies\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">map\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">p\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> p.\u003Cspan class=\"hljs-property\">san\u003C\u002Fspan>), game.\u003Cspan class=\"hljs-property\">outcome\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>?.\u003Cspan class=\"hljs-property\">winner\u003C\u002Fspan>) : \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> jevTimes = ref&lt;number[]&gt;([])\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-variable constant_\">SPARK\u003C\u002Fspan> = \u003Cspan class=\"hljs-number\">24\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> over = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> {\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> o = game.\u003Cspan class=\"hljs-property\">outcome\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!o) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">who\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">c: \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan> | \u003Cspan class=\"hljs-string\">&#x27;black&#x27;\u003C\u002Fspan>\u003C\u002Fspan>) =&gt; (players.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>[c] === \u003Cspan class=\"hljs-string\">&#x27;human&#x27;\u003C\u002Fspan> ? \u003Cspan class=\"hljs-title function_\">cap\u003C\u002Fspan>(c) : \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${PLAYER_NAME[players.value[c]]}\u003C\u002Fspan> (\u003Cspan class=\"hljs-subst\">${cap(c)}\u003C\u002Fspan>)`\u003C\u002Fspan>)\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> line = !o.\u003Cspan class=\"hljs-property\">winner\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;Nobody wins&#x27;\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${who(o.winner)}\u003C\u002Fspan> wins`\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> { \u003Cspan class=\"hljs-attr\">reason\u003C\u002Fspan>: o.\u003Cspan class=\"hljs-property\">reason\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">score\u003C\u002Fspan>: !o.\u003Cspan class=\"hljs-property\">winner\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;½–½&#x27;\u003C\u002Fspan> : o.\u003Cspan class=\"hljs-property\">winner\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;1–0&#x27;\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;0–1&#x27;\u003C\u002Fspan>, line, \u003Cspan class=\"hljs-attr\">summary\u003C\u002Fspan>: story.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>?.\u003Cspan class=\"hljs-property\">summary\u003C\u002Fspan> }\n})\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> status = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> {\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> o = game.\u003Cspan class=\"hljs-property\">outcome\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!game.\u003Cspan class=\"hljs-property\">ready\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;Setting up the rules…&#x27;\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (viewing.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">`Move \u003Cspan class=\"hljs-subst\">${\u003Cspan class=\"hljs-built_in\">Math\u003C\u002Fspan>.ceil(shown.value \u002F \u003Cspan class=\"hljs-number\">2\u003C\u002Fspan>)}\u003C\u002Fspan> of \u003Cspan class=\"hljs-subst\">${\u003Cspan class=\"hljs-built_in\">Math\u003C\u002Fspan>.ceil(game.plies.value.length \u002F \u003Cspan class=\"hljs-number\">2\u003C\u002Fspan>)}\u003C\u002Fspan>, looking back.`\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (o) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> o.\u003Cspan class=\"hljs-property\">winner\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${o.reason}\u003C\u002Fspan>. \u003Cspan class=\"hljs-subst\">${cap(o.winner)}\u003C\u002Fspan> wins.`\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${o.reason}\u003C\u002Fspan>. Draw.`\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> side = \u003Cspan class=\"hljs-title function_\">cap\u003C\u002Fspan>(game.\u003Cspan class=\"hljs-property\">turn\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>)\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (thinking.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${thinking.value === \u003Cspan class=\"hljs-string\">&#x27;jev&#x27;\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;Jev&#x27;\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;Simple&#x27;\u003C\u002Fspan>}\u003C\u002Fspan> thinking…`\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (resting.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> &amp;&amp; spent.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;Jev has used today\\&#x27;s budget. Back after midnight (UTC).&#x27;\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (resting.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;Jev is resting a moment. The watch goes on by itself.&#x27;\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (idle.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;Ready: press Play.&#x27;\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (auto.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> &amp;&amp; paused.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">&#x27;Paused.&#x27;\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${side}\u003C\u002Fspan> to move\u003Cspan class=\"hljs-subst\">${game.check.value !== \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">&#x27;, in check&#x27;\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan>}\u003C\u002Fspan>.`\u003C\u002Fspan>\n})\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> pieces = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">setup\u003C\u002Fspan>(rank.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> files = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> (flipped.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? [...\u003Cspan class=\"hljs-string\">&#x27;hgfedcba&#x27;\u003C\u002Fspan>] : [...\u003Cspan class=\"hljs-string\">&#x27;abcdefgh&#x27;\u003C\u002Fspan>]))\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> ranks = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> (flipped.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? [...\u003Cspan class=\"hljs-string\">&#x27;12345678&#x27;\u003C\u002Fspan>] : [...\u003Cspan class=\"hljs-string\">&#x27;87654321&#x27;\u003C\u002Fspan>]))\n\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> humanSides = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> ([\u003Cspan class=\"hljs-string\">&#x27;white&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-string\">&#x27;black&#x27;\u003C\u002Fspan>] \u003Cspan class=\"hljs-keyword\">as\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan>).\u003Cspan class=\"hljs-title function_\">filter\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">c\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> players.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>[c] === \u003Cspan class=\"hljs-string\">&#x27;human&#x27;\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-comment\">\u002F\u002F one rail: playing first, then what a game leaves behind, then how the board looks\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-variable constant_\">RAIL_TABS\u003C\u002Fspan> = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> [\n  { \u003Cspan class=\"hljs-attr\">id\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;play&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Play&#x27;\u003C\u002Fspan> },\n  ...(humanSides.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> ? [{ \u003Cspan class=\"hljs-attr\">id\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;review&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Review&#x27;\u003C\u002Fspan> }] : []),\n  ...(auto.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? [{ \u003Cspan class=\"hljs-attr\">id\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;score&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Score&#x27;\u003C\u002Fspan> }] : []),\n  { \u003Cspan class=\"hljs-attr\">id\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;export&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Export&#x27;\u003C\u002Fspan> },\n  ...(is960.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? [{ \u003Cspan class=\"hljs-attr\">id\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;setup&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Setup&#x27;\u003C\u002Fspan> }] : []),\n  { \u003Cspan class=\"hljs-attr\">id\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;set&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;Set&#x27;\u003C\u002Fspan> },\n])\ntype \u003Cspan class=\"hljs-title class_\">ReviewItem\u003C\u002Fspan> = { \u003Cspan class=\"hljs-attr\">ply\u003C\u002Fspan>: number; \u003Cspan class=\"hljs-attr\">san\u003C\u002Fspan>: string; \u003Cspan class=\"hljs-attr\">type\u003C\u002Fspan>: string; \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: string; \u003Cspan class=\"hljs-attr\">advice\u003C\u002Fspan>: string }\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> review = ref&lt;{ \u003Cspan class=\"hljs-attr\">key\u003C\u002Fspan>: string; \u003Cspan class=\"hljs-attr\">items\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">ReviewItem\u003C\u002Fspan>[] }&gt;()\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> reviewLoading = \u003Cspan class=\"hljs-title function_\">ref\u003C\u002Fspan>(\u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">reviewKey\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">\u003C\u002Fspan>) =&gt; \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${n.value}\u003C\u002Fspan>:\u003Cspan class=\"hljs-subst\">${humanSides.value.join(\u003Cspan class=\"hljs-string\">&#x27;,&#x27;\u003C\u002Fspan>)}\u003C\u002Fspan>:\u003Cspan class=\"hljs-subst\">${game.moves.value.join(\u003Cspan class=\"hljs-string\">&#x27;.&#x27;\u003C\u002Fspan>)}\u003C\u002Fspan>`\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">async\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">loadReview\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">\u003C\u002Fspan>) {\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> moves = game.\u003Cspan class=\"hljs-property\">moves\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, sides = humanSides.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>, key = \u003Cspan class=\"hljs-title function_\">reviewKey\u003C\u002Fspan>()\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!moves.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> || !sides.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> || review.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>?.\u003Cspan class=\"hljs-property\">key\u003C\u002Fspan> === key) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan>\n  reviewLoading.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">try\u003C\u002Fspan> {\n    \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> r = \u003Cspan class=\"hljs-keyword\">await\u003C\u002Fspan> $fetch&lt;{ \u003Cspan class=\"hljs-attr\">items\u003C\u002Fspan>: \u003Cspan class=\"hljs-title class_\">ReviewItem\u003C\u002Fspan>[] }&gt;(\u003Cspan class=\"hljs-string\">&#x27;\u002Fapi\u002Fchess\u002Freview&#x27;\u003C\u002Fspan>, { \u003Cspan class=\"hljs-attr\">method\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;POST&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">body\u003C\u002Fspan>: { \u003Cspan class=\"hljs-attr\">start\u003C\u002Fspan>: \u003Cspan class=\"hljs-title function_\">startFen\u003C\u002Fspan>(rank.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>), moves, sides } })\n    \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (\u003Cspan class=\"hljs-title function_\">reviewKey\u003C\u002Fspan>() === key) review.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = { key, \u003Cspan class=\"hljs-attr\">items\u003C\u002Fspan>: r.\u003Cspan class=\"hljs-property\">items\u003C\u002Fspan> }\n  } \u003Cspan class=\"hljs-keyword\">catch\u003C\u002Fspan> {} \u003Cspan class=\"hljs-keyword\">finally\u003C\u002Fspan> { reviewLoading.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan> }\n}\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> railTab = ref&lt;string&gt;(\u003Cspan class=\"hljs-string\">&#x27;play&#x27;\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-title function_\">watch\u003C\u002Fspan>([railTab, \u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> game.\u003Cspan class=\"hljs-property\">moves\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan>], \u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> { \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (railTab.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;review&#x27;\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">void\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">loadReview\u003C\u002Fspan>() })\n\u003Cspan class=\"hljs-title function_\">watch\u003C\u002Fspan>(railTab, \u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">t\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> { \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (t === \u003Cspan class=\"hljs-string\">&#x27;score&#x27;\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">void\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">fetchScores\u003C\u002Fspan>() })\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-variable constant_\">EXPORTS\u003C\u002Fspan> = [{ \u003Cspan class=\"hljs-attr\">value\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;pgn&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;PGN&#x27;\u003C\u002Fspan> }, { \u003Cspan class=\"hljs-attr\">value\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;fen&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;FEN&#x27;\u003C\u002Fspan> }] \u003Cspan class=\"hljs-keyword\">as\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> exportKind = ref&lt;\u003Cspan class=\"hljs-string\">&#x27;pgn&#x27;\u003C\u002Fspan> | \u003Cspan class=\"hljs-string\">&#x27;fen&#x27;\u003C\u002Fspan>&gt;(\u003Cspan class=\"hljs-string\">&#x27;pgn&#x27;\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> exported = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> {\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (railTab.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> !== \u003Cspan class=\"hljs-string\">&#x27;export&#x27;\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> \u003Cspan class=\"hljs-literal\">undefined\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (exportKind.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> === \u003Cspan class=\"hljs-string\">&#x27;pgn&#x27;\u003C\u002Fspan> &amp;&amp; pgn.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> { \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;PGN&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">value\u003C\u002Fspan>: pgn.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> }\n  \u003Cspan class=\"hljs-keyword\">return\u003C\u002Fspan> { \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;FEN&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-attr\">value\u003C\u002Fspan>: game.\u003Cspan class=\"hljs-property\">fen\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> }\n})\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> copied = \u003Cspan class=\"hljs-title function_\">refAutoReset\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan>, \u003Cspan class=\"hljs-number\">1600\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">async\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">function\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">copy\u003C\u002Fspan>(\u003Cspan class=\"hljs-params\">label: string, value: string\u003C\u002Fspan>) {\n  \u003Cspan class=\"hljs-keyword\">try\u003C\u002Fspan> { \u003Cspan class=\"hljs-keyword\">await\u003C\u002Fspan> navigator.\u003Cspan class=\"hljs-property\">clipboard\u003C\u002Fspan>.\u003Cspan class=\"hljs-title function_\">writeText\u003C\u002Fspan>(value); copied.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = label } \u003Cspan class=\"hljs-keyword\">catch\u003C\u002Fspan> { copied.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C\u002Fspan> }\n}\n\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> draft = \u003Cspan class=\"hljs-title function_\">ref\u003C\u002Fspan>(\u003Cspan class=\"hljs-title class_\">String\u003C\u002Fspan>(n.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>))\n\u003Cspan class=\"hljs-title function_\">watch\u003C\u002Fspan>(n, \u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">v\u003C\u002Fspan>) =&gt;\u003C\u002Fspan> { draft.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = \u003Cspan class=\"hljs-title class_\">String\u003C\u002Fspan>(v) })\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> invalid = \u003Cspan class=\"hljs-title function_\">ref\u003C\u002Fspan>(\u003Cspan class=\"hljs-literal\">false\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">go\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">\u003C\u002Fspan>) =&gt; {\n  \u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> next = \u003Cspan class=\"hljs-title class_\">Number\u003C\u002Fspan>(draft.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>)\n  invalid.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> = !\u003Cspan class=\"hljs-title function_\">isPositionId\u003C\u002Fspan>(next)\n  \u003Cspan class=\"hljs-keyword\">if\u003C\u002Fspan> (!invalid.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>) \u003Cspan class=\"hljs-keyword\">void\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">navigateTo\u003C\u002Fspan>(\u003Cspan class=\"hljs-title function_\">href\u003C\u002Fspan>(next))\n}\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">random\u003C\u002Fspan> = (\u003Cspan class=\"hljs-params\">\u003C\u002Fspan>) =&gt; \u003Cspan class=\"hljs-title function_\">navigateTo\u003C\u002Fspan>(\u003Cspan class=\"hljs-title function_\">random960\u003C\u002Fspan>())\n\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> { canonical } = \u003Cspan class=\"hljs-title function_\">usePageSeo\u003C\u002Fspan>({\n  \u003Cspan class=\"hljs-attr\">title\u003C\u002Fspan>: \u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> (is960.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">`Chess960 #\u003Cspan class=\"hljs-subst\">${n.value}\u003C\u002Fspan>: \u003Cspan class=\"hljs-subst\">${rank.value}\u003C\u002Fspan>`\u003C\u002Fspan> : \u003Cspan class=\"hljs-string\">&#x27;Chess&#x27;\u003C\u002Fspan>),\n  \u003Cspan class=\"hljs-attr\">description\u003C\u002Fspan>: \u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> (is960.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>\n    ? \u003Cspan class=\"hljs-string\">`Chess960 starting position \u003Cspan class=\"hljs-subst\">${n.value}\u003C\u002Fspan> of 960: \u003Cspan class=\"hljs-subst\">${rank.value}\u003C\u002Fspan>. Play Jev, an engine or a friend from it, or watch Jev play.`\u003C\u002Fspan>\n    : \u003Cspan class=\"hljs-string\">&#x27;Play chess against Jev, TypeSafe AI’s System One model, a simple engine or a friend, or watch Jev play itself, with its thinking on show.&#x27;\u003C\u002Fspan>),\n  \u003Cspan class=\"hljs-attr\">image\u003C\u002Fspan>: \u003Cspan class=\"hljs-string\">&#x27;\u002Flab\u002Fchess.png&#x27;\u003C\u002Fspan>,\n  \u003Cspan class=\"hljs-attr\">screenshot\u003C\u002Fspan>: \u003Cspan class=\"hljs-literal\">true\u003C\u002Fspan>,\n})\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> keptUrl = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> kept.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> &amp;&amp; \u003Cspan class=\"hljs-keyword\">new\u003C\u002Fspan> \u003Cspan class=\"hljs-title function_\">URL\u003C\u002Fspan>(\u003Cspan class=\"hljs-string\">`\u002Fg\u002F\u003Cspan class=\"hljs-subst\">${kept.value}\u003C\u002Fspan>`\u003C\u002Fspan>, \u003Cspan class=\"hljs-title function_\">useRuntimeConfig\u003C\u002Fspan>().\u003Cspan class=\"hljs-property\">public\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">siteUrl\u003C\u002Fspan>).\u003Cspan class=\"hljs-property\">href\u003C\u002Fspan>)\n\u003Cspan class=\"hljs-keyword\">const\u003C\u002Fspan> url = \u003Cspan class=\"hljs-title function_\">computed\u003C\u002Fspan>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C\u002Fspan> keptUrl.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan> || (game.\u003Cspan class=\"hljs-property\">moves\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>.\u003Cspan class=\"hljs-property\">length\u003C\u002Fspan> ? \u003Cspan class=\"hljs-string\">`\u003Cspan class=\"hljs-subst\">${canonical.value}\u003C\u002Fspan>?g=\u003Cspan class=\"hljs-subst\">${game.moves.value.join(\u003Cspan class=\"hljs-string\">&#x27;.&#x27;\u003C\u002Fspan>)}\u003C\u002Fspan>`\u003C\u002Fspan> : canonical.\u003Cspan class=\"hljs-property\">value\u003C\u002Fspan>))\n\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">script\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n\n\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">article\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;lab-stage bg-paper&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n      \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;chess&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n        \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">Win\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:title\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;boardTitle&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">as\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;figure&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;Board&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;board-win&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">data-shot\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:draggable\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;false&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:minimizable\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;false&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n          \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan> #\u003Cspan class=\"hljs-attr\">meta\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">GlyphStatus\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;!game.ready.value&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">active\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;Setting up the rules&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">set\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;shade&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">GlyphStatus\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-else-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;thinking&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">active\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;`${thinking === &#x27;jev&#x27; ? &#x27;Jev&#x27; : &#x27;Simple&#x27;} thinking`&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-else\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ status }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n          \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n          \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;board&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;{ &#x27;is-flipped&#x27;: flipped }&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-for\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;(s, at) in seats&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:key\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;at&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;board__seat mono-label&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;[`board__seat--${at}`, { &#x27;is-to-move&#x27;: s.toMove }]&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;board__seat-mark&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">aria-hidden\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;true&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">GlyphSpinner\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;s.thinking&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-else\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ s.toMove ? &#x27;■&#x27; : &#x27;□&#x27; }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;board__seat-name&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ s.name }}\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;s.toMove&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;visually-hidden&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>, to move\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;board__seat-note&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ s.note }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;board__ranks mono-label&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">aria-hidden\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;true&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-for\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;r in ranks&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:key\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;r&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ r }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">ChessBoard\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;board__squares&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:squares\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;viewing ? game.squaresAt(shown) : game.squares.value&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:font\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;font&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:theme\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;theme&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:flipped\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;flipped&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:interactive\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;playable &amp;&amp; !viewing&quot;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-attr\">:targets\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;game.targets&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:needs-promotion\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;game.needsPromotion&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:check\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;viewing ? game.checkAt(shown) : game.check.value&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:last\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;shownLast&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:ply-count\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;shown&quot;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-attr\">:premove-color\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;thinking ? humanSides[0] : undefined&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:premove\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;premove&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:arrows\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;arrows&quot;\u003C\u002Fspan>\n              @\u003Cspan class=\"hljs-attr\">move\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;move&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">premove\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;premove = $event&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">cancel-premove\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;premove = undefined&quot;\u003C\u002Fspan>\n            \u002F&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;idle &amp;&amp; !viewing&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;over start&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">Btn\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">variant\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;amber&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">click\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;paused = false&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ modeLabel }} ►\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">Btn\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;over &amp;&amp; !reviewing &amp;&amp; !viewing&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;over&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">role\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;status&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">ChessGameOver\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:over\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;over&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:kept\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;kept&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:kept-url\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;keptUrl&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">new-game\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;newGame&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">hide\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;reviewing = true&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;evalShown !== undefined&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;board__eval&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">role\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;img&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:aria-label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;`Jev&#x27;s reading: White ${pct(evalShown)}`&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:style\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;{ &#x27;--white&#x27;: flipped ? 1 - evalShown : evalShown }&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;board__files mono-label&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">aria-hidden\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;true&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-for\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;f in files&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:key\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;f&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ f }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n          \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n        \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">Win\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n        \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;visually-hidden&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">role\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;status&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">aria-live\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;polite&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ status }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n\n        \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">Win\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-model:tab\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;railTab&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">title\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;CW\u002FGAME&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">as\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;section&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;Game&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:tabs\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;RAIL_TABS&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">persist\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;chess-rail&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:draggable\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;false&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:minimizable\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;false&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;rail&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n          \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan> #\u003Cspan class=\"hljs-attr\">meta\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">button\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;exported&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">type\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;button&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;bar-btn bare&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">click\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;copy(exported.label, exported.value)&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ copied === exported.label ? &#x27;Copied&#x27; : &#x27;Copy&#x27; }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">button\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">button\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-else-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;railTab === &#x27;score&#x27; &amp;&amp; scoreScope === &#x27;browser&#x27;&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">type\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;button&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;bar-btn bare&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:disabled\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;!games&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">click\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;resetScore&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>Reset\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">button\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">button\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-else-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;railTab === &#x27;setup&#x27;&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">type\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;button&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;bar-btn bare&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">click\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;copy(&#x27;Back rank&#x27;, rank)&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ copied === &#x27;Back rank&#x27; ? &#x27;Copied&#x27; : rank }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">button\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-else-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;jevTimes.length&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">GlyphSparkline\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:values\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;jevTimes&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:min\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;0&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;Jev&#x27;s time per move&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">live\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan> {{ jevTimes.at(-1) }} ms\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n          \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n          \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan> #\u003Cspan class=\"hljs-attr\">default\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;{ tab }&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;tab === &#x27;set&#x27;&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">ul\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;sets&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">role\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;radiogroup&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">aria-label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;Chess set&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">li\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-for\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;(s, id) in CHESS_SETS&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:key\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;id&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">button\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">type\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;button&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">role\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;radio&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;sets__one bare&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:aria-checked\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;set === id&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">click\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;set = id&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                    \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;sets__sample&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:style\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;{ ...swatch(s.theme), fontFamily: `&#x27;Chess ${s.font}&#x27;, var(--font-mono)` }&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ squareGlyph(&#x27;N&#x27;, true, s.font) }}{{ squareGlyph(&#x27;q&#x27;, false, s.font) }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                    \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;mono-label&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ s.name }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">button\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">li\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">ul\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-else-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;tab === &#x27;setup&#x27; &amp;&amp; is960&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">table\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;setup mono-label&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">caption\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;visually-hidden&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>Where each piece goes\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">caption\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">thead\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">tr\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">th\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">scope\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;col&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">th\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">scope\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;col&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>Piece\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">th\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">th\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">scope\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;col&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>White\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">th\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">th\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">scope\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;col&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>Black\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">th\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">tr\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">thead\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">tbody\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">tr\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-for\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;p in pieces&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:key\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;p.white&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                    \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">td\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;setup__glyph&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">aria-hidden\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;true&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:style\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;{ fontFamily: family }&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ pieceGlyph(p.piece, font) }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">td\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                    \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">td\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ p.name }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">td\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                    \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">td\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ p.white }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">td\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                    \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">td\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ p.black }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">td\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">tr\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">tbody\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">table\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-else-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;tab === &#x27;score&#x27; &amp;&amp; watchKey&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">ChessScore\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-model:scope\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;scoreScope&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:rows\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;scoreRows&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:loaded\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;!!everyone&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-else-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;tab === &#x27;review&#x27;&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;!game.plies.value.length&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;panel__note mono-label&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>Play a few moves. The review looks at yours: each mistake, what kind, and what was better.\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-else-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;reviewLoading &amp;&amp; !review&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;panel__note mono-label&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">GlyphSpinner\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan> Reviewing your moves\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">ol\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-else-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;review?.items.length&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;review mono-label&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">data-lenis-prevent\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">li\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-for\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;it in review.items&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:key\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;it.ply&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">button\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">type\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;button&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;play__move bare&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">click\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;goTo(it.ply + 1); railTab = &#x27;play&#x27;&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ Math.floor(it.ply \u002F 2) + 1 }}{{ it.ply % 2 ? &#x27;…&#x27; : &#x27;.&#x27; }} {{ it.san }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">button\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;review__type&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ it.label }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;review__advice&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ it.advice }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">li\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">ol\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-else-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;review&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;panel__note mono-label&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>No mistakes in your moves so far: nothing left hanging, no mate missed or allowed.\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-else-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;tab === &#x27;export&#x27;&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">ChessToggle\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-model\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;exportKind&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:options\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;EXPORTS&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;Export as&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">CodeView\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;exported?.label === &#x27;PGN&#x27;&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:html\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;pgnHtml(exported.value)&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">theme\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;light&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:padded\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;false&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">wrap\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;export__pgn&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">pre\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-else-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;exported&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;export__text mono-label&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ exported.value }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">pre\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;visually-hidden&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">aria-live\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;polite&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ copied ? `${copied} copied to clipboard` : &#x27;&#x27; }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-else\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">button\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">type\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;button&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;game__summary mono-label&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:aria-expanded\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;settingsOpen&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">aria-controls\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;chess-settings&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">click\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;settingsOpen = !settingsOpen&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ settingsSummary }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">aria-hidden\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;true&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ settingsOpen ? &#x27;▲&#x27; : &#x27;▼&#x27; }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">button\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">id\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;chess-settings&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;game__settings&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;{ &#x27;is-open&#x27;: settingsOpen }&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">label\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;mode mono-label&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;visually-hidden&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>What to do\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">select\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:value\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;mode&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;mode__select&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">change\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;choose(($event.target as HTMLSelectElement).value as Mode)&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                    \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">option\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-for\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;m in MODES&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:key\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;m.value&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:value\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;m.value&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ m.label }} · {{ m.note }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">option\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">select\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;mode__caret&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">aria-hidden\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;true&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>▾\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">label\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;fields mono-label&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;mode === &#x27;jev&#x27; || mode === &#x27;simple&#x27;&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;seed&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>You play\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">ChessToggle\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-model\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;colour&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:options\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;COLOURS&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;You play&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">pick\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;newGame&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;jevPlays&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;seed&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>Jev’s level\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">ChessToggle\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-model\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;level&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:options\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;LEVELS&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;Jev’s level&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;auto&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;seed&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>Speed\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">ChessToggle\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-model\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;speed&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:options\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;PACES&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;Speed&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;seed&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>Board\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">ChessToggle\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:model-value\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;is960 ? &#x27;chess960&#x27; : &#x27;standard&#x27;&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:options\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;VARIANTS&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;Variant&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;is960&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;seed&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                    \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">label\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">for\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;chess-n&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>Position\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">label\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                    \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;pos&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                      \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">NuxtLink\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:to\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;step(-1)&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;pos__step&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">aria-label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;Previous position&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>◄\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">NuxtLink\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                      \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">input\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">id\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;chess-n&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-model\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;draft&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;seed__input&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">inputmode\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;numeric&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">maxlength\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;3&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:aria-invalid\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;invalid&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">keydown.enter.prevent\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;go&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">blur\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;draft = String(n); invalid = false&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                      \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">NuxtLink\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:to\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;step(1)&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;pos__step&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">aria-label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;Next position&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>►\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">NuxtLink\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                      \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">button\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">type\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;button&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;pos__step bare&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">aria-label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;A random position&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">title\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;A random position&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">click\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;random&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">PhShuffle\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:size\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;14&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">weight\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;bold&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">aria-hidden\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;true&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">button\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                    \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;humanSides.length&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;seed&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>Coach\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">ChessToggle\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-model\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;coach&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:options\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;COACH&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;Coach&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;actions&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">Btn\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;auto &amp;&amp; !game.outcome.value&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">variant\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;amber&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">size\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;md&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">click\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;paused = !paused&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ paused ? &#x27;► Play&#x27; : &#x27;║ Pause&#x27; }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">Btn\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">Btn\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-else\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">variant\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;amber&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">size\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;md&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">click\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;newGame&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>+ New game\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">Btn\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;actions__links mono-label&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">button\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;auto &amp;&amp; !game.outcome.value&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">type\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;button&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;bare&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:disabled\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;!game.plies.value.length&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">click\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;newGame&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>Reset\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">button\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">button\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;!auto&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">type\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;button&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;bare&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:disabled\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;!game.plies.value.length&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">click\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;undo&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>Undo\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">button\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">button\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">type\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;button&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;bare&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:aria-pressed\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;flipped&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">click\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;flipped = !flipped&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>Flip\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">button\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">ChessCoach\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;coach &amp;&amp; humanSides.length&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:verdict\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;verdict&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:thinking\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;coachThinking&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">section\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;jevPlays &amp;&amp; jevDecision&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;reading&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">aria-label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;Jev&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;jev__head&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;jev__move&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ jevDecision.san }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;engine__note mono-label&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ jevDecision.forced ? FORCED_NOTE[jevDecision.forced] : `${jevDecision.options} legal moves · ${jevDecision.ms} ms` }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;jev__say&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ (!viewing &amp;&amp; decision?.note) || narration }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">ol\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;!jevDecision.forced&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;engine__cands&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">aria-label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;Jev&#x27;s top candidate moves&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">li\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-for\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;(c, i) in jevDecision.candidates?.slice(0, 3)&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:key\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;i&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;{ &#x27;is-picked&#x27;: c.san === jevDecision.san }&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                    \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ c.san }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">GlyphBar\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:value\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;c.p&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ pct(c.p) }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">li\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">ol\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;readingLine?.length&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;engine__meta mono-label&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ readingLine.join(&#x27; · &#x27;) }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;!auto &amp;&amp; (guess || reveal)&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;engine__meta mono-label&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;{ &#x27;is-hit&#x27;: !guess &amp;&amp; reveal?.hit }&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;guess&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>Jev has guessed your reply. It shows once you move.\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-else-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;reveal&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>Jev expected {{ reveal.expected }} ({{ pct(reveal.p) }}). You played {{ reveal.played }}{{ reveal.hit ? &#x27; ■&#x27; : &#x27;&#x27; }}.\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">section\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-else-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;jevPlays &amp;&amp; !viewing&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;panel__note mono-label&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ decision?.note || &#x27;Jev’s reading shows here once it moves: its pick, how sure it was, and its plan.&#x27; }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;moves&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;moves__head mono-label&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>Moves\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;game.plies.value.length &gt; 1&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">GlyphSparkline\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:values\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;balance.slice(-SPARK)&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">label\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;White&#x27;s material lead over the last moves&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan> {{ Math.ceil(game.plies.value.length \u002F 2) }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n                \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">ChessMoveList\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:sans\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;game.plies.value.map((p) =&gt; p.san)&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:marks\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;story?.marks&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:shown\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;shown&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:viewing\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;viewing&quot;\u003C\u002Fspan> @\u003Cspan class=\"hljs-attr\">go\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;goTo&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\n              \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n          \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n        \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">Win\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n      \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">article\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n\n    \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">section\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;bg-paper pb-section&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n      \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;wrap grid gap-head&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n        \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">PageHead\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:back\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;{ to: &#x27;\u002Flab&#x27;, label: &#x27;Lab&#x27; }&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:rule\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;false&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n          \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan> #\u003Cspan class=\"hljs-attr\">meta\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ is960 ? &#x27;Chess960&#x27; : &#x27;Chess&#x27; }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;is960&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{{ String(n).padStart(3, &#x27;0&#x27;) }} \u002F {{ POSITIONS - 1 }}\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">span\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n          \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n          \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">h1\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;is960&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;statement-lg&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>Chess960 \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">AccentText\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:text\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;`#${n}`&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:accent\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;`#${n}`&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">h1\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n          \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">h1\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-else\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;statement-lg&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>A game of \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">AccentText\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">text\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;chess.&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">accent\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;chess.&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">h1\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n          \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-if\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;is960&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;lede&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>One of the 960 Fischer random starting positions. Pawns stay put; the back rank is shuffled so the bishops sit on opposite colours and the king stands between the rooks.\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n          \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">v-else\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;lede&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>Play Jev, TypeSafe AI’s System One model, a simple engine or a friend, or watch Jev play itself. Each turn Jev weighs every legal move at once, as one typed Choice, and shows how sure it is. Chess960 shuffles the back rank into one of 960 starting positions.\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n          \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;chess-head__actions&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">ShareBar\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:url\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;url&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">:title\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;is960 ? `Chess960 #${n}: ${rank}` : &#x27;Chess, with Jev&#x27;&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\n            \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">Btn\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">to\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;\u002Flab\u002Fchess\u002Fsource&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">variant\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;ghost&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">size\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;md&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>{ } Source\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">Btn\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n          \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n        \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">PageHead\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n        \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">class\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;credit mono-label&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n          Piece sets by Armando H. Marroquín, Utrecht by Hans L. Bodlaender, from Eric Bentzen’s\n          \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">a\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">href\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;https:\u002F\u002Fctan.org\u002Ftex-archive\u002Ffonts\u002Fchess\u002Fenpassant&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">rel\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;noopener&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>En Passant collection\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">a\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n          (\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">a\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">href\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;https:\u002F\u002Fwww.chessvariants.com\u002Fd.font\u002F&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">rel\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;noopener&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>more on the fonts\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">a\u003C\u002Fspan>&gt;\u003C\u002Fspan>); Arcade and Console by\n          \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">a\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">href\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;https:\u002F\u002Fspicygame.itch.io\u002Fchess-pieces&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">rel\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;noopener&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>SpicyGame\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">a\u003C\u002Fspan>&gt;\u003C\u002Fspan> (CC0).\n          Rules by \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">a\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">href\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;https:\u002F\u002Fgithub.com\u002Fniklasf\u002Fchessops&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">rel\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;noopener&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>chessops\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">a\u003C\u002Fspan>&gt;\u003C\u002Fspan>, by Niklas Fiekas, the library behind Lichess, licensed under the\n          \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">a\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">href\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;https:\u002F\u002Fwww.gnu.org\u002Flicenses\u002Fgpl-3.0.html&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">rel\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;noopener&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>GPL-3.0\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">a\u003C\u002Fspan>&gt;\u003C\u002Fspan>, and so is\n          \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">NuxtLink\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">to\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;\u002Flab\u002Fchess\u002Fsource&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>this experiment’s source\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">NuxtLink\u003C\u002Fspan>&gt;\u003C\u002Fspan>.\n          Jev is \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">a\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">href\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;https:\u002F\u002Ftypesafe.ai&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">rel\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;noopener&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>TypeSafe AI\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">a\u003C\u002Fspan>&gt;\u003C\u002Fspan>’s System One model, called through Vercel’s AI Gateway.\n          The coach is \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">a\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">href\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;https:\u002F\u002Fgithub.com\u002Fofficial-stockfish\u002FStockfish&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">rel\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;noopener&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>Stockfish\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">a\u003C\u002Fspan>&gt;\u003C\u002Fspan>, as\n          \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">a\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">href\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;https:\u002F\u002Fgithub.com\u002Fnmrugg\u002Fstockfish.js&quot;\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">rel\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;noopener&quot;\u003C\u002Fspan>&gt;\u003C\u002Fspan>stockfish.js\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">a\u003C\u002Fspan>&gt;\u003C\u002Fspan> (GPL-3.0), loaded only when the coach is on.\n        \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">p\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n      \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">section\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n    \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">ExperimentPager\u003C\u002Fspan> \u003Cspan class=\"hljs-attr\">current\u003C\u002Fspan>=\u003Cspan class=\"hljs-string\">&quot;\u002Flab\u002Fchess&quot;\u003C\u002Fspan> \u002F&gt;\u003C\u002Fspan>\n  \u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">div\u003C\u002Fspan>&gt;\u003C\u002Fspan>\n\u003Cspan class=\"hljs-tag\">&lt;\u002F\u003Cspan class=\"hljs-name\">template\u003C\u002Fspan>&gt;\u003C\u002Fspan>",1790665483939]