UNPKG

@coledon/advanced-tictactoe

Version:

Advanced TicTacToe React component with AI opponents, animations, and multiple game modes. Perfect for 404 pages, hidden games, or entertainment features.

1,585 lines (1,582 loc) 212 kB
import * as us from "react"; import He, { useState as ge, useCallback as Q, useEffect as dt, createContext as Le, useContext as te, useLayoutEffect as go, useRef as dn, useInsertionEffect as yo, useMemo as It, forwardRef as wi, createElement as mn, useId as vo } from "react"; var pn = { exports: {} }, Qe = {}; /** * @license React * react-jsx-runtime.production.min.js * * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ var fs; function xo() { if (fs) return Qe; fs = 1; var e = He, t = Symbol.for("react.element"), n = Symbol.for("react.fragment"), s = Object.prototype.hasOwnProperty, i = e.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner, o = { key: !0, ref: !0, __self: !0, __source: !0 }; function r(a, l, c) { var u, f = {}, h = null, m = null; c !== void 0 && (h = "" + c), l.key !== void 0 && (h = "" + l.key), l.ref !== void 0 && (m = l.ref); for (u in l) s.call(l, u) && !o.hasOwnProperty(u) && (f[u] = l[u]); if (a && a.defaultProps) for (u in l = a.defaultProps, l) f[u] === void 0 && (f[u] = l[u]); return { $$typeof: t, type: a, key: h, ref: m, props: f, _owner: i.current }; } return Qe.Fragment = n, Qe.jsx = r, Qe.jsxs = r, Qe; } var et = {}; /** * @license React * react-jsx-runtime.development.js * * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ var hs; function bo() { return hs || (hs = 1, process.env.NODE_ENV !== "production" && function() { var e = He, t = Symbol.for("react.element"), n = Symbol.for("react.portal"), s = Symbol.for("react.fragment"), i = Symbol.for("react.strict_mode"), o = Symbol.for("react.profiler"), r = Symbol.for("react.provider"), a = Symbol.for("react.context"), l = Symbol.for("react.forward_ref"), c = Symbol.for("react.suspense"), u = Symbol.for("react.suspense_list"), f = Symbol.for("react.memo"), h = Symbol.for("react.lazy"), m = Symbol.for("react.offscreen"), g = Symbol.iterator, v = "@@iterator"; function T(d) { if (d === null || typeof d != "object") return null; var y = g && d[g] || d[v]; return typeof y == "function" ? y : null; } var P = e.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; function b(d) { { for (var y = arguments.length, w = new Array(y > 1 ? y - 1 : 0), M = 1; M < y; M++) w[M - 1] = arguments[M]; x("error", d, w); } } function x(d, y, w) { { var M = P.ReactDebugCurrentFrame, N = M.getStackAddendum(); N !== "" && (y += "%s", w = w.concat([N])); var I = w.map(function(E) { return String(E); }); I.unshift("Warning: " + y), Function.prototype.apply.call(console[d], console, I); } } var C = !1, V = !1, U = !1, B = !1, D = !1, S; S = Symbol.for("react.module.reference"); function L(d) { return !!(typeof d == "string" || typeof d == "function" || d === s || d === o || D || d === i || d === c || d === u || B || d === m || C || V || U || typeof d == "object" && d !== null && (d.$$typeof === h || d.$$typeof === f || d.$$typeof === r || d.$$typeof === a || d.$$typeof === l || // This needs to include all possible module reference object // types supported by any Flight configuration anywhere since // we don't know which Flight build this will end up being used // with. d.$$typeof === S || d.getModuleId !== void 0)); } function H(d, y, w) { var M = d.displayName; if (M) return M; var N = y.displayName || y.name || ""; return N !== "" ? w + "(" + N + ")" : w; } function j(d) { return d.displayName || "Context"; } function $(d) { if (d == null) return null; if (typeof d.tag == "number" && b("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."), typeof d == "function") return d.displayName || d.name || null; if (typeof d == "string") return d; switch (d) { case s: return "Fragment"; case n: return "Portal"; case o: return "Profiler"; case i: return "StrictMode"; case c: return "Suspense"; case u: return "SuspenseList"; } if (typeof d == "object") switch (d.$$typeof) { case a: var y = d; return j(y) + ".Consumer"; case r: var w = d; return j(w._context) + ".Provider"; case l: return H(d, d.render, "ForwardRef"); case f: var M = d.displayName || null; return M !== null ? M : $(d.type) || "Memo"; case h: { var N = d, I = N._payload, E = N._init; try { return $(E(I)); } catch { return null; } } } return null; } var R = Object.assign, O = 0, F, Y, oe, he, Ke, _, we; function qe() { } qe.__reactDisabledLog = !0; function xt() { { if (O === 0) { F = console.log, Y = console.info, oe = console.warn, he = console.error, Ke = console.group, _ = console.groupCollapsed, we = console.groupEnd; var d = { configurable: !0, enumerable: !0, value: qe, writable: !0 }; Object.defineProperties(console, { info: d, log: d, warn: d, error: d, group: d, groupCollapsed: d, groupEnd: d }); } O++; } } function bt() { { if (O--, O === 0) { var d = { configurable: !0, enumerable: !0, writable: !0 }; Object.defineProperties(console, { log: R({}, d, { value: F }), info: R({}, d, { value: Y }), warn: R({}, d, { value: oe }), error: R({}, d, { value: he }), group: R({}, d, { value: Ke }), groupCollapsed: R({}, d, { value: _ }), groupEnd: R({}, d, { value: we }) }); } O < 0 && b("disabledDepth fell below zero. This is a bug in React. Please file an issue."); } } var de = P.ReactCurrentDispatcher, Fe; function Ie(d, y, w) { { if (Fe === void 0) try { throw Error(); } catch (N) { var M = N.stack.trim().match(/\n( *(at )?)/); Fe = M && M[1] || ""; } return ` ` + Fe + d; } } var je = !1, me; { var pe = typeof WeakMap == "function" ? WeakMap : Map; me = new pe(); } function Xt(d, y) { if (!d || je) return ""; { var w = me.get(d); if (w !== void 0) return w; } var M; je = !0; var N = Error.prepareStackTrace; Error.prepareStackTrace = void 0; var I; I = de.current, de.current = null, xt(); try { if (y) { var E = function() { throw Error(); }; if (Object.defineProperty(E.prototype, "props", { set: function() { throw Error(); } }), typeof Reflect == "object" && Reflect.construct) { try { Reflect.construct(E, []); } catch (ne) { M = ne; } Reflect.construct(d, [], E); } else { try { E.call(); } catch (ne) { M = ne; } d.call(E.prototype); } } else { try { throw Error(); } catch (ne) { M = ne; } d(); } } catch (ne) { if (ne && M && typeof ne.stack == "string") { for (var k = ne.stack.split(` `), J = M.stack.split(` `), X = k.length - 1, K = J.length - 1; X >= 1 && K >= 0 && k[X] !== J[K]; ) K--; for (; X >= 1 && K >= 0; X--, K--) if (k[X] !== J[K]) { if (X !== 1 || K !== 1) do if (X--, K--, K < 0 || k[X] !== J[K]) { var ae = ` ` + k[X].replace(" at new ", " at "); return d.displayName && ae.includes("<anonymous>") && (ae = ae.replace("<anonymous>", d.displayName)), typeof d == "function" && me.set(d, ae), ae; } while (X >= 1 && K >= 0); break; } } } finally { je = !1, de.current = I, bt(), Error.prepareStackTrace = N; } var We = d ? d.displayName || d.name : "", De = We ? Ie(We) : ""; return typeof d == "function" && me.set(d, De), De; } function zr(d, y, w) { return Xt(d, !1); } function Hr(d) { var y = d.prototype; return !!(y && y.isReactComponent); } function wt(d, y, w) { if (d == null) return ""; if (typeof d == "function") return Xt(d, Hr(d)); if (typeof d == "string") return Ie(d); switch (d) { case c: return Ie("Suspense"); case u: return Ie("SuspenseList"); } if (typeof d == "object") switch (d.$$typeof) { case l: return zr(d.render); case f: return wt(d.type, y, w); case h: { var M = d, N = M._payload, I = M._init; try { return wt(I(N), y, w); } catch { } } } return ""; } var Ze = Object.prototype.hasOwnProperty, Zn = {}, Jn = P.ReactDebugCurrentFrame; function Pt(d) { if (d) { var y = d._owner, w = wt(d.type, d._source, y ? y.type : null); Jn.setExtraStackFrame(w); } else Jn.setExtraStackFrame(null); } function Xr(d, y, w, M, N) { { var I = Function.call.bind(Ze); for (var E in d) if (I(d, E)) { var k = void 0; try { if (typeof d[E] != "function") { var J = Error((M || "React class") + ": " + w + " type `" + E + "` is invalid; it must be a function, usually from the `prop-types` package, but received `" + typeof d[E] + "`.This often happens because of typos such as `PropTypes.function` instead of `PropTypes.func`."); throw J.name = "Invariant Violation", J; } k = d[E](y, E, M, w, null, "SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"); } catch (X) { k = X; } k && !(k instanceof Error) && (Pt(N), b("%s: type specification of %s `%s` is invalid; the type checker function must return `null` or an `Error` but returned a %s. You may have forgotten to pass an argument to the type checker creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and shape all require an argument).", M || "React class", w, E, typeof k), Pt(null)), k instanceof Error && !(k.message in Zn) && (Zn[k.message] = !0, Pt(N), b("Failed %s type: %s", w, k.message), Pt(null)); } } } var Yr = Array.isArray; function Yt(d) { return Yr(d); } function Kr(d) { { var y = typeof Symbol == "function" && Symbol.toStringTag, w = y && d[Symbol.toStringTag] || d.constructor.name || "Object"; return w; } } function qr(d) { try { return Qn(d), !1; } catch { return !0; } } function Qn(d) { return "" + d; } function es(d) { if (qr(d)) return b("The provided key is an unsupported type %s. This value must be coerced to a string before before using it here.", Kr(d)), Qn(d); } var Je = P.ReactCurrentOwner, Zr = { key: !0, ref: !0, __self: !0, __source: !0 }, ts, ns, Kt; Kt = {}; function Jr(d) { if (Ze.call(d, "ref")) { var y = Object.getOwnPropertyDescriptor(d, "ref").get; if (y && y.isReactWarning) return !1; } return d.ref !== void 0; } function Qr(d) { if (Ze.call(d, "key")) { var y = Object.getOwnPropertyDescriptor(d, "key").get; if (y && y.isReactWarning) return !1; } return d.key !== void 0; } function eo(d, y) { if (typeof d.ref == "string" && Je.current && y && Je.current.stateNode !== y) { var w = $(Je.current.type); Kt[w] || (b('Component "%s" contains the string ref "%s". Support for string refs will be removed in a future major release. This case cannot be automatically converted to an arrow function. We ask you to manually fix this case by using useRef() or createRef() instead. Learn more about using refs safely here: https://reactjs.org/link/strict-mode-string-ref', $(Je.current.type), d.ref), Kt[w] = !0); } } function to(d, y) { { var w = function() { ts || (ts = !0, b("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://reactjs.org/link/special-props)", y)); }; w.isReactWarning = !0, Object.defineProperty(d, "key", { get: w, configurable: !0 }); } } function no(d, y) { { var w = function() { ns || (ns = !0, b("%s: `ref` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://reactjs.org/link/special-props)", y)); }; w.isReactWarning = !0, Object.defineProperty(d, "ref", { get: w, configurable: !0 }); } } var so = function(d, y, w, M, N, I, E) { var k = { // This tag allows us to uniquely identify this as a React Element $$typeof: t, // Built-in properties that belong on the element type: d, key: y, ref: w, props: E, // Record the component responsible for creating this element. _owner: I }; return k._store = {}, Object.defineProperty(k._store, "validated", { configurable: !1, enumerable: !1, writable: !0, value: !1 }), Object.defineProperty(k, "_self", { configurable: !1, enumerable: !1, writable: !1, value: M }), Object.defineProperty(k, "_source", { configurable: !1, enumerable: !1, writable: !1, value: N }), Object.freeze && (Object.freeze(k.props), Object.freeze(k)), k; }; function io(d, y, w, M, N) { { var I, E = {}, k = null, J = null; w !== void 0 && (es(w), k = "" + w), Qr(y) && (es(y.key), k = "" + y.key), Jr(y) && (J = y.ref, eo(y, N)); for (I in y) Ze.call(y, I) && !Zr.hasOwnProperty(I) && (E[I] = y[I]); if (d && d.defaultProps) { var X = d.defaultProps; for (I in X) E[I] === void 0 && (E[I] = X[I]); } if (k || J) { var K = typeof d == "function" ? d.displayName || d.name || "Unknown" : d; k && to(E, K), J && no(E, K); } return so(d, k, J, N, M, Je.current, E); } } var qt = P.ReactCurrentOwner, ss = P.ReactDebugCurrentFrame; function _e(d) { if (d) { var y = d._owner, w = wt(d.type, d._source, y ? y.type : null); ss.setExtraStackFrame(w); } else ss.setExtraStackFrame(null); } var Zt; Zt = !1; function Jt(d) { return typeof d == "object" && d !== null && d.$$typeof === t; } function is() { { if (qt.current) { var d = $(qt.current.type); if (d) return ` Check the render method of \`` + d + "`."; } return ""; } } function ro(d) { { if (d !== void 0) { var y = d.fileName.replace(/^.*[\\\/]/, ""), w = d.lineNumber; return ` Check your code at ` + y + ":" + w + "."; } return ""; } } var rs = {}; function oo(d) { { var y = is(); if (!y) { var w = typeof d == "string" ? d : d.displayName || d.name; w && (y = ` Check the top-level render call using <` + w + ">."); } return y; } } function os(d, y) { { if (!d._store || d._store.validated || d.key != null) return; d._store.validated = !0; var w = oo(y); if (rs[w]) return; rs[w] = !0; var M = ""; d && d._owner && d._owner !== qt.current && (M = " It was passed a child from " + $(d._owner.type) + "."), _e(d), b('Each child in a list should have a unique "key" prop.%s%s See https://reactjs.org/link/warning-keys for more information.', w, M), _e(null); } } function as(d, y) { { if (typeof d != "object") return; if (Yt(d)) for (var w = 0; w < d.length; w++) { var M = d[w]; Jt(M) && os(M, y); } else if (Jt(d)) d._store && (d._store.validated = !0); else if (d) { var N = T(d); if (typeof N == "function" && N !== d.entries) for (var I = N.call(d), E; !(E = I.next()).done; ) Jt(E.value) && os(E.value, y); } } } function ao(d) { { var y = d.type; if (y == null || typeof y == "string") return; var w; if (typeof y == "function") w = y.propTypes; else if (typeof y == "object" && (y.$$typeof === l || // Note: Memo only checks outer props here. // Inner props are checked in the reconciler. y.$$typeof === f)) w = y.propTypes; else return; if (w) { var M = $(y); Xr(w, d.props, "prop", M, d); } else if (y.PropTypes !== void 0 && !Zt) { Zt = !0; var N = $(y); b("Component %s declared `PropTypes` instead of `propTypes`. Did you misspell the property assignment?", N || "Unknown"); } typeof y.getDefaultProps == "function" && !y.getDefaultProps.isReactClassApproved && b("getDefaultProps is only used on classic React.createClass definitions. Use a static property named `defaultProps` instead."); } } function lo(d) { { for (var y = Object.keys(d.props), w = 0; w < y.length; w++) { var M = y[w]; if (M !== "children" && M !== "key") { _e(d), b("Invalid prop `%s` supplied to `React.Fragment`. React.Fragment can only have `key` and `children` props.", M), _e(null); break; } } d.ref !== null && (_e(d), b("Invalid attribute `ref` supplied to `React.Fragment`."), _e(null)); } } var ls = {}; function cs(d, y, w, M, N, I) { { var E = L(d); if (!E) { var k = ""; (d === void 0 || typeof d == "object" && d !== null && Object.keys(d).length === 0) && (k += " You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports."); var J = ro(N); J ? k += J : k += is(); var X; d === null ? X = "null" : Yt(d) ? X = "array" : d !== void 0 && d.$$typeof === t ? (X = "<" + ($(d.type) || "Unknown") + " />", k = " Did you accidentally export a JSX literal instead of a component?") : X = typeof d, b("React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s", X, k); } var K = io(d, y, w, N, I); if (K == null) return K; if (E) { var ae = y.children; if (ae !== void 0) if (M) if (Yt(ae)) { for (var We = 0; We < ae.length; We++) as(ae[We], d); Object.freeze && Object.freeze(ae); } else b("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead."); else as(ae, d); } if (Ze.call(y, "key")) { var De = $(d), ne = Object.keys(y).filter(function(po) { return po !== "key"; }), Qt = ne.length > 0 ? "{key: someKey, " + ne.join(": ..., ") + ": ...}" : "{key: someKey}"; if (!ls[De + Qt]) { var mo = ne.length > 0 ? "{" + ne.join(": ..., ") + ": ...}" : "{}"; b(`A props object containing a "key" prop is being spread into JSX: let props = %s; <%s {...props} /> React keys must be passed directly to JSX without using spread: let props = %s; <%s key={someKey} {...props} />`, Qt, De, mo, De), ls[De + Qt] = !0; } } return d === s ? lo(K) : ao(K), K; } } function co(d, y, w) { return cs(d, y, w, !0); } function uo(d, y, w) { return cs(d, y, w, !1); } var fo = uo, ho = co; et.Fragment = s, et.jsx = fo, et.jsxs = ho; }()), et; } process.env.NODE_ENV === "production" ? pn.exports = xo() : pn.exports = bo(); var p = pn.exports; const Tt = { theme: "dark", soundEnabled: !0, musicEnabled: !1, animationsEnabled: !0, difficulty: "medium", boardSize: 3, timeLimit: void 0, firstMoveAdvantage: !1, showMoveHints: !1 }, wo = { MIN_BOARD_SIZE: 3, MAX_BOARD_SIZE: 5, MIN_PLAYERS: 2, MAX_PLAYERS: 2, WIN_CONDITION_LENGTH: { 3: 3, // 3x3 board needs 3 in a row 4: 4, // 4x4 board needs 4 in a row 5: 4 // 5x5 board needs 4 in a row (more balanced) }, MAX_MOVES: { 3: 9, // 3x3 = 9 cells 4: 16, // 4x4 = 16 cells 5: 25 // 5x5 = 25 cells } }; class Pi { constructor(t = 3) { this.boardSize = t, this.winLength = wo.WIN_CONDITION_LENGTH[t]; } /** * Creates an empty board */ createEmptyBoard() { return Array(this.boardSize).fill(null).map( () => Array(this.boardSize).fill(null) ); } /** * Validates if a position is within board bounds */ isValidPosition(t) { const { row: n, col: s } = t; return n >= 0 && n < this.boardSize && s >= 0 && s < this.boardSize; } /** * Validates if a move is legal */ isValidMove(t, n) { if (!this.isValidPosition(n)) return !1; const { row: s, col: i } = n; return t[s][i] === null; } /** * Makes a move on the board */ makeMove(t, n, s) { if (!this.isValidMove(t, n)) throw new Error("Invalid move"); const i = t.map((o) => [...o]); return i[n.row][n.col] = s, i; } /** * Checks if the board is full */ isBoardFull(t) { return t.every((n) => n.every((s) => s !== null)); } /** * Gets all empty positions on the board */ getEmptyPositions(t) { const n = []; for (let s = 0; s < this.boardSize; s++) for (let i = 0; i < this.boardSize; i++) t[s][i] === null && n.push({ row: s, col: i }); return n; } /** * Checks for a win condition and returns the winning line */ checkWin(t) { for (let n = 0; n < this.boardSize; n++) { const s = this.checkLine(t, { row: n, col: 0 }, { row: 0, col: 1 }, "row"); if (s) return s; } for (let n = 0; n < this.boardSize; n++) { const s = this.checkLine(t, { row: 0, col: n }, { row: 1, col: 0 }, "column"); if (s) return s; } for (let n = 0; n <= this.boardSize - this.winLength; n++) { const s = this.checkLine( t, { row: 0, col: n }, { row: 1, col: 1 }, "diagonal" ); if (s) return s; if (n > 0) { const i = this.checkLine( t, { row: n, col: 0 }, { row: 1, col: 1 }, "diagonal" ); if (i) return i; } } for (let n = 0; n <= this.boardSize - this.winLength; n++) { const s = this.checkLine( t, { row: 0, col: this.boardSize - 1 - n }, { row: 1, col: -1 }, "diagonal" ); if (s) return s; if (n > 0) { const i = this.checkLine( t, { row: n, col: this.boardSize - 1 }, { row: 1, col: -1 }, "diagonal" ); if (i) return i; } } return null; } /** * Checks a line for consecutive pieces */ checkLine(t, n, s, i) { let o = 0, r = null; const a = []; let l = n.row, c = n.col; for (; this.isValidPosition({ row: l, col: c }); ) { const u = t[l][c]; if (u === null ? (o = 0, r = null, a.length = 0) : u === r ? (o++, a.push({ row: l, col: c })) : (r = u, o = 1, a.length = 0, a.push({ row: l, col: c })), o >= this.winLength && r) return { player: r, positions: a.slice(-this.winLength), // Get the last winLength positions type: i }; l += s.row, c += s.col; } return null; } /** * Evaluates board position for AI (minimax algorithm) */ evaluateBoard(t, n) { const s = this.checkWin(t); return s ? s.player === n ? 10 : -10 : this.isBoardFull(t) ? 0 : this.evaluatePosition(t, n); } /** * Advanced position evaluation for AI */ evaluatePosition(t, n) { let s = 0; const i = n === "X" ? "O" : "X"; if (s += this.evaluateAllLines(t, n, 1), s -= this.evaluateAllLines(t, i, 1), this.boardSize >= 3) { const o = Math.floor(this.boardSize / 2); t[o][o] === n ? s += 0.3 : t[o][o] === i && (s -= 0.3); } return s; } /** * Evaluates all possible lines for potential wins */ evaluateAllLines(t, n, s) { let i = 0; for (let o = 0; o < this.boardSize; o++) i += this.evaluateLine(t, { row: o, col: 0 }, { row: 0, col: 1 }, n) * s; for (let o = 0; o < this.boardSize; o++) i += this.evaluateLine(t, { row: 0, col: o }, { row: 1, col: 0 }, n) * s; for (let o = 0; o <= this.boardSize - this.winLength; o++) i += this.evaluateLine(t, { row: 0, col: o }, { row: 1, col: 1 }, n) * s, o > 0 && (i += this.evaluateLine(t, { row: o, col: 0 }, { row: 1, col: 1 }, n) * s), i += this.evaluateLine(t, { row: 0, col: this.boardSize - 1 - o }, { row: 1, col: -1 }, n) * s, o > 0 && (i += this.evaluateLine(t, { row: o, col: this.boardSize - 1 }, { row: 1, col: -1 }, n) * s); return i; } /** * Evaluates a single line for a player */ evaluateLine(t, n, s, i) { let o = 0, r = 0, a = 0, l = 0; const c = i === "X" ? "O" : "X"; let u = n.row, f = n.col, h = 0; for (; this.isValidPosition({ row: u, col: f }) && h < this.winLength; ) { const m = t[u][f]; m === i ? r++ : m === c ? l++ : a++, u += s.row, f += s.col, h++; } return l > 0 ? 0 : (r === this.winLength - 1 && a === 1 ? o = 5 : r === this.winLength - 2 && a === 2 ? o = 2 : r > 0 && (o = 1), o); } /** * Creates a copy of the board */ cloneBoard(t) { return t.map((n) => [...n]); } /** * Converts position to string for caching */ positionToString(t) { return `${t.row},${t.col}`; } /** * Converts string back to position */ stringToPosition(t) { const [n, s] = t.split(",").map(Number); return { row: n, col: s }; } /** * Converts board to string for hashing/caching */ boardToString(t) { return t.map((n) => n.map((s) => s || "_").join("")).join(""); } /** * Gets the opposite player */ getOpponentPlayer(t) { return t === "X" ? "O" : "X"; } /** * Calculates move score for move ordering in AI */ getMoveScore(t, n, s) { const { row: i, col: o } = n; let r = 0; const a = Math.floor(this.boardSize / 2), l = Math.abs(i - a) + Math.abs(o - a); return r += (this.boardSize - l) * 0.1, this.boardSize === 3 && (i === 0 || i === 2) && (o === 0 || o === 2) && (r += 0.2), r; } /** * Get all possible moves sorted by potential value */ getSortedMoves(t, n) { return this.getEmptyPositions(t).sort((i, o) => { const r = this.getMoveScore(t, i, n); return this.getMoveScore(t, o, n) - r; }); } } class Po { constructor(t = 3, n = "medium", s = "O") { this.engine = new Pi(t), this.difficulty = n, this.player = s, this.state = { isThinking: !1, lastMove: null, moveCount: 0, thinkingTime: 0 }; } /** * Makes a move based on current difficulty level */ async makeMove(t) { this.state.isThinking = !0; const n = Date.now(); try { const s = this.getThinkingDelay(); await this.delay(s); let i; switch (this.difficulty) { case "easy": i = this.makeEasyMove(t); break; case "medium": i = this.makeMediumMove(t); break; case "hard": i = this.makeHardMove(t); break; default: i = this.makeMediumMove(t); } return this.state.thinkingTime = Date.now() - n, this.state.lastMove = i, this.state.moveCount++, i; } finally { this.state.isThinking = !1; } } /** * Easy AI: Mostly random with basic win/block logic */ makeEasyMove(t) { const n = this.getAvailableMoves(t); if (Math.random() > 0.5) { const s = this.findWinningMove(t) || this.findBlockingMove(t); if (s) return s; } return n[Math.floor(Math.random() * n.length)]; } /** * Medium AI: Always tries to win or block, then plays strategically */ makeMediumMove(t) { const n = this.findWinningMove(t); if (n) return n; const s = this.findBlockingMove(t); return s || this.findStrategicMove(t); } /** * Hard AI: Uses minimax algorithm for optimal play */ makeHardMove(t) { const n = this.findWinningMove(t); if (n) return n; const s = this.findBlockingMove(t); return s || this.findOptimalMove(t); } /** * Find a move that wins the game immediately */ findWinningMove(t) { const n = this.getAvailableMoves(t); for (const s of n) { const i = this.engine.makeMove(t, s, this.player); if (this.engine.checkWin(i)) return s; } return null; } /** * Find a move that blocks the opponent from winning */ findBlockingMove(t) { const n = this.getAvailableMoves(t), s = this.getOpponent(); for (const i of n) { const o = this.engine.makeMove(t, i, s); if (this.engine.checkWin(o)) return i; } return null; } /** * Find a strategic move (center, corners, edges in that order) */ findStrategicMove(t) { const n = this.getAvailableMoves(t), s = t.length, i = Math.floor(s / 2), o = { row: i, col: i }; if (this.isMoveAvailable(t, o)) return o; const r = [ { row: 0, col: 0 }, { row: 0, col: s - 1 }, { row: s - 1, col: 0 }, { row: s - 1, col: s - 1 } ]; for (const a of r) if (this.isMoveAvailable(t, a)) return a; return n[0]; } /** * Find optimal move using simple minimax */ findOptimalMove(t) { const n = this.getAvailableMoves(t); let s = n[0], i = -1 / 0; for (const o of n) { const r = this.engine.makeMove(t, o, this.player), a = this.minimax(r, 5, !1); a > i && (i = a, s = o); } return s; } /** * Simple minimax algorithm */ minimax(t, n, s) { const i = this.engine.checkWin(t); if (i) return i.player === this.player ? 10 - n : n - 10; if (this.engine.isBoardFull(t) || n === 0) return 0; const o = this.getAvailableMoves(t); if (s) { let r = -1 / 0; for (const a of o) { const l = this.engine.makeMove(t, a, this.player), c = this.minimax(l, n - 1, !1); r = Math.max(r, c); } return r; } else { let r = 1 / 0; for (const a of o) { const l = this.engine.makeMove(t, a, this.getOpponent()), c = this.minimax(l, n - 1, !0); r = Math.min(r, c); } return r; } } /** * Get all available moves on the board */ getAvailableMoves(t) { const n = []; for (let s = 0; s < t.length; s++) for (let i = 0; i < t[s].length; i++) t[s][i] === null && n.push({ row: s, col: i }); return n; } /** * Check if a move is available */ isMoveAvailable(t, n) { return t[n.row][n.col] === null; } /** * Get the opponent player */ getOpponent() { return this.player === "X" ? "O" : "X"; } /** * Get thinking delay based on difficulty */ getThinkingDelay() { switch (this.difficulty) { case "easy": return 300 + Math.random() * 500; case "medium": return 500 + Math.random() * 700; case "hard": return 800 + Math.random() * 1e3; default: return 500; } } /** * Simple delay utility */ delay(t) { return new Promise((n) => setTimeout(n, t)); } /** * Get current AI state */ getState() { return { ...this.state }; } /** * Set AI difficulty */ setDifficulty(t) { this.difficulty = t; } /** * Reset AI state */ reset() { this.state = { isThinking: !1, lastMove: null, moveCount: 0, thinkingTime: 0 }; } } const tt = (e, t, n = 365) => { const s = /* @__PURE__ */ new Date(); s.setTime(s.getTime() + n * 24 * 60 * 60 * 1e3), document.cookie = `${e}=${t};expires=${s.toUTCString()};path=/`; }, nt = (e) => { const t = e + "=", n = document.cookie.split(";"); for (let s = 0; s < n.length; s++) { let i = n[s]; for (; i.charAt(0) === " "; ) i = i.substring(1, i.length); if (i.indexOf(t) === 0) return i.substring(t.length, i.length); } return null; }, To = () => { const [e, t] = ge("menu"), [n] = ge(() => new Pi(3)), [s, i] = ge(null), [o, r] = ge(!1), a = Q(() => ({ name: nt("playerName") || "Player", gamesPlayed: parseInt(nt("gamesPlayed") || "0"), wins: parseInt(nt("wins") || "0"), winStreak: parseInt(nt("winStreak") || "0"), draws: parseInt(nt("draws") || "0") }), []), [l, c] = ge(a), u = Q((S) => { tt("playerName", S.name), tt("gamesPlayed", S.gamesPlayed.toString()), tt("wins", S.wins.toString()), tt("winStreak", S.winStreak.toString()), tt("draws", S.draws.toString()); }, []), f = Q(() => ({ board: n.createEmptyBoard(), currentPlayer: "X", gameMode: "twoPlayer", status: "waiting", winner: null, winCondition: null, moveHistory: [], startTime: Date.now(), settings: Tt, players: { X: { id: "player1", name: l.name, stats: { gamesPlayed: 0, wins: 0, losses: 0, draws: 0, winStreak: 0, longestWinStreak: 0, totalMoves: 0, averageMovesPerGame: 0, fastestWin: 0 }, achievements: [], preferences: Tt }, O: { id: "player2", name: "Player 2", stats: { gamesPlayed: 0, wins: 0, losses: 0, draws: 0, winStreak: 0, longestWinStreak: 0, totalMoves: 0, averageMovesPerGame: 0, fastestWin: 0 }, achievements: [], preferences: Tt } }, scores: { X: 0, O: 0 }, round: 1 }), [n, l.name]), [h, m] = ge(f), g = Q((S, L) => { c((H) => { const j = { ...H }; return j.gamesPlayed++, S === "X" ? (j.wins++, j.winStreak++) : (S === null && j.draws++, j.winStreak = 0), u(j), j; }); }, [u]), v = Q((S) => { c((L) => { const H = { ...L, name: S }; return u(H), H; }), m((L) => ({ ...L, players: { ...L.players, X: { ...L.players.X, name: S } } })); }, [u]), T = Q(() => { t("menu"); }, []), P = Q((S, L) => { const H = { ...Tt, ...L }; if (S === "singlePlayer") { const j = new Po(H.boardSize, H.difficulty, "O"); i(j); } else i(null); m((j) => ({ ...f(), gameMode: S, settings: H, status: "playing", players: { ...j.players, X: { ...j.players.X, name: l.name }, O: S === "singlePlayer" ? { ...j.players.O, name: "AI Player" } : j.players.O } })), t("game"); }, [f, l.name]), b = Q(async (S) => { if (h.status !== "playing" || o) return !1; try { if (!n.isValidMove(h.board, S)) return !1; const L = n.makeMove(h.board, S, h.currentPlayer), H = { position: S, player: h.currentPlayer, timestamp: Date.now(), moveNumber: h.moveHistory.length + 1 }, j = n.checkWin(L), $ = n.isBoardFull(L); let R = h.status, O = null; j ? (R = "finished", O = j.player) : $ && (R = "finished", O = null); const F = n.getOpponentPlayer(h.currentPlayer); if (m((Y) => ({ ...Y, board: L, currentPlayer: F, moveHistory: [...Y.moveHistory, H], status: R, winner: O, winCondition: j, endTime: R === "finished" ? Date.now() : void 0 })), R === "finished") { const Y = Date.now() - h.startTime; g(O, Y), O && m((oe) => ({ ...oe, scores: { ...oe.scores, [O]: oe.scores[O] + 1 } })); } return !0; } catch (L) { return console.error("Move failed:", L), !1; } }, [h, n, o, g]), x = Q(async () => { if (!(!s || h.status !== "playing" || h.currentPlayer !== "O" || o)) { r(!0); try { const S = await s.makeMove(h.board); if (n.isValidMove(h.board, S)) { const L = n.makeMove(h.board, S, "O"), H = { position: S, player: "O", timestamp: Date.now(), moveNumber: h.moveHistory.length + 1 }, j = n.checkWin(L), $ = n.isBoardFull(L); let R = h.status, O = null; if (j ? (R = "finished", O = j.player) : $ && (R = "finished", O = null), m((F) => ({ ...F, board: L, currentPlayer: "X", moveHistory: [...F.moveHistory, H], status: R, winner: O, winCondition: j, endTime: R === "finished" ? Date.now() : void 0 })), R === "finished") { const F = Date.now() - h.startTime; g(O, F), O && m((Y) => ({ ...Y, scores: { ...Y.scores, [O]: Y.scores[O] + 1 } })); } } } catch (S) { console.error("AI move failed:", S); } finally { r(!1); } } }, [s, h, n, o, g]); dt(() => { if (h.gameMode === "singlePlayer" && h.currentPlayer === "O" && h.status === "playing" && !o) { const S = setTimeout(x, 500); return () => clearTimeout(S); } }, [h.currentPlayer, h.status, h.gameMode, o, x]); const C = Q(() => { m((S) => ({ ...f(), gameMode: S.gameMode, settings: S.settings, players: S.players, scores: S.scores, round: S.round + 1, status: "playing" })), r(!1); }, [f]), V = Q(() => h.status === "playing" || h.status === "paused", [h.status]), U = Q(() => h.gameMode === "singlePlayer" && h.currentPlayer === "O" && h.status === "playing", [h]), B = Q(() => { if (!h.startTime) return 0; const S = h.endTime || Date.now(); return Math.floor((S - h.startTime) / 1e3); }, [h]), D = Q(() => l, [l]); return { gameState: h, currentView: e, aiPlayer: s, engine: n, playerData: l, // View navigation setCurrentView: t, showMenu: T, startNewGame: P, // Player management updatePlayerName: v, // Game actions makeMove: b, resetGame: C, // Game state queries isGameActive: V, isAITurn: U, getGameDuration: B, getTotalStats: D }; }, Ti = Le(void 0), So = ({ children: e }) => { const t = To(); return /* @__PURE__ */ p.jsx(Ti.Provider, { value: t, children: e }); }, Co = () => { const e = te(Ti); if (e === void 0) throw new Error("useGame must be used within a GameProvider"); return e; }, ds = ({ onStartGame: e, playerName: t, onPlayerNameChange: n, totalStats: s }) => { const [i, o] = ge("medium"), [r, a] = ge(t), [l, c] = ge(!1); dt(() => { a(t), c(!1); }, [t]); const u = (m) => { a(m), c(m.trim() !== t); }, f = () => { r.trim() && r.trim() !== t && (n(r.trim()), c(!1)); }, h = (m) => { m.key === "Enter" && f(); }; return /* @__PURE__ */ p.jsx("div", { className: "min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 flex items-center justify-center p-4", children: /* @__PURE__ */ p.jsxs("div", { className: "max-w-md w-full bg-white rounded-2xl shadow-2xl p-8", children: [ /* @__PURE__ */ p.jsxs("div", { className: "text-center mb-8", children: [ /* @__PURE__ */ p.jsx("h1", { className: "text-4xl font-bold text-gray-800 mb-2", children: "Advanced Tic-Tac-Toe" }), /* @__PURE__ */ p.jsx("p", { className: "text-gray-600", children: "Challenge the AI or play with friends" }) ] }), /* @__PURE__ */ p.jsxs("div", { className: "mb-8", children: [ /* @__PURE__ */ p.jsx("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: "Player Name" }), /* @__PURE__ */ p.jsxs("div", { className: "flex gap-2", children: [ /* @__PURE__ */ p.jsx( "input", { type: "text", value: r, onChange: (m) => u(m.target.value), onKeyPress: h, onBlur: f, className: "flex-1 px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent", placeholder: "Enter your name", maxLength: 20 } ), l && /* @__PURE__ */ p.jsx( "button", { onClick: f, className: "px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors", children: "Save" } ) ] }) ] }), /* @__PURE__ */ p.jsxs("div", { className: "mb-8 p-4 bg-gray-50 rounded-lg", children: [ /* @__PURE__ */ p.jsx("h3", { className: "font-semibold text-gray-800 mb-3", children: "Your Stats" }), /* @__PURE__ */ p.jsxs("div", { className: "grid grid-cols-2 gap-3 text-sm", children: [ /* @__PURE__ */ p.jsxs("div", { className: "text-center", children: [ /* @__PURE__ */ p.jsx("p", { className: "text-2xl font-bold text-blue-600", children: s.gamesPlayed }), /* @__PURE__ */ p.jsx("p", { className: "text-gray-600", children: "Games Played" }) ] }), /* @__PURE__ */ p.jsxs("div", { className: "text-center", children: [ /* @__PURE__ */ p.jsx("p", { className: "text-2xl font-bold text-green-600", children: s.wins }), /* @__PURE__ */ p.jsx("p", { className: "text-gray-600", children: "Wins" }) ] }), /* @__PURE__ */ p.jsxs("div", { className: "text-center", children: [ /* @__PURE__ */ p.jsx("p", { className: "text-2xl font-bold text-yellow-600", children: s.draws }), /* @__PURE__ */ p.jsx("p", { className: "text-gray-600", children: "Draws" }) ] }), /* @__PURE__ */ p.jsxs("div", { className: "text-center", children: [ /* @__PURE__ */ p.jsx("p", { className: "text-2xl font-bold text-purple-600", children: s.winStreak }), /* @__PURE__ */ p.jsx("p", { className: "text-gray-600", children: "Win Streak" }) ] }) ] }) ] }), /* @__PURE__ */ p.jsxs("div", { className: "mb-6", children: [ /* @__PURE__ */ p.jsx("label", { className: "block text-sm font-medium text-gray-700 mb-3", children: "AI Difficulty" }), /* @__PURE__ */ p.jsx("div", { className: "grid grid-cols-3 gap-2", children: ["easy", "medium", "hard"].map((m) => /* @__PURE__ */ p.jsx( "button", { onClick: () => o(m), className: `px-3 py-2 rounded-lg text-sm font-medium transition-colors ${i === m ? "bg-blue-500 text-white" : "bg-gray-200 text-gray-700 hover:bg-gray-300"}`, children: m.charAt(0).toUpperCase() + m.slice(1) }, m )) }) ] }), /* @__PURE__ */ p.jsxs("div", { className: "space-y-3", children: [ /* @__PURE__ */ p.jsxs( "button", { onClick: () => e("singlePlayer", { difficulty: i }), className: "w-full bg-blue-500 hover:bg-blue-600 text-white font-medium py-3 px-6 rounded-lg transition-colors duration-200 flex items-center justify-center gap-2", children: [ /* @__PURE__ */ p.jsx("span", { children: "🤖" }), "Play vs AI (", i, ")" ] } ), /* @__PURE__ */ p.jsxs( "button", { onClick: () => e("twoPlayer"), className: "w-full bg-green-500 hover:bg-green-600 text-white font-medium py-3 px-6 rounded-lg transition-colors duration-200 flex items-center justify-center gap-2", children: [ /* @__PURE__ */ p.jsx("span", { children: "👥" }), "Play with Friend" ] } ) ] }), /* @__PURE__ */ p.jsx("div", { className: "mt-8 text-center text-xs text-gray-500", children: "Your progress is automatically saved" }) ] }) }); }, Si = Le({ transformPagePoint: (e) => e, isStatic: !1, reducedMotion: "never" }), _t = Le({}), jn = Le(null), Wt = typeof document < "u", Ao = Wt ? go : dt, Ci = Le({ strict: !1 }), Dn = (e) => e.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(), Mo = "framerAppearId", Ai = "data-" + Dn(Mo); function Vo(e, t, n, s) { const { visualElement: i } = te(_t), o = te(Ci), r = te(jn), a = te(Si).reducedMotion, l = dn(); s = s || o.renderer, !l.current && s && (l.current = s(e, { visualState: t, parent: i, props: n, presenceContext: r, blockInitialAnimation: r ? r.initial === !1 : !1, reducedMotionConfig: a })); const c = l.current; yo(() => { c && c.update(n, r); }); const u = dn(!!(n[Ai] && !window.HandoffComplete)); return Ao(() => { c && (c.render(), u.current && c.animationState && c.animationState.animateChanges()); }), dt(() => { c && (c.updateFeatures(), !u.current && c.animationState && c.animationState.animateChanges(), u.current && (u.current = !1, window.HandoffComplete = !0)); }), c; } function Ue(e) { return e && typeof e == "object" && Object.prototype.hasOwnProperty.call(e, "current"); } function jo(e, t, n) { return Q( (s) => { s && e.mount && e.mount(s), t && (s ? t.mount(s) : t.unmount()), n && (typeof n == "function" ? n(s) : Ue(n) && (n.current = s)); }, /** * Only pass a new ref callback to React if we've received a visual element * factory. Otherwise we'll be mounting/remounting every time externalRef * or other dependencies change. */ [t] ); } function ut(e) { return typeof e == "string" || Array.isArray(e); } function Ut(e) { return e !== null && typeof e == "object" && typeof e.start == "function"; } const kn = [ "animate", "whileInView", "whileFocus", "whileHover", "whileTap", "whileDrag", "exit" ], Rn = ["initial", ...kn]; function $t(e) { return Ut(e.animate) || Rn.some((t) => ut(e[t])); } function Mi(e) { return !!($t(e) || e.variants); } function Do(e, t) { if ($t(e)) { const { initial: n, animate: s } = e; return { initial: n === !1 || ut(n) ? n : void 0, animate: ut(s) ? s : void 0 }; } return e.inherit !== !1 ? t : {}; } function ko(e) { const { initial: t, animate: n } = Do(e, te(_t)); return It(() => ({ initial: t, animate: n }), [ms(t), ms(n)]); } function ms(e) { return Array.isArray(e) ? e.join(" ") : e; } const ps = { animation: [ "animate", "variants", "whileHover", "whileTap", "exit", "whileInView", "whileFocus", "whileDrag" ], exit: ["exit"], drag: ["drag", "dragControls"], focus: ["whileFocus"], hover: ["whileHover", "onHoverStart", "onHoverEnd"], tap: ["whileTap", "onTap", "onTapStart", "onTapCancel"], pan: ["onPan", "onPanStart", "onPanSessionStart", "onPanEnd"], inView: ["whileInView", "onViewportEnter", "onViewportLeave"], layout: ["layout", "layoutId"] }, ft = {}; for (const e in ps) ft[e] = { isEnabled: (t) => ps[e].some((n) => !!t[n]) }; function Ro(e) { for (const t in e) ft[t] = { ...ft[t], ...e[t] }; } const Vi = Le({}), ji = Le({}), Eo = Symbol.for("motionComponentSymbol"); function No({ preloadedFeatures: e, createVisualElement: t, useRender: n, useVisualState: s, Component: i }) { e && Ro(e); function o(a, l) { let c; const u = { ...te(Si), ...a, layoutId: Lo(a) }, { isStatic: f } = u, h = ko(a), m = s(a, f); if (!f && Wt) { h.visualElement = Vo(i, m, u, t); const g = te(ji), v = te(Ci).strict; h.visua