summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsanine-a <sanine.not@pm.me>2021-04-16 13:07:17 -0500
committersanine-a <sanine.not@pm.me>2021-04-16 13:07:17 -0500
commit6dbd6e965439a5cce29bccc27cbb9d88afc984f7 (patch)
treed31fedf389c7f5e74f052c50cdd0e2f4c39babae
parent897d1fe760f1ea25b8dd802f152d577a396af665 (diff)
add Game component and reset()
-rw-r--r--App.js167
1 files changed, 145 insertions, 22 deletions
diff --git a/App.js b/App.js
index 7b7a22c..d72edf4 100644
--- a/App.js
+++ b/App.js
@@ -31,14 +31,17 @@ const setState = update => {
*/
// IMPURE
-const App = ({state, setState}) => {
- const { guessInput, } = state;
-
- return h(GuessInput, {
- value: guessInput.value,
- isShaking: guessInput.isShaking,
- handleInput: updateStateOnEvent(state, handleGuessInputInput),
- handleKeyDown: updateStateOnEvent(state, handleGuessInputKeyDown),
+const App = ({state}) => {
+ const { currentLevel, guessInput, } = state;
+
+ if (guessInput.isShaking)
+ // side-effect!!
+ setTimeout(() => setState({ guessInput: { isShaking: false } }), 300);
+
+ return h(Game, {
+ state,
+ currentLevel,
+ guessInput,
});
};
@@ -50,8 +53,29 @@ const App = ({state, setState}) => {
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
+const Game = ({ state, currentLevel, guessInput }) => {
+ const { characters, index, running } = currentLevel;
+
+ if (!running)
+ return h('p', {}, 'Finished');
+ else {
+ const [ character ] = characters[index];
+
+ return h('div', {}, [
+ h('p', {}, character),
+ h(GuessInput, {
+ value: guessInput.value,
+ isShaking: guessInput.isShaking,
+ handleInput: updateStateOnEvent(state, handleGuessInputInput),
+ handleKeyDown: updateStateOnEvent(state, handleGuessInputKeyDown),
+ }),
+ ]);
+ }
+};
+
+
const GuessInput = ({value, isShaking, handleInput, handleKeyDown}) => {
- const inputTag = isShaking ? 'input.shaking' : 'input';
+ const inputTag = isShaking ? 'input.shake' : 'input';
return h(inputTag, {
type: 'text',
@@ -74,39 +98,138 @@ const updateStateOnEvent = (state, handler) =>
event => setState(handler(state, event));
-const handleGuessInputInput = (state, event) =>
- ({ guessInput: { value: event.target.value } });
+const handleGuessInputInput = (state, event) => (
+ { guessInput: { value: event.target.value } }
+);
const handleGuessInputKeyDown = (state, event) => {
const KEYCODE_ENTER = 13;
+ const { guessInput, currentLevel } = state;
+
+ const guessValue = guessInput.value;
+ const { characters, index, correctGuesses, totalGuesses } = currentLevel;
+ const [ _, pinyin ] = characters[index];
+
if (event.keyCode === KEYCODE_ENTER) {
- console.log(state.guessInput.value);
- return { guessInput: { value: '' } };
+ if (guessValue === pinyin)
+ return {
+ guessInput: {
+ value: '',
+ },
+ currentLevel: {
+ index: index + 1,
+ correctGuesses: correctGuesses + 1,
+ totalGuesses: totalGuesses + 1,
+ running: (index + 1) < characters.length,
+ }
+ };
+ else
+ return {
+ guessInput: {
+ isShaking: true,
+ },
+ currentLevel: {
+ totalGuesses: totalGuesses + 1,
+ }
+ };
}
-
- return {};
+ else
+ // enter wasn't pressed, no update
+ return {};
};
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
- * Document load
+ * Document load and game reset
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
-// IMPURE
-window.onload = () => {
- const initialState = {
+const availableGameModes = (level, levelSize) => {
+ const clampNonNeg = value => value < 0 ? 0 : value;
+
+ const startLevels = [...new Set([
+ clampNonNeg(level),
+ clampNonNeg(level-3),
+ clampNonNeg(level-7),
+ clampNonNeg(level-12),
+ clampNonNeg(0),
+ ])];
+
+ const modeName = range => {
+ const [start, end] = range;
+
+ if (start === end)
+ return `Characters from level ${start+1}`;
+ else if (start === 0)
+ return `Characters from levels 1-${end+1}`;
+ else
+ return `Characters from levels ${start+1}-${end+1}`;
+ }
+
+ const mode = startLevel => {
+ const levelRange = [startLevel, level];
+ const range = levelRange.map((x, i) => levelSize * (x+i));
+
+ return {
+ name: modeName(levelRange),
+ range,
+ };
+ };
+
+ const modes = startLevels.map(mode);
+ return modes;
+};
+
+
+const reset = (state, update) => {
+ const newLevel = 0;
+ const gameModes = availableGameModes(newLevel, 20);
+ const newGameMode = 0;
+
+ // new level characters
+ const shuffled = array => {
+ const shuffle = [...array];
+ for (let i=shuffle.length-1; i>1; i--) {
+ const j = Math.floor(Math.random() * (i+1));
+ [shuffle[i], shuffle[j]] = [shuffle[j], shuffle[i]];
+ }
+ return shuffle;
+ };
+
+ const levelCharacters = gameMode => {
+ const [start, end] = gameMode.range;
+ return shuffled(characters.slice(start, end));
+ };
+
+ return {
+ gameParams: {
+ level: newLevel,
+ gameModes,
+ gameMode: newGameMode,
+ },
+ currentLevel: {
+ characters: levelCharacters(gameModes[newGameMode]),
+ index: 0,
+ correctGuesses: 0,
+ totalGuesses: 0,
+ running: true,
+ },
guessInput: {
value: '',
isShaking: false,
- },
+ }
};
-
+};
+
+
+// IMPURE
+window.onload = () => {
+ const initialState = reset();
setState(initialState);
-}
+};