- {(state.mode === "test" || state.mode === "intro") &&
}
-
- {state.mode === "test"
- ?
- : state.mode === "practice" ?
- :
}
-
- {state.mode === "test" && dispatch({ type: "timeout" })}
- />}
- {state.mode !== "intro" && }
-
-
-
- {state.justStruck &&
- {getStrikeMessage()}
-
}
-
-
-
- {state.mode === "intro" &&
-
- {/* TODO: ADD IN TEXT DISPLAY OPTIONS HERE TOO - WHEN WE START USING THEM*/}
-
-
-
-
}
- {gameRunning &&
dispatch({ type: "handle question response", payload: { correct }})}
- />}
- {(state.mode === "practice" && (state.justStruck || state.showAnswer)) &&
-
-
}
- {(state.showAnswer && state.mode === "practice") &&
-
-
-
-
-
}
- {state.mode === "complete" &&
-
- 🎉 Finished!
-
-
- }
- {(state.mode === "timeout" || state.mode === "fail") &&
-
{failMessage({
- numberComplete: state.numberComplete,
- amount,
- type: state.mode,
- })}
-
The correct answer was:
-
-
-
-
-
}
-
-
+ if (action.type === "timeout") {
+ logGameEvent("timeout");
+ handleResult(false);
+ return {
+ ...gs,
+ mode: "timeout",
+ justStruck: false,
+ showAnswer: false,
+ };
+ }
+ if (action.type === "toggle show answer") {
+ if (gs.mode === "practice") {
+ return {
+ ...gs,
+ justStruck: false,
+ showAnswer: !gs.showAnswer,
+ };
+ }
+ return gs;
+ }
+ if (action.type === "skip") {
+ if (gs.mode === "practice") {
+ return {
+ ...gs,
+ current: getQuestion(),
+ justStruck: false,
+ showAnswer: false,
+ };
+ }
+ return gs;
+ }
+ throw new Error("unknown GameReducerAction");
+ };
+
+ function dispatch(action: GameReducerAction) {
+ setStateDangerous((gs) => gameReducer(gs, action));
+ }
+
+ function logGameEvent(action: string) {
+ if (isProd && !user?.admin) {
+ ReactGA.event({
+ category: "Game",
+ action: `${action} - ${id}`,
+ label: id,
+ });
+ }
+ }
+ function punish() {
+ if (navigator.vibrate) {
+ navigator.vibrate(errorVibration);
+ }
+ }
+ function handleResult(done: boolean) {
+ const result: AT.TestResult = {
+ done,
+ time: getTimestamp(),
+ id,
+ };
+ // add the test to the user object
+ if (!user) return;
+ setUser((u) => {
+ // pure type safety with the prevUser
+ if (!u) return u;
+ return {
+ ...u,
+ tests: [...u.tests, result],
+ };
+ });
+ // save the test result in local storage
+ saveResult(result, user.userId);
+ // try to post the result
+ postSavedResults(user.userId)
+ .then((r) => {
+ if (r === "sent") pullUser();
+ })
+ .catch(console.error);
+ }
+ function getProgressWidth(): string {
+ const num = !state.current
+ ? 0
+ : state.mode === "complete"
+ ? 100
+ : getPercentageDone(state.numberComplete, amount);
+ return `${num}%`;
+ }
+ const progressColor =
+ state.mode === "complete"
+ ? "success"
+ : state.mode === "fail" || state.mode === "timeout"
+ ? "danger"
+ : "primary";
+ const gameRunning = state.mode === "practice" || state.mode === "test";
+ function ActionButtons() {
+ return (
+
+ {!inChapter && (
+
+
+
+ )}
+
+
+
+ );
+ }
+ return (
+ <>
+
+ {(state.mode === "test" || state.mode === "intro") && (
+
+ )}
+
+ {state.mode === "test" ? (
+
+ ) : state.mode === "practice" ? (
+
+ ) : (
+
+ )}
+
+ {state.mode === "test" && (
+ dispatch({ type: "timeout" })}
+ />
+ )}
+ {state.mode !== "intro" && (
+
+ )}
+
- {gameRunning &&
+ {state.justStruck && (
+
+ {getStrikeMessage()}
+
+ )}
+
+
+
+ {state.mode === "intro" && (
+
+
+ {/* TODO: ADD IN TEXT DISPLAY OPTIONS HERE TOO - WHEN WE START USING THEM*/}
+
+
+
+
+ )}
+ {gameRunning && (
+
+ dispatch({
+ type: "handle question response",
+ payload: { correct },
+ })
+ }
+ />
+ )}
+ {state.mode === "practice" &&
+ (state.justStruck || state.showAnswer) && (
+
+
+
+ )}
+ {state.showAnswer && state.mode === "practice" && (
+
+
+
+
+
+
+ )}
+ {state.mode === "complete" && (
+
+
+
+ 🎉
+ {" "}
+ Finished!
+
+
+
+ )}
+ {(state.mode === "timeout" || state.mode === "fail") && (
+
+
+ {failMessage({
+ numberComplete: state.numberComplete,
+ amount,
+ type: state.mode,
+ })}
+
+
The correct answer was:
+
+
+
+
+
+ )}
+
+
+
+ {gameRunning && (
+
({ inChapter, getQuestion, amount, Display, DisplayCo
width: "100%",
height: "100%",
zIndex: 6,
- }}>
}
- >;
+ }}
+ >
+ )}
+ >
+ );
}
-function PracticeStatusDisplay({ correct, incorrect }: { correct: number, incorrect: number }) {
- return
-
✅ Correct: {correct}
-
❌ Incorrect: {incorrect}
+function PracticeStatusDisplay({
+ correct,
+ incorrect,
+}: {
+ correct: number;
+ incorrect: number;
+}) {
+ return (
+
+
+ ✅ Correct: {correct}
+
+
+ ❌ Incorrect: {incorrect}
+
+ );
}
function StrikesDisplay({ strikes }: { strikes: number }) {
- return
- {[...Array(strikes)].map(_ => ❌)}
-
;
+ return (
+
+ {[...Array(strikes)].map((_) => (
+
+ ❌
+
+ ))}
+
+ );
}
function getStrikeMessage() {
- return randFromArray([
- "Not quite! Try again.",
- "No sorry, try again",
- "Umm, no, try again",
- "Try again",
- "Oooooooo, sorry no...",
- ]);
+ return randFromArray([
+ "Not quite! Try again.",
+ "No sorry, try again",
+ "Umm, no, try again",
+ "Try again",
+ "Oooooooo, sorry no...",
+ ]);
}
-function failMessage({ numberComplete, amount, type }: {
- numberComplete: number,
- amount: number,
- type: "timeout" | "fail",
+function failMessage({
+ numberComplete,
+ amount,
+ type,
+}: {
+ numberComplete: number;
+ amount: number;
+ type: "timeout" | "fail";
}): string {
- const pDone = getPercentageDone(numberComplete, amount);
- const { message, face } = pDone < 20
- ? { message: "No, sorry", face: "😑" }
- : pDone < 30
- ? { message: "Oops, that's wrong", face: "😟" }
- : pDone < 55
- ? { message: "Fail", face: "😕" }
- : pDone < 78
- ? { message: "You almost got it!", face: "😩" }
- : { message: "Nooo! So close!", face: "😭" };
- return type === "fail"
- ? `${message} ${face}`
- : `⏳ Time's Up ${face}`;
+ const pDone = getPercentageDone(numberComplete, amount);
+ const { message, face } =
+ pDone < 20
+ ? { message: "No, sorry", face: "😑" }
+ : pDone < 30
+ ? { message: "Oops, that's wrong", face: "😟" }
+ : pDone < 55
+ ? { message: "Fail", face: "😕" }
+ : pDone < 78
+ ? { message: "You almost got it!", face: "😩" }
+ : { message: "Nooo! So close!", face: "😭" };
+ return type === "fail" ? `${message} ${face}` : `⏳ Time's Up ${face}`;
}
-export default GameCore;
\ No newline at end of file
+export default GameCore;
diff --git a/w-grammar.txt b/w-grammar.txt
new file mode 100644
index 0000000..c940dec
--- /dev/null
+++ b/w-grammar.txt
@@ -0,0 +1,29 @@
+Metaproductions
+
+PERSON :: 0 .. 11
+
+Hyper-rules
+
+s ()
+ => es
+ => vs
+
+es (subj: PERSON)
+ => np(subj), adj(subj), eq(subj)
+es (subj: PERSON, pred: PERSON)
+ => np(subj), np(pred), eq(pred)
+
+vs ()
+ => vs-intrans
+ => vs-trans-past
+ => vs-trans-non-past
+
+vs-trans-non-past (subj: PERSON, obj: PERSON)
+ => np(subj), np(obj), v-trans-non-past(subj, obj)
+ => np(obj), np(subj), v-trans-non-past(subj, obj)
+
+vs-trans-past (subj: PERSON, obj: PERSON)
+ => np(subj), np(obj), v-trans-past(obj, obj)
+ => np(obj), np(subj), v-trans-past(obj, obj)
+
+vs-intrans-past (subj: PERSON) => np(subj), v-intrans(subj)
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index e77e13d..d8e67de 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4523,10 +4523,10 @@ react-fast-compare@^3.0.1:
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb"
integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==
-react-ga@3.3.0:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/react-ga/-/react-ga-3.3.0.tgz#c91f407198adcb3b49e2bc5c12b3fe460039b3ca"
- integrity sha512-o8RScHj6Lb8cwy3GMrVH6NJvL+y0zpJvKtc0+wmH7Bt23rszJmnqEQxRbyrqUzk9DTJIHoP42bfO5rswC9SWBQ==
+react-ga4@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/react-ga4/-/react-ga4-2.1.0.tgz#56601f59d95c08466ebd6edfbf8dede55c4678f9"
+ integrity sha512-ZKS7PGNFqqMd3PJ6+C2Jtz/o1iU9ggiy8Y8nUeksgVuvNISbmrQtJiZNvC/TjDsqD0QlU5Wkgs7i+w9+OjHhhQ==
react-is@^16.13.1, react-is@^16.3.2, react-is@^16.7.0:
version "16.13.1"