Don't use component library for game boards...
This commit is contained in:
parent
9fd2b4d507
commit
677221603c
|
@ -8,6 +8,7 @@
|
|||
"name": "frontend",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"@game-algorithms/connect-four-rust": "^0.0.1",
|
||||
"@game-algorithms/o-x-rust": "^0.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -80,6 +81,12 @@
|
|||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@game-algorithms/connect-four-rust": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://git.koval.net/api/packages/cyclane/npm/%40game-algorithms%2Fconnect-four-rust/-/0.0.1/connect-four-rust-0.0.1.tgz",
|
||||
"integrity": "sha512-XFVCupzmxi6lL9jfrETenwQwo7JDvGby8PB2jOfRuRpmGBZwgx9GQvc9euw+LwlGCXUhN8zYqKIdoU7IDfd6ng==",
|
||||
"license": "GNU GPLv3"
|
||||
},
|
||||
"node_modules/@game-algorithms/o-x-rust": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://git.koval.net/api/packages/cyclane/npm/%40game-algorithms%2Fo-x-rust/-/0.1.0/o-x-rust-0.1.0.tgz",
|
||||
|
@ -2927,6 +2934,11 @@
|
|||
"strip-json-comments": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"@game-algorithms/connect-four-rust": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://git.koval.net/api/packages/cyclane/npm/%40game-algorithms%2Fconnect-four-rust/-/0.0.1/connect-four-rust-0.0.1.tgz",
|
||||
"integrity": "sha512-XFVCupzmxi6lL9jfrETenwQwo7JDvGby8PB2jOfRuRpmGBZwgx9GQvc9euw+LwlGCXUhN8zYqKIdoU7IDfd6ng=="
|
||||
},
|
||||
"@game-algorithms/o-x-rust": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://git.koval.net/api/packages/cyclane/npm/%40game-algorithms%2Fo-x-rust/-/0.1.0/o-x-rust-0.1.0.tgz",
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@game-algorithms/o-x-rust": "^0.1.0"
|
||||
"@game-algorithms/o-x-rust": "^0.1.0",
|
||||
"@game-algorithms/connect-four-rust": "^0.0.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
<script lang="ts">
|
||||
import { type SvelteComponent, createEventDispatcher } from "svelte";
|
||||
|
||||
export let board: number[];
|
||||
export let iconMap: Record<number, typeof SvelteComponent>;
|
||||
export let disabled = false;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
/**
|
||||
* Generate handler function for board cell click
|
||||
*
|
||||
* @param idx Index of cell for event
|
||||
* @returns Handler function
|
||||
*/
|
||||
function handleClick(idx: number) {
|
||||
return () => dispatch("click", {
|
||||
idx
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="grid">
|
||||
{#each board as b, idx}
|
||||
<button disabled={b !== 0 || disabled} class="item" on:click={handleClick(idx)}>
|
||||
<svelte:component this="{iconMap[b]}"/>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
max-width: min(100%, 24rem);
|
||||
border: 1px solid var(--cds-interactive-03);
|
||||
}
|
||||
button.item {
|
||||
cursor: pointer;
|
||||
aspect-ratio: 1/1;
|
||||
background: none;
|
||||
border: 2px solid var(--cds-interactive-03);
|
||||
color: var(--cds-interactive-03);
|
||||
transition: background 70ms cubic-bezier(0, 0, 0.38, 0.9),
|
||||
color 70ms cubic-bezier(0, 0, 0.38, 0.9);
|
||||
}
|
||||
button.item:enabled:hover {
|
||||
background-color: var(--cds-hover-tertiary);
|
||||
color: var(--cds-inverse-01);
|
||||
}
|
||||
button.item:disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
</style>
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<style>
|
||||
div {
|
||||
width: 5rem;
|
||||
height: 5rem;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
<style>
|
||||
h1 {
|
||||
width: 5rem;
|
||||
height: 5rem;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 4rem;
|
||||
}
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
<style>
|
||||
h1 {
|
||||
width: 5rem;
|
||||
height: 5rem;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 4rem;
|
||||
}
|
|
@ -2,6 +2,10 @@
|
|||
import { Column, Grid, Link, Row } from "carbon-components-svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>About</title>
|
||||
</svelte:head>
|
||||
|
||||
<Grid>
|
||||
<Row>
|
||||
<Column>
|
||||
|
|
|
@ -12,14 +12,15 @@
|
|||
UnorderedList
|
||||
} from "carbon-components-svelte";
|
||||
import wasmInit, { count_empty, find_winner, get_score, predict } from "@game-algorithms/o-x-rust";
|
||||
import OXNoneIcon from "$lib/components/OXNoneIcon.svelte";
|
||||
import OXOIcon from "$lib/components/OXOIcon.svelte";
|
||||
import OXXIcon from "$lib/components/OXXIcon.svelte";
|
||||
import OXBoard from "$lib/components/o-x/OXBoard.svelte";
|
||||
import OXNoneIcon from "$lib/components/o-x/OXNoneIcon.svelte";
|
||||
import OXOIcon from "$lib/components/o-x/OXOIcon.svelte";
|
||||
import OXXIcon from "$lib/components/o-x/OXXIcon.svelte";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
let board: number[][] = [];
|
||||
for (let i = 0;i < 3;i++) {
|
||||
board.push([0, 0, 0]);
|
||||
let board: number[] = [];
|
||||
for (let i = 0;i < 9;i++) {
|
||||
board.push(0);
|
||||
}
|
||||
|
||||
let turn = -1;
|
||||
|
@ -44,7 +45,7 @@
|
|||
* Complete a turn logic
|
||||
*/
|
||||
function completeTurn() {
|
||||
const convertedBoard = Uint8Array.from(board.flat());
|
||||
const convertedBoard = Uint8Array.from(board);
|
||||
scores = [...scores, getBoardScore(board, human, bot, algorithm)];
|
||||
const winner = find_winner(convertedBoard);
|
||||
if (winner !== 0 || count_empty(convertedBoard) === 0) {
|
||||
|
@ -73,7 +74,7 @@
|
|||
} else {
|
||||
status = "Algorithm's turn!";
|
||||
const p = predict(bot, human, bot === 1, convertedBoard, algorithm);
|
||||
board[Math.floor(p / 3)][p % 3] = bot;
|
||||
board[p] = bot;
|
||||
completeTurn();
|
||||
}
|
||||
}
|
||||
|
@ -88,17 +89,17 @@
|
|||
* @returns The scores for the moves for each cell and player
|
||||
*/
|
||||
function getBoardScore(
|
||||
board: number[][],
|
||||
board: number[],
|
||||
human: number,
|
||||
bot: number,
|
||||
algorithm: string
|
||||
): [number | null, number | null][] {
|
||||
return board.flat().map((v, i) => {
|
||||
if (v === 0) {
|
||||
const humanCopy = board.flat();
|
||||
const humanCopy = board.slice();
|
||||
humanCopy[i] = human;
|
||||
const hUint8Array = Uint8Array.from(humanCopy);
|
||||
const botCopy = board.flat();
|
||||
const botCopy = board.slice();
|
||||
botCopy[i] = bot;
|
||||
const bUint8Array = Uint8Array.from(humanCopy);
|
||||
return [
|
||||
|
@ -151,6 +152,10 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Noughts & Crosses</title>
|
||||
</svelte:head>
|
||||
|
||||
<Grid>
|
||||
<Row>
|
||||
<Column>
|
||||
|
@ -166,7 +171,7 @@
|
|||
<ListItem>mm+d: minimax with depth</ListItem>
|
||||
</UnorderedList>
|
||||
<div class="selection">
|
||||
<RadioButtonGroup disabled={turn !== -1} legendText="Algorithms" bind:selected={algorithm}>
|
||||
<RadioButtonGroup disabled={turn !== -1} legendText="Algorithm" bind:selected={algorithm}>
|
||||
<RadioButton labelText="sa" value="sa" />
|
||||
<RadioButton labelText="sa+rd" value="sa+rd" />
|
||||
<RadioButton labelText="sa+r-d" value="sa+r-d" />
|
||||
|
@ -183,8 +188,8 @@
|
|||
<Button disabled={!loaded || turn !== -1} on:click={() => {
|
||||
board = [];
|
||||
scores = [];
|
||||
for (let i = 0;i < 3;i++) {
|
||||
board.push([0, 0, 0]);
|
||||
for (let i = 0;i < 9;i++) {
|
||||
board.push(0);
|
||||
}
|
||||
turn = 2;
|
||||
human = Number(playAs === "O") + 1;
|
||||
|
@ -199,27 +204,19 @@
|
|||
<h2>Board</h2>
|
||||
<p>{status}</p>
|
||||
{#if loaded}
|
||||
<Grid>
|
||||
{#each board as row, r}
|
||||
<Row>
|
||||
{#each row as col, c}
|
||||
<Column sm={.1} style="border: 1px solid white;">
|
||||
<Button
|
||||
kind="tertiary"
|
||||
iconDescription={col === 0 ? "Available" : col === 1 ? "Cross" : "Nought"}
|
||||
icon={col === 0 ? OXNoneIcon : col === 1 ? OXXIcon : OXOIcon}
|
||||
disabled={board[r][c] !== 0 || turn !== human}
|
||||
on:click={() => {
|
||||
board[r][c] = human;
|
||||
completeTurn();
|
||||
console.log(scores);
|
||||
}}
|
||||
/>
|
||||
</Column>
|
||||
{/each}
|
||||
</Row>
|
||||
{/each}
|
||||
</Grid>
|
||||
<OXBoard
|
||||
disabled={turn !== human}
|
||||
board={board}
|
||||
iconMap={{
|
||||
0: OXNoneIcon,
|
||||
1: OXXIcon,
|
||||
2: OXOIcon
|
||||
}}
|
||||
on:click={event => {
|
||||
board[event.detail.idx] = human;
|
||||
completeTurn();
|
||||
}}
|
||||
/>
|
||||
{:else}
|
||||
<h3>Loading...</h3>
|
||||
{/if}
|
||||
|
@ -248,7 +245,7 @@
|
|||
key: "move",
|
||||
value: "Move"
|
||||
},
|
||||
...board.flat().map((_, c) => {
|
||||
...board.map((_, c) => {
|
||||
return {
|
||||
key: c.toString(),
|
||||
value: (c + 1).toString()
|
||||
|
|
Loading…
Reference in New Issue