diff --git a/src/lib/games/quantum-tictactoe/AiApp.svelte b/src/lib/games/quantum-tictactoe/AiApp.svelte new file mode 100644 index 0000000..c367a4a --- /dev/null +++ b/src/lib/games/quantum-tictactoe/AiApp.svelte @@ -0,0 +1,227 @@ + + + +
+ + +
+ + + diff --git a/src/lib/utils/getRandomInt.ts b/src/lib/utils/getRandomInt.ts new file mode 100644 index 0000000..4799287 --- /dev/null +++ b/src/lib/utils/getRandomInt.ts @@ -0,0 +1,49 @@ +type GetRandomInt = (prop: { min?: number; max: number; excepts?: number[] }) => number; + +const getRandomInt: GetRandomInt = ({ min, max, excepts }) => { + if (min === undefined) min = 0; + if (!Number.isInteger(min) || !Number.isInteger(max)) + console.error('getRandomInt: arguments min and max should be integers.'); + + if (max < min) console.error('getRandomInt: argument max should be greater than min.'); + + if (excepts && !Array.isArray(excepts)) + console.error('getRandomInt: argument excepts should be an array.'); + if (excepts && Array.isArray(excepts)) { + while (excepts.includes(min)) min++; + while (excepts.includes(max)) max--; + if (max < min) + console.error( + 'getRandomInt: range [min, max] must have at least one integer not included in excepts.' + ); + } + + let ret = Math.floor(Math.random() * (max - min + 1)) + min; + while (excepts && Array.isArray(excepts) && excepts.includes(ret)) + ret = Math.floor(Math.random() * (max - min + 1)) + min; + + return ret; +}; + +export { getRandomInt }; + +// test +if (import.meta.vitest) { + const { test, expect } = import.meta.vitest; + test('getRandomInt', () => { + const min = 1; + const max = 10; + const n = getRandomInt({ min, max }); + expect(n).toBeGreaterThanOrEqual(min); + expect(n).toBeLessThanOrEqual(max); + }); + test('getRandomInt with excepts', () => { + const min = 1; + const max = 10; + const excepts = [1, 2, 3, 8, 10]; + const n = getRandomInt({ min, max, excepts }); + expect(n).toBeGreaterThanOrEqual(4); + expect(n).toBeLessThanOrEqual(9); + expect(excepts.includes(n)).toBe(false); + }); +} diff --git a/src/lib/utils/sleep.ts b/src/lib/utils/sleep.ts new file mode 100644 index 0000000..414dfc7 --- /dev/null +++ b/src/lib/utils/sleep.ts @@ -0,0 +1,16 @@ +const sleep = async (ms: number): Promise => + new Promise((resolve) => setTimeout(resolve, ms)); + +export { sleep }; + +// test +if (import.meta.vitest) { + const { test, expect } = import.meta.vitest; + test('sleep', async () => { + const sleepTime = 100; + const start = Date.now(); + await sleep(sleepTime); + const end = Date.now(); + expect(end - start).toBeGreaterThanOrEqual(sleepTime); + }); +} diff --git a/src/routes/games/quantum-tictactoe/+page.svelte b/src/routes/games/quantum-tictactoe/+page.svelte index 40b023d..052376e 100644 --- a/src/routes/games/quantum-tictactoe/+page.svelte +++ b/src/routes/games/quantum-tictactoe/+page.svelte @@ -19,6 +19,10 @@ let footerHeight: number; >チュートリアル +
  • + AI対局 +
  • オフライン対局 +import AiApp from '$lib/games/quantum-tictactoe/AiApp.svelte'; + + + + + Quantum Tic-Tac-Toe - Quantum Game Arena + + + + +
    + +

    Quantum Tic-Tac-Toe

    + +
    + + diff --git a/static/sitemap.xml b/static/sitemap.xml index 7236442..8e53a4c 100644 --- a/static/sitemap.xml +++ b/static/sitemap.xml @@ -9,7 +9,7 @@ https://qgame.app/games/quantum-tictactoe - 2022-09-29 + 2024-05-04 yearly 0.8 @@ -20,6 +20,13 @@ yearly + + https://qgame.app/games/quantum-tictactoe/play/ai + 2024-05-04 + monthly + 1.0 + + https://qgame.app/games/quantum-tictactoe/play/human 2023-12-22