Game working alright! 💪

This commit is contained in:
lingdocs 2022-04-12 16:05:14 +05:00
parent 0fb73af58b
commit dad93bfa14
5 changed files with 61 additions and 15 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "@lingdocs/pashto-inflector", "name": "@lingdocs/pashto-inflector",
"version": "1.9.0", "version": "1.9.1",
"author": "lingdocs.com", "author": "lingdocs.com",
"description": "A Pashto inflection and verb conjugation engine, inculding React components for displaying Pashto text, inflections, and conjugations", "description": "A Pashto inflection and verb conjugation engine, inculding React components for displaying Pashto text, inflections, and conjugations",
"homepage": "https://verbs.lingdocs.com", "homepage": "https://verbs.lingdocs.com",

View File

@ -11,6 +11,20 @@
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
} }
.answer-feedback {
transition: opacity 0.3s ease-in;
opacity: 0.8;
position: fixed;
top: 50%;
left: 50%;
z-index: 99999999;
transform: translate(-50%, -50%);
}
.hide {
opacity: 0;
}
:root { :root {
--secondary: #00c1fc; --secondary: #00c1fc;
--primary: #ffda54; --primary: #ffda54;

View File

@ -68,10 +68,11 @@ export function getRandomTense(type: "basic" | "modal" | "perfect", o?: T.Perfec
return tns; return tns;
} }
function TensePicker({ onChange, vps, mode }: { function TensePicker({ onChange, vps, mode, locked }: {
vps: T.VPSelectionState, vps: T.VPSelectionState,
onChange: (p: T.VPSelectionState) => void, onChange: (p: T.VPSelectionState) => void,
mode: "charts" | "phrases" | "quiz", mode: "charts" | "phrases" | "quiz",
locked: boolean,
}) { }) {
function onTenseSelect(o: { value: T.VerbTense | T.PerfectTense } | null) { function onTenseSelect(o: { value: T.VerbTense | T.PerfectTense } | null) {
const value = o?.value ? o.value : undefined; const value = o?.value ? o.value : undefined;
@ -179,7 +180,7 @@ function TensePicker({ onChange, vps, mode }: {
options={tOptions} options={tOptions}
{...zIndexProps} {...zIndexProps}
/> />
{vps.verb && <div className="d-flex flex-row justify-content-between align-items-center mt-3 mb-1" style={{ width: "100%" }}> {vps.verb && !locked && <div className="d-flex flex-row justify-content-between align-items-center mt-3 mb-1" style={{ width: "100%" }}>
<div className="btn btn-light clickable" onClick={moveTense("back")}> <div className="btn btn-light clickable" onClick={moveTense("back")}>
<i className="fas fa-chevron-left" /> <i className="fas fa-chevron-left" />
</div> </div>

View File

@ -16,10 +16,13 @@ import { randomSubjObj } from "../../library";
import shuffleArray from "../../lib/shuffle-array"; import shuffleArray from "../../lib/shuffle-array";
import InlinePs from "../InlinePs"; import InlinePs from "../InlinePs";
import { psStringEquals } from "../../lib/p-text-helpers"; import { psStringEquals } from "../../lib/p-text-helpers";
import classNames from "classnames";
import { randFromArray } from "../../lib/misc-helpers";
// import { useReward } from 'react-rewards'; // import { useReward } from 'react-rewards';
const kingEmoji = "👑"; const kingEmoji = "👑";
const servantEmoji = "🙇‍♂️"; const servantEmoji = "🙇‍♂️";
const correctEmoji = ["✅", '🤓', "✅", '😊', "🌹", "✅", "✅", "🕺", "💃", '🥳', "👏", "✅", "💯", "😎", "✅", "👍"];
// TODO: Drill Down text display options // TODO: Drill Down text display options
@ -34,6 +37,8 @@ const servantEmoji = "🙇‍♂️";
// TODO: error handling on error with rendering etc // TODO: error handling on error with rendering etc
const checkDuration = 400;
type QuizState = { type QuizState = {
answer: { answer: {
ps: T.SingleOrLengthOpts<T.PsString[]>; ps: T.SingleOrLengthOpts<T.PsString[]>;
@ -62,18 +67,26 @@ export function VPExplorer(props: {
); );
const [mode, setMode] = useStickyState<"charts" | "phrases" | "quiz">("phrases", "verbExplorerMode"); const [mode, setMode] = useStickyState<"charts" | "phrases" | "quiz">("phrases", "verbExplorerMode");
const [quizState, setQuizState] = useState<QuizState | undefined>(undefined); const [quizState, setQuizState] = useState<QuizState | undefined>(undefined);
const [showCheck, setShowCheck] = useState<boolean>(false);
const [currentCorrectEmoji, setCurrentCorrectEmoji] = useState<string>(randFromArray(correctEmoji));
// const { reward } = useReward('rewardId', "emoji", { // const { reward } = useReward('rewardId', "emoji", {
// emoji: ['🤓', '😊', '🥳', "👏", "💯", "😎", "👍"], // emoji: ['🤓', '😊', '🥳', "👏", "💯", "😎", "👍"],
// lifetime: 50, // lifetime: 50,
// elementCount: 10, // elementCount: 10,
// elementSize: 30, // elementSize: 30,
// }); // });
useEffect(() => {
if (mode === "quiz") {
handleResetQuiz();
}
// eslint-disable-next-line
}, []);
useEffect(() => { useEffect(() => {
setVps(o => { setVps(o => {
if (mode === "quiz") { if (mode === "quiz") {
return getRandomVPSelection("both")( const { VPS, qs } = makeQuizState(vps);
makeVPSelectionState(props.verb, o) setQuizState(qs);
); return VPS;
} }
return makeVPSelectionState(props.verb, o); return makeVPSelectionState(props.verb, o);
}); });
@ -130,8 +143,17 @@ export function VPExplorer(props: {
function checkQuizAnswer(a: T.PsString) { function checkQuizAnswer(a: T.PsString) {
if (!quizState) return; if (!quizState) return;
if (isInAnswer(a, quizState.answer)) { if (isInAnswer(a, quizState.answer)) {
// reward(); setShowCheck(true);
handleResetQuiz(); setTimeout(() => {
handleResetQuiz();
}, checkDuration / 2);
setTimeout(() => {
setShowCheck(false);
}, checkDuration);
// this sucks, have to do this so the emoji doesn't change in the middle of animation
setTimeout(() => {
setCurrentCorrectEmoji(randFromArray(correctEmoji));
}, checkDuration * 2);
} else { } else {
setQuizState({ setQuizState({
...quizState, ...quizState,
@ -219,6 +241,7 @@ export function VPExplorer(props: {
vps={vps} vps={vps}
onChange={quizLock(setVps)} onChange={quizLock(setVps)}
mode={mode} mode={mode}
locked={!!(mode === "quiz" && quizState)}
/> />
</div> </div>
</div> </div>
@ -228,10 +251,15 @@ export function VPExplorer(props: {
{(vps.verb && (mode === "charts")) && <ChartDisplay VS={vps.verb} opts={props.opts} />} {(vps.verb && (mode === "charts")) && <ChartDisplay VS={vps.verb} opts={props.opts} />}
<span id="rewardId" /> <span id="rewardId" />
{(mode === "quiz" && quizState) && <div className="text-center"> {(mode === "quiz" && quizState) && <div className="text-center">
<div style={{ fontSize: "4rem" }} className={classNames("answer-feedback", { hide: !showCheck })}>
{currentCorrectEmoji}
</div>
{quizState.result === "waiting" ? <> {quizState.result === "waiting" ? <>
<div className="text-muted my-3">Choose a correct answer:</div> <div className="text-muted my-3">Choose a correct answer:</div>
{quizState.options.map(o => <div className="pb-3"> {quizState.options.map(o => <div className="pb-3" key={o.f}>
<div className="btn btn-outline-secondary" onClick={() => checkQuizAnswer(o)}> <div className="btn btn-answer btn-outline-secondary" onClick={() => {
checkQuizAnswer(o);
}}>
<InlinePs opts={props.opts}>{o}</InlinePs> <InlinePs opts={props.opts}>{o}</InlinePs>
</div> </div>
</div>)} </div>)}
@ -248,9 +276,6 @@ export function VPExplorer(props: {
</div> </div>
</div>} </div>}
</div>} </div>}
{mode === "quiz" && <div style={{ height: "300px" }}>
{/* spacer for blank space while quizzing */}
</div>}
</div> </div>
} }
@ -398,7 +423,7 @@ function getRandomVPSelection(mix: MixType = "both") {
}; };
return { return {
subject: s, subject: s,
verb: mix === "both" ? randomizeTense(v, false) : v, verb: randomizeTense(v, true),
}; };
}; };
}; };

View File

@ -152,6 +152,12 @@ export function randomNumber(minInclusive: number, maxExclusive: number): number
return Math.floor(Math.random() * (maxExclusive - minInclusive) + minInclusive); return Math.floor(Math.random() * (maxExclusive - minInclusive) + minInclusive);
} }
export function randFromArray<M>(arr: M[]): M {
return arr[
Math.floor(Math.random()*arr.length)
];
}
// TODO: deprecate this because we have it in np-tools? // TODO: deprecate this because we have it in np-tools?
/** /**
* Sees if a possiblePerson (for subject/object) is possible, given the other person * Sees if a possiblePerson (for subject/object) is possible, given the other person