summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsanine-a <sanine.not@pm.me>2021-04-16 12:18:00 -0500
committersanine-a <sanine.not@pm.me>2021-04-16 12:18:00 -0500
commit897d1fe760f1ea25b8dd802f152d577a396af665 (patch)
tree875e345953420f2f16e09499974fe34a89fa36e0
parent9207e74f3af48a7a0c76188401c7470c0331ce3e (diff)
begin functional refactor
-rw-r--r--App.js331
-rw-r--r--index.html6
2 files changed, 84 insertions, 253 deletions
diff --git a/App.js b/App.js
index d7dc14b..7b7a22c 100644
--- a/App.js
+++ b/App.js
@@ -1,277 +1,112 @@
-const levels = [];
-const LEVEL_SIZE = 20;
-
-for (let i=0; (LEVEL_SIZE*i) < characters.length; i++) {
- let start = (20*i) + 1;
- let end = 20 * (i+1);
- end = end > characters.length ? characters.length-1 : end;
-
- levels.push(`Level ${i+1} (${start} - ${end})`);
-}
-
-
-const gameModes = [
- 'Only Level Characters',
- 'Level + Previous Four Levels',
- 'All Characters up to Level',
-];
-
-const GAMEMODE_LEVEL_ONLY = 0;
-const GAMEMODE_PREV_LEVELS = 1;
-const GAMEMODE_ALL_TO_LEVEL = 2;
-
-
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-let state = {
- level: 0,
- gameMode: GAMEMODE_LEVEL_ONLY,
- paused: false,
-
- levelCharacters: [],
- index: 0,
-
- character: '你',
- pinyin: 'ni3',
-
- guessHistory: [],
- numGuesses: 0,
- correctGuesses: 0,
-
- hintLevel: 0,
-
- inputValue: undefined,
- inputShaking: false,
-};
-
-
-function setState(update)
-{
- for (const key in update)
- state[key] = update[key];
-
- render();
-}
+'use strict';
+const h = Inferno.h;
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+const GlobalState = {};
-const App = function()
-{
- const {
- levelCharacters, time,
- level, gameMode,
- character, pinyin,
- numGuesses, correctGuesses,
- hintLevel,
- inputValue, inputShaking
- } = state;
-
- return h(
- 'div', {},
- [
- h(ScoreView,
- { level: level,
- numCharacters: levelCharacters.length,
- guesses: numGuesses,
- correctGuesses,
- time,
- }),
-
- h('h1', {}, character),
-
- h(InputBox,
- { value: inputValue,
- shaking: inputShaking,
- handleKeyDown: handleInputKeyDown,
- }),
-
- h('br'),
-
- h(HintButton,
- {
- answer: pinyin,
- hintLevel,
- handleClick: () => setState({ hintLevel: hintLevel+1 }),
- }),
-
- h('br'),
-
- h(StyleDropdown,
- { options: levels,
- index: level,
- defaultText: 'Select a Level',
- onChoose: (index) => {
- setState({ level: index });
- reset();
- },
- }),
+// IMPURE
+const updateState = (state, update) => Object.keys(update).forEach(
+ key => {
+ if (typeof(state[key]) === 'object')
+ updateState(state[key], update[key]);
+ else
+ state[key] = update[key];
+ });
- h(StyleDropdown,
- { options: gameModes,
- index: gameMode,
- defaultText: 'Select a Game Mode',
- onChoose: (index) => {
- setState({ gameMode: index });
- reset();
- },
- }),
- ]
+// IMPURE
+const setState = update => {
+ updateState(GlobalState, update);
+ Inferno.render(
+ h(App, {state: GlobalState, setState}),
+ document.getElementById('root')
);
}
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-function handleInputKeyDown(event)
-{
- const KEY_ENTER = 13;
-
- if (event.keyCode === KEY_ENTER) {
- makeGuess();
- }
- else {
- setTimeout(() => setState({
- inputValue: event.target.value
- }), 300);
- }
-}
-
-
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * App
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
-function makeGuess()
-{
- const { inputValue, pinyin } = state;
-
- if (inputValue === pinyin)
- correctAnswer();
- else
- shakeInputBox();
-}
+// IMPURE
+const App = ({state, setState}) => {
+ const { guessInput, } = state;
-function correctAnswer()
-{
- setState({
- inputValue: undefined,
- hintLevel: 0,
+ return h(GuessInput, {
+ value: guessInput.value,
+ isShaking: guessInput.isShaking,
+ handleInput: updateStateOnEvent(state, handleGuessInputInput),
+ handleKeyDown: updateStateOnEvent(state, handleGuessInputKeyDown),
});
-}
+};
-function shakeInputBox()
-{
- setState({ inputShaking: true });
- setTimeout(() => setState({ inputShaking: false }), 300);
-}
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * Components
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+const GuessInput = ({value, isShaking, handleInput, handleKeyDown}) => {
+ const inputTag = isShaking ? 'input.shaking' : 'input';
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ return h(inputTag, {
+ type: 'text',
+ value,
+ onInput: handleInput,
+ onKeyDown: handleKeyDown,
+ });
+};
-// fisher-yates shuffle
-function shuffledArray(arr)
-{
- const shuffled = [...arr];
- for (let i=arr.length-1; i>0; i--) {
- const j = Math.floor(Math.random() * i);
- let tmp = shuffled[j];
- shuffled[j] = shuffled[i];
- shuffled[i] = tmp;
- }
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * Event Handlers
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
- return shuffled;
-}
+// IMPURE
+const updateStateOnEvent = (state, handler) =>
+ event => setState(handler(state, event));
-function buildLevel(level, levelSize, gameMode, characters)
-{
- let start;
-
- switch (gameMode) {
- case GAMEMODE_LEVEL_ONLY:
- start = levelSize * level;
- break;
+const handleGuessInputInput = (state, event) =>
+ ({ guessInput: { value: event.target.value } });
- case GAMEMODE_PREV_LEVELS:
- start = levelSize * (level - 4);
- break;
- case GAMEMODE_ALL_TO_LEVEL:
- start = 0;
- break;
+const handleGuessInputKeyDown = (state, event) => {
+ const KEYCODE_ENTER = 13;
- default:
- start = 0;
- break;
+ if (event.keyCode === KEYCODE_ENTER) {
+ console.log(state.guessInput.value);
+ return { guessInput: { value: '' } };
}
- start = start < 0 ? 0 : start;
-
- let end = levelSize * (level + 1);
+ return {};
+};
- const levelCharacters = [];
- for (let i=start; i<end; i++)
- levelCharacters.push(characters[i]);
- return shuffledArray(levelCharacters);
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * Document load
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+// IMPURE
+window.onload = () => {
+ const initialState = {
+ guessInput: {
+ value: '',
+ isShaking: false,
+ },
+ };
+
+ setState(initialState);
}
-
-function reset() {
- const { level, gameMode } = state;
-
- const levelCharacters = buildLevel(level, LEVEL_SIZE, gameMode, characters);
-
- const [character, pinyin] = levelCharacters[0];
-
- clearInterval(timeInterval);
- timeInterval = setInterval(() => {
- const { paused, time } = state;
- if (!paused)
- setState({ time: time+1 });
- }, 1000);
-
- setState({
- levelCharacters,
- index: 0,
- paused: false,
- time: 0,
-
- character,
- pinyin,
- guessHistory: [],
- numGuesses: 0,
- correctGuesses: 0,
- hintLevel: 0,
-
- inputValue: undefined,
- inputShaking: false,
- });
-}
-
-
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-let timeInterval;
-
-function ScoreView({ level, numCharacters, guesses, correctGuesses, time })
-{
- const minutes = Math.floor(time/60);
- let seconds = time % 60;
- seconds = seconds < 10 ? '0' + seconds : seconds;
-
-
- const levelName = `Level ${level + 1}`;
- const percentage =
- guesses === 0 ? '100.0' : String(0.1 * Math.floor(1000 * correctGuesses / guesses));
- const score = `${correctGuesses}/${numCharacters} (${percentage}%)`;
-
- return h(
- 'div', {},
- [
- h('h1', {}, `${levelName} - ${minutes}:${seconds}`),
- h('h1', {}, score),
- ]
- );
-}
diff --git a/index.html b/index.html
index 224e992..8ba628b 100644
--- a/index.html
+++ b/index.html
@@ -9,16 +9,12 @@
<script src="https://unpkg.com/inferno-hyperscript@7.4.8/dist/inferno-hyperscript.min.js"></script>
<!-- local scripts -->
- <script src="./main.js"></script>
<script src="./characters.js"></script>
- <script src="./InputBox.js"></script>
- <script src="./StyleButton.js"></script>
- <script src="./HintButton.js"></script>
- <script src="./StyleDropdown.js"></script>
<script src="./App.js"></script>
<!-- styling -->
<link href="./style.css" rel="stylesheet">
+ <!-- -->
</head>
<body>