Add difficulty menu to UI (not yet functional)
This commit is contained in:
parent
ef655f99cd
commit
60fabb0214
4 changed files with 110 additions and 8 deletions
|
@ -27,7 +27,11 @@ function addLogInfo(existingLog: React.JSX.Element[], newItem: React.JSX.Element
|
||||||
return existingLog.slice();
|
return existingLog.slice();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Game(props: {wasm: GameWasm, settings: Settings}) {
|
export function Game(props: {
|
||||||
|
wasm: GameWasm,
|
||||||
|
settings: Settings,
|
||||||
|
end_game_fn: () => void,
|
||||||
|
}) {
|
||||||
|
|
||||||
const cellTypes = useMemo(() => {
|
const cellTypes = useMemo(() => {
|
||||||
return props.wasm.get_board_cell_types();
|
return props.wasm.get_board_cell_types();
|
||||||
|
|
81
ui/src/Menu.tsx
Normal file
81
ui/src/Menu.tsx
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import {useState} from "react";
|
||||||
|
import {GameWasm} from 'word_grid';
|
||||||
|
import {Settings} from "./utils";
|
||||||
|
import {Game} from "./Game";
|
||||||
|
|
||||||
|
export function Menu(props: {settings: Settings, dictionary_text: string}) {
|
||||||
|
|
||||||
|
const [aiRandomness, setAIRandomness] = useState<number>(6);
|
||||||
|
const [proportionDictionary, setProportionDictionary] = useState<number>(7);
|
||||||
|
const [game, setGame] = useState<React.JSX.Element>(null);
|
||||||
|
|
||||||
|
|
||||||
|
// Can change log scale to control shape of curve using following equation:
|
||||||
|
// aiRandomness = log(1 + x*(n-1))/log(n) when x, the user input, ranges between 0 and 1
|
||||||
|
const logBase: number = 10000;
|
||||||
|
const processedAIRandomness = Math.log(1 + (logBase - 1)*aiRandomness/100) / Math.log(logBase);
|
||||||
|
|
||||||
|
|
||||||
|
if (game == null) {
|
||||||
|
|
||||||
|
return <dialog open>
|
||||||
|
<div className="new-game">
|
||||||
|
<div className="grid">
|
||||||
|
<label htmlFor="proportion-dictionary">AI's proportion of dictionary:</label>
|
||||||
|
<input type="number"
|
||||||
|
name="proportion-dictionary"
|
||||||
|
value={proportionDictionary}
|
||||||
|
onInput={(e) => {
|
||||||
|
setProportionDictionary(parseInt(e.currentTarget.value));
|
||||||
|
}}
|
||||||
|
min={1}
|
||||||
|
max={100}/>
|
||||||
|
<label htmlFor="randomness">Level of randomness in AI:</label>
|
||||||
|
<input type="number"
|
||||||
|
name="randomness"
|
||||||
|
value={aiRandomness}
|
||||||
|
onInput={(e) => {
|
||||||
|
setAIRandomness(parseInt(e.currentTarget.value));
|
||||||
|
}}
|
||||||
|
min={0}
|
||||||
|
max={100}/>
|
||||||
|
</div>
|
||||||
|
<details>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
"AI's proportion of dictionary" controls what percent of the total AI dictionary
|
||||||
|
the AI can form words with. At 100%, it has access to its entire dictionary -
|
||||||
|
although this dictionary is still less than what the player has access to.</li>
|
||||||
|
<li>
|
||||||
|
<div>
|
||||||
|
"Level of randomness in AI" controls the degree to which the AI picks the optimal move
|
||||||
|
for each of its turns. At 0, it always picks the highest scoring move it can do using the
|
||||||
|
dictionary it has access to. At 1, it picks from its available moves at random.
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Note that "Level of randomness in AI" is now mapped on a log scale.
|
||||||
|
Your current setting is equivalent to {(100*processedAIRandomness).toFixed(1)}% on the previous scale.
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
<div className="selection-buttons">
|
||||||
|
<button onClick={() => {
|
||||||
|
const seed = new Date().getTime();
|
||||||
|
const game_wasm = new GameWasm(BigInt(seed), props.dictionary_text);
|
||||||
|
const game = <Game settings={props.settings} wasm={game_wasm} key={seed} end_game_fn={() => setGame(null)}/>
|
||||||
|
setGame(game);
|
||||||
|
}}>New Game</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
|
} else {
|
||||||
|
return game;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ import init, {GameWasm} from '../node_modules/word_grid/word_grid.js';
|
||||||
import {Game} from "./Game";
|
import {Game} from "./Game";
|
||||||
import {createRoot} from "react-dom/client";
|
import {createRoot} from "react-dom/client";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import {Menu} from "./Menu";
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const dictionary_url = new URL("../../resources/dictionary.csv", import.meta.url);
|
const dictionary_url = new URL("../../resources/dictionary.csv", import.meta.url);
|
||||||
|
@ -45,15 +46,9 @@ async function run() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let game = new GameWasm(BigInt(1234), dictionary_text);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const cellTypes = game.get_board_cell_types();
|
|
||||||
console.log({cellTypes});
|
|
||||||
|
|
||||||
const root = createRoot(document.getElementById("root"));
|
const root = createRoot(document.getElementById("root"));
|
||||||
root.render(<Game wasm={game} settings={{trayLength: 7}} />);
|
root.render(<Menu dictionary_text={dictionary_text} settings={{trayLength: 7}}/>);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -169,6 +169,28 @@ dialog {
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
|
||||||
|
.new-game {
|
||||||
|
width: 50em;
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 3fr 2fr;
|
||||||
|
grid-column-gap: 1em;
|
||||||
|
grid-row-gap: 0.5em;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.selection-buttons {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
justify-items: center;
|
||||||
|
padding-top: 1em;
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 40%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.close-button-div {
|
.close-button-div {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
Loading…
Reference in a new issue