verb formulas game
This commit is contained in:
parent
6eab368245
commit
b0e1789914
|
@ -4,6 +4,7 @@ title: Verb Forms Master Chart
|
||||||
|
|
||||||
import { Camera, Video } from "../../components/terms-links";
|
import { Camera, Video } from "../../components/terms-links";
|
||||||
import Link from "../../components/Link";
|
import Link from "../../components/Link";
|
||||||
|
import GameDisplay from "../../games/GameDisplay";
|
||||||
|
|
||||||
## Basic Verb Tenses
|
## Basic Verb Tenses
|
||||||
|
|
||||||
|
|
|
@ -9,20 +9,22 @@ import {
|
||||||
import { makePool } from "../../lib/pool";
|
import { makePool } from "../../lib/pool";
|
||||||
import { CSSProperties, useEffect, useState } from "react";
|
import { CSSProperties, useEffect, useState } from "react";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
import { isImperativeTense } from "@lingdocs/pashto-inflector/dist/lib/type-predicates";
|
||||||
|
|
||||||
const amount = 10;
|
const amount = 12;
|
||||||
const timeLimit = 60;
|
const timeLimit = 125;
|
||||||
|
|
||||||
type StemRoot = "imperfective stem" | "perfective stem" | "imperfective root" | "perfective root";
|
type StemRoot = "imperfective stem" | "perfective stem" | "imperfective root" | "perfective root";
|
||||||
type Ending = "present" | "past" | "imperative";
|
type Ending = "present" | "past" | "imperative";
|
||||||
type Formula = {
|
type Formula = {
|
||||||
ba: boolean,
|
ba: boolean,
|
||||||
|
mu: boolean,
|
||||||
stemRoot: StemRoot,
|
stemRoot: StemRoot,
|
||||||
ending: Ending,
|
ending: Ending,
|
||||||
};
|
};
|
||||||
|
|
||||||
type Question = {
|
type Question = {
|
||||||
tense: T.VerbTense,
|
tense: T.VerbTense | T.ImperativeTense | "negative imperative",
|
||||||
formula: Formula,
|
formula: Formula,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +33,7 @@ const questions: Question[] = [
|
||||||
tense: "presentVerb",
|
tense: "presentVerb",
|
||||||
formula: {
|
formula: {
|
||||||
ba: false,
|
ba: false,
|
||||||
|
mu: false,
|
||||||
stemRoot: "imperfective stem",
|
stemRoot: "imperfective stem",
|
||||||
ending: "present",
|
ending: "present",
|
||||||
},
|
},
|
||||||
|
@ -39,6 +42,7 @@ const questions: Question[] = [
|
||||||
tense: "subjunctiveVerb",
|
tense: "subjunctiveVerb",
|
||||||
formula: {
|
formula: {
|
||||||
ba: false,
|
ba: false,
|
||||||
|
mu: false,
|
||||||
stemRoot: "perfective stem",
|
stemRoot: "perfective stem",
|
||||||
ending: "present",
|
ending: "present",
|
||||||
},
|
},
|
||||||
|
@ -47,6 +51,7 @@ const questions: Question[] = [
|
||||||
tense: "imperfectiveFuture",
|
tense: "imperfectiveFuture",
|
||||||
formula: {
|
formula: {
|
||||||
ba: true,
|
ba: true,
|
||||||
|
mu: false,
|
||||||
stemRoot: "imperfective stem",
|
stemRoot: "imperfective stem",
|
||||||
ending: "present",
|
ending: "present",
|
||||||
},
|
},
|
||||||
|
@ -55,6 +60,7 @@ const questions: Question[] = [
|
||||||
tense: "perfectiveFuture",
|
tense: "perfectiveFuture",
|
||||||
formula: {
|
formula: {
|
||||||
ba: true,
|
ba: true,
|
||||||
|
mu: false,
|
||||||
stemRoot: "perfective stem",
|
stemRoot: "perfective stem",
|
||||||
ending: "present",
|
ending: "present",
|
||||||
},
|
},
|
||||||
|
@ -63,6 +69,7 @@ const questions: Question[] = [
|
||||||
tense: "imperfectivePast",
|
tense: "imperfectivePast",
|
||||||
formula: {
|
formula: {
|
||||||
ba: false,
|
ba: false,
|
||||||
|
mu: false,
|
||||||
stemRoot: "imperfective root",
|
stemRoot: "imperfective root",
|
||||||
ending: "past",
|
ending: "past",
|
||||||
},
|
},
|
||||||
|
@ -71,6 +78,7 @@ const questions: Question[] = [
|
||||||
tense: "perfectivePast",
|
tense: "perfectivePast",
|
||||||
formula: {
|
formula: {
|
||||||
ba: false,
|
ba: false,
|
||||||
|
mu: false,
|
||||||
stemRoot: "perfective root",
|
stemRoot: "perfective root",
|
||||||
ending: "past",
|
ending: "past",
|
||||||
},
|
},
|
||||||
|
@ -79,6 +87,7 @@ const questions: Question[] = [
|
||||||
tense: "habitualImperfectivePast",
|
tense: "habitualImperfectivePast",
|
||||||
formula: {
|
formula: {
|
||||||
ba: true,
|
ba: true,
|
||||||
|
mu: false,
|
||||||
stemRoot: "imperfective root",
|
stemRoot: "imperfective root",
|
||||||
ending: "past",
|
ending: "past",
|
||||||
},
|
},
|
||||||
|
@ -87,10 +96,38 @@ const questions: Question[] = [
|
||||||
tense: "habitualPerfectivePast",
|
tense: "habitualPerfectivePast",
|
||||||
formula: {
|
formula: {
|
||||||
ba: true,
|
ba: true,
|
||||||
|
mu: false,
|
||||||
stemRoot: "perfective root",
|
stemRoot: "perfective root",
|
||||||
ending: "past",
|
ending: "past",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
tense: "perfectiveImperative",
|
||||||
|
formula: {
|
||||||
|
ba: false,
|
||||||
|
mu: false,
|
||||||
|
stemRoot: "perfective stem",
|
||||||
|
ending: "imperative",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tense: "imperfectiveImperative",
|
||||||
|
formula: {
|
||||||
|
ba: false,
|
||||||
|
mu: false,
|
||||||
|
stemRoot: "imperfective stem",
|
||||||
|
ending: "imperative",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tense: "negative imperative",
|
||||||
|
formula: {
|
||||||
|
ba: false,
|
||||||
|
mu: true,
|
||||||
|
stemRoot: "imperfective stem",
|
||||||
|
ending: "imperative",
|
||||||
|
},
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function VerbFormulas({ inChapter, id, link, level }: { inChapter: boolean, id: string, link: string, level: "all" }) {
|
export default function VerbFormulas({ inChapter, id, link, level }: { inChapter: boolean, id: string, link: string, level: "all" }) {
|
||||||
|
@ -101,7 +138,6 @@ export default function VerbFormulas({ inChapter, id, link, level }: { inChapter
|
||||||
function Instructions() {
|
function Instructions() {
|
||||||
return <p className="lead">Pick the formula for each verb tense</p>;
|
return <p className="lead">Pick the formula for each verb tense</p>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <GameCore
|
return <GameCore
|
||||||
inChapter={inChapter}
|
inChapter={inChapter}
|
||||||
studyLink={link}
|
studyLink={link}
|
||||||
|
@ -117,19 +153,24 @@ export default function VerbFormulas({ inChapter, id, link, level }: { inChapter
|
||||||
|
|
||||||
function Display({ question, callback }: QuestionDisplayProps<Question>) {
|
function Display({ question, callback }: QuestionDisplayProps<Question>) {
|
||||||
const [ba, setBa] = useState<boolean>(false);
|
const [ba, setBa] = useState<boolean>(false);
|
||||||
|
const [mu, setMu] = useState<boolean>(false);
|
||||||
const [stemRoot, setStemRoot] = useState<StemRoot | "">("");
|
const [stemRoot, setStemRoot] = useState<StemRoot | "">("");
|
||||||
const [ending, setEnding] = useState<Ending | "">("");
|
const [ending, setEnding] = useState<Ending | "">("");
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setBa(false);
|
setBa(false);
|
||||||
setStemRoot("");
|
setStemRoot("");
|
||||||
setEnding("");
|
setEnding("");
|
||||||
|
setMu(false);
|
||||||
}, [question]);
|
}, [question]);
|
||||||
const canSubmit = !!(stemRoot && ending);
|
const canSubmit = !!(stemRoot && ending);
|
||||||
|
const showMu = question.tense === "negative imperative" || isImperativeTense(question.tense);
|
||||||
function handleSubmit() {
|
function handleSubmit() {
|
||||||
const { formula } = question;
|
const { formula } = question;
|
||||||
callback(
|
callback(
|
||||||
(ba === formula.ba)
|
(ba === formula.ba)
|
||||||
&&
|
&&
|
||||||
|
(mu === formula.mu)
|
||||||
|
&&
|
||||||
(stemRoot === formula.stemRoot)
|
(stemRoot === formula.stemRoot)
|
||||||
&&
|
&&
|
||||||
(ending === formula.ending)
|
(ending === formula.ending)
|
||||||
|
@ -138,13 +179,14 @@ function Display({ question, callback }: QuestionDisplayProps<Question>) {
|
||||||
return <div>
|
return <div>
|
||||||
<div className="my-4" style={{ maxWidth: "300px", margin: "0 auto" }}>
|
<div className="my-4" style={{ maxWidth: "300px", margin: "0 auto" }}>
|
||||||
<p className="lead">
|
<p className="lead">
|
||||||
{humanReadableVerbForm(question.tense)}
|
{humanReadableT(question.tense)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-center mb-2">
|
<div className="text-center mb-2">
|
||||||
<BaPicker hasBa={ba} onChange={setBa} />
|
<BaPicker value={ba} onChange={setBa} />
|
||||||
<RootsAndStemsPicker stemRoot={stemRoot} onChange={setStemRoot} />
|
{showMu && <MuPicker value={mu} onChange={setMu} />}
|
||||||
<EndingPicker ending={ending} onChange={setEnding} />
|
<RootsAndStemsPicker value={stemRoot} onChange={setStemRoot} />
|
||||||
|
<EndingPicker value={ending} onChange={setEnding} />
|
||||||
<button
|
<button
|
||||||
className="btn btn-primary my-2"
|
className="btn btn-primary my-2"
|
||||||
disabled={!canSubmit}
|
disabled={!canSubmit}
|
||||||
|
@ -153,12 +195,30 @@ function Display({ question, callback }: QuestionDisplayProps<Question>) {
|
||||||
Submit
|
Submit
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<samp>{canSubmit ? printFormula({ ba, stemRoot, ending }) : " "}</samp>
|
<samp>{printFormula({ ba, stemRoot, ending, mu })}</samp>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
function printFormula(f: Formula): string {
|
function humanReadableT(tense: T.VerbTense | T.ImperativeTense | "negative imperative"): string {
|
||||||
return `${f.ba ? "ba + " : ""}${f.stemRoot} + ${f.ending} ending`;
|
if (tense === "negative imperative") {
|
||||||
|
return tense;
|
||||||
|
}
|
||||||
|
return humanReadableVerbForm(tense);
|
||||||
|
}
|
||||||
|
|
||||||
|
function printFormula({ mu, ba, stemRoot, ending }: {
|
||||||
|
mu: boolean,
|
||||||
|
ba: boolean,
|
||||||
|
stemRoot: StemRoot | "",
|
||||||
|
ending: Ending | "",
|
||||||
|
}): string {
|
||||||
|
const elements = [
|
||||||
|
mu ? "mu" : undefined,
|
||||||
|
ba ? "ba" : undefined,
|
||||||
|
stemRoot,
|
||||||
|
ending ? `${ending} ending` : undefined,
|
||||||
|
].filter(x => x) as string[];
|
||||||
|
return elements.join(" + ");
|
||||||
}
|
}
|
||||||
|
|
||||||
function DisplayCorrectAnswer({ question }: { question: Question }): JSX.Element {
|
function DisplayCorrectAnswer({ question }: { question: Question }): JSX.Element {
|
||||||
|
@ -167,7 +227,7 @@ function DisplayCorrectAnswer({ question }: { question: Question }): JSX.Element
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function EndingPicker({ onChange, ending }: { ending: Ending | "", onChange: (e: Ending | "") => void }) {
|
function EndingPicker({ onChange, value }: { value: Ending | "", onChange: (e: Ending | "") => void }) {
|
||||||
const options: { label: string, value: Ending }[] = [
|
const options: { label: string, value: Ending }[] = [
|
||||||
{ label: "Present", value: "present" },
|
{ label: "Present", value: "present" },
|
||||||
{ label: "Past", value: "past" },
|
{ label: "Past", value: "past" },
|
||||||
|
@ -187,7 +247,7 @@ function EndingPicker({ onChange, ending }: { ending: Ending | "", onChange: (e:
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"btn",
|
"btn",
|
||||||
"btn-outline-secondary",
|
"btn-outline-secondary",
|
||||||
{ active: ending === option.value },
|
{ active: value === option.value },
|
||||||
)}
|
)}
|
||||||
onClick={() => handleClick(option.value)}
|
onClick={() => handleClick(option.value)}
|
||||||
>
|
>
|
||||||
|
@ -198,13 +258,13 @@ function EndingPicker({ onChange, ending }: { ending: Ending | "", onChange: (e:
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function BaPicker({ onChange, hasBa }: { hasBa: boolean, onChange: (b: boolean) => void }) {
|
function BaPicker({ onChange, value }: { value: boolean, onChange: (b: boolean) => void }) {
|
||||||
return <div className="form-check my-3" style={{ fontSize: "larger" }}>
|
return <div className="form-check my-3" style={{ fontSize: "larger" }}>
|
||||||
<input
|
<input
|
||||||
id="baCheckbox"
|
id="baCheckbox"
|
||||||
className="form-check-input"
|
className="form-check-input"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={hasBa}
|
checked={value}
|
||||||
onChange={e => onChange(e.target.checked)}
|
onChange={e => onChange(e.target.checked)}
|
||||||
/>
|
/>
|
||||||
<label className="form-check-label text-muted" htmlFor="baCheckbox">
|
<label className="form-check-label text-muted" htmlFor="baCheckbox">
|
||||||
|
@ -213,7 +273,22 @@ function BaPicker({ onChange, hasBa }: { hasBa: boolean, onChange: (b: boolean)
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
function RootsAndStemsPicker({ onChange, stemRoot }: { stemRoot: StemRoot | "", onChange: (s: StemRoot | "" ) => void }) {
|
function MuPicker({ onChange, value }: { value: boolean, onChange: (b: boolean) => void }) {
|
||||||
|
return <div className="form-check my-3" style={{ fontSize: "larger" }}>
|
||||||
|
<input
|
||||||
|
id="baCheckbox"
|
||||||
|
className="form-check-input"
|
||||||
|
type="checkbox"
|
||||||
|
checked={value}
|
||||||
|
onChange={e => onChange(e.target.checked)}
|
||||||
|
/>
|
||||||
|
<label className="form-check-label text-muted" htmlFor="baCheckbox">
|
||||||
|
with <InlinePs opts={opts}>{{ p: "مه", f: "mú" }}</InlinePs>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
function RootsAndStemsPicker({ onChange, value }: { value: StemRoot | "", onChange: (s: StemRoot | "" ) => void }) {
|
||||||
const colClass = "col col-md-5 px-0 mb-1";
|
const colClass = "col col-md-5 px-0 mb-1";
|
||||||
const rowClass = "row justify-content-between";
|
const rowClass = "row justify-content-between";
|
||||||
const title: CSSProperties = {
|
const title: CSSProperties = {
|
||||||
|
@ -225,7 +300,7 @@ function RootsAndStemsPicker({ onChange, stemRoot }: { stemRoot: StemRoot | "",
|
||||||
background: "rgba(255, 227, 10, 0.6)",
|
background: "rgba(255, 227, 10, 0.6)",
|
||||||
};
|
};
|
||||||
function handleStemRootClick(s: StemRoot) {
|
function handleStemRootClick(s: StemRoot) {
|
||||||
onChange(stemRoot === s ? "" : s);
|
onChange(value === s ? "" : s);
|
||||||
}
|
}
|
||||||
return <div className="verb-info" style={{
|
return <div className="verb-info" style={{
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
|
@ -254,24 +329,24 @@ function RootsAndStemsPicker({ onChange, stemRoot }: { stemRoot: StemRoot | "",
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={rowClass}>
|
<div className={rowClass}>
|
||||||
<div className={colClass} style={stemRoot === "imperfective stem" ? highlight : {}}>
|
<div className={colClass} style={value === "imperfective stem" ? highlight : {}}>
|
||||||
<div className="clickable" style={title} onClick={() => handleStemRootClick("imperfective stem")}>
|
<div className="clickable" style={title} onClick={() => handleStemRootClick("imperfective stem")}>
|
||||||
<div>Imperfective Stem</div>
|
<div>Imperfective Stem</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={colClass} style={stemRoot === "perfective stem" ? highlight : {}}>
|
<div className={colClass} style={value === "perfective stem" ? highlight : {}}>
|
||||||
<div className="clickable" style={title} onClick={() => handleStemRootClick("perfective stem")}>
|
<div className="clickable" style={title} onClick={() => handleStemRootClick("perfective stem")}>
|
||||||
<div>Perfective Stem</div>
|
<div>Perfective Stem</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={rowClass}>
|
<div className={rowClass}>
|
||||||
<div className={colClass} style={stemRoot === "imperfective root" ? highlight : {}}>
|
<div className={colClass} style={value === "imperfective root" ? highlight : {}}>
|
||||||
<div className="clickable" style={title} onClick={() => handleStemRootClick("imperfective root")}>
|
<div className="clickable" style={title} onClick={() => handleStemRootClick("imperfective root")}>
|
||||||
<div>Imperfective Root</div>
|
<div>Imperfective Root</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={colClass} style={stemRoot === "perfective root" ? highlight : {}}>
|
<div className={colClass} style={value === "perfective root" ? highlight : {}}>
|
||||||
<div>
|
<div>
|
||||||
<div className="clickable" style={title} onClick={() => handleStemRootClick("perfective root")}>
|
<div className="clickable" style={title} onClick={() => handleStemRootClick("perfective root")}>
|
||||||
<div>Perfective Root</div>
|
<div>Perfective Root</div>
|
||||||
|
|
Loading…
Reference in New Issue