add perfect verb games
This commit is contained in:
parent
65339221ea
commit
9957e5b024
|
@ -18,7 +18,11 @@ import BasicVerbShowCase from "../../components/BasicVerbShowCase";
|
||||||
import perfectDogMeme from "./perfect-dog-meme.jpg";
|
import perfectDogMeme from "./perfect-dog-meme.jpg";
|
||||||
import chemistryPerfect from "./chemistry-perfect.jpg";
|
import chemistryPerfect from "./chemistry-perfect.jpg";
|
||||||
import BasicBlocks from "../../components/BasicBlocks";
|
import BasicBlocks from "../../components/BasicBlocks";
|
||||||
|
import GameDisplay from "../../games/GameDisplay";
|
||||||
|
import {
|
||||||
|
perfectGameOne,
|
||||||
|
perfectGameMix,
|
||||||
|
} from "../../games/games";
|
||||||
|
|
||||||
In the previous chapter we explained how [perfect](https://en.wikipedia.org/wiki/Perfect_(grammar)) forms are made by combining the <Link to="/verbs/roots-and-stems/#the-past-participle">past participle</Link> of a verb with an equative.
|
In the previous chapter we explained how [perfect](https://en.wikipedia.org/wiki/Perfect_(grammar)) forms are made by combining the <Link to="/verbs/roots-and-stems/#the-past-participle">past participle</Link> of a verb with an equative.
|
||||||
|
|
||||||
|
@ -317,3 +321,7 @@ Just like the <Link to="/equatives/other-equatives/#would-have-been-equative">"w
|
||||||
e: "Ah, you (f.) should have come!",
|
e: "Ah, you (f.) should have come!",
|
||||||
},
|
},
|
||||||
])}</Examples>
|
])}</Examples>
|
||||||
|
|
||||||
|
<GameDisplay record={perfectGameOne} />
|
||||||
|
|
||||||
|
<GameDisplay record={perfectGameMix} />
|
||||||
|
|
|
@ -20,6 +20,12 @@ import presentPerfect from "./present-perfect.svg";
|
||||||
import chemistryPerfect from "./chemistry-perfect.jpg";
|
import chemistryPerfect from "./chemistry-perfect.jpg";
|
||||||
import BasicBlocks from "../../components/BasicBlocks";
|
import BasicBlocks from "../../components/BasicBlocks";
|
||||||
import VideoPlayer from "../../components/VideoPlayer";
|
import VideoPlayer from "../../components/VideoPlayer";
|
||||||
|
import GameDisplay from "../../games/GameDisplay";
|
||||||
|
import {
|
||||||
|
intransitivePresentPerfectGameOne,
|
||||||
|
intransitivePresentPerfectGameMix,
|
||||||
|
presentPerfectGame,
|
||||||
|
} from "../../games/games";
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
|
@ -236,6 +242,12 @@ With transitive verbs everything works the same, but we follow the <Link to="/ph
|
||||||
{"blocks":[{"key":0.48107357509198234,"block":{"type":"subjectSelection","selection":{"type":"NP","selection":{"type":"noun","entry":{"ts":1527812881,"i":11710,"p":"ماشوم","f":"maashoom","g":"maashoom","e":"child, kid","c":"n. m. anim. unisex","ec":"child","ep":"children"},"gender":"masc","genderCanChange":true,"number":"plural","numberCanChange":true,"adjectives":[],"possesor":{"np":{"type":"NP","selection":{"type":"pronoun","person":2,"distance":"far"}},"shrunken":false}}}}},{"key":0.8253773159904139,"block":{"type":"objectSelection","selection":{"type":"NP","selection":{"type":"pronoun","person":0,"distance":"far"}}}}],"verb":{"type":"verb","verb":{"entry":{"ts":1527815399,"i":14484,"p":"وهل","f":"wahul","g":"wahul","e":"to hit","c":"v. trans.","tppp":"واهه","tppf":"waahu","ec":"hit,hits,hitting,hit,hit"}},"verbTense":"perfectivePast","perfectTense":"presentPerfect","imperativeTense":"imperfectiveImperative","tenseCategory":"perfect","transitivity":"transitive","isCompound":false,"voice":"active","negative":false,"canChangeTransitivity":false,"canChangeVoice":true,"canChangeStatDyn":false},"form":{"removeKing":false,"shrinkServant":false}}
|
{"blocks":[{"key":0.48107357509198234,"block":{"type":"subjectSelection","selection":{"type":"NP","selection":{"type":"noun","entry":{"ts":1527812881,"i":11710,"p":"ماشوم","f":"maashoom","g":"maashoom","e":"child, kid","c":"n. m. anim. unisex","ec":"child","ep":"children"},"gender":"masc","genderCanChange":true,"number":"plural","numberCanChange":true,"adjectives":[],"possesor":{"np":{"type":"NP","selection":{"type":"pronoun","person":2,"distance":"far"}},"shrunken":false}}}}},{"key":0.8253773159904139,"block":{"type":"objectSelection","selection":{"type":"NP","selection":{"type":"pronoun","person":0,"distance":"far"}}}}],"verb":{"type":"verb","verb":{"entry":{"ts":1527815399,"i":14484,"p":"وهل","f":"wahul","g":"wahul","e":"to hit","c":"v. trans.","tppp":"واهه","tppf":"waahu","ec":"hit,hits,hitting,hit,hit"}},"verbTense":"perfectivePast","perfectTense":"presentPerfect","imperativeTense":"imperfectiveImperative","tenseCategory":"perfect","transitivity":"transitive","isCompound":false,"voice":"active","negative":false,"canChangeTransitivity":false,"canChangeVoice":true,"canChangeStatDyn":false},"form":{"removeKing":false,"shrinkServant":false}}
|
||||||
}</EditableVPEx>
|
}</EditableVPEx>
|
||||||
|
|
||||||
|
<GameDisplay record={intransitivePresentPerfectGameOne} />
|
||||||
|
|
||||||
|
<GameDisplay record={intransitivePresentPerfectGameMix} />
|
||||||
|
|
||||||
|
<GameDisplay record={presentPerfectGame} />
|
||||||
|
|
||||||
## Negatives with the perfect
|
## Negatives with the perfect
|
||||||
|
|
||||||
To make perfect forms negative you add a <InlinePs opts={opts} ps={{ p: "نه", f: "nú", e: "" }} /> block, just as you would with any other verb. But interestingly, **the past participle and equative blocks switch places**.
|
To make perfect forms negative you add a <InlinePs opts={opts} ps={{ p: "نه", f: "nú", e: "" }} /> block, just as you would with any other verb. But interestingly, **the past participle and equative blocks switch places**.
|
||||||
|
|
|
@ -8,6 +8,7 @@ import EquativeIdentify from "./sub-cores/EquativeIdentify";
|
||||||
import VerbFormulas from "./sub-cores/VerbFormulas";
|
import VerbFormulas from "./sub-cores/VerbFormulas";
|
||||||
import InflectionPatterns from "./sub-cores/InflectionPatterns";
|
import InflectionPatterns from "./sub-cores/InflectionPatterns";
|
||||||
import InflectionsWriting from "./sub-cores/InflectionsWriting";
|
import InflectionsWriting from "./sub-cores/InflectionsWriting";
|
||||||
|
import PerfectVerbsIntransitive from "./sub-cores/PerfectGame";
|
||||||
|
|
||||||
|
|
||||||
// NOUNS
|
// NOUNS
|
||||||
|
@ -35,42 +36,42 @@ export const unisexNounGame = makeGameRecord({
|
||||||
|
|
||||||
// INFLECTIONS
|
// INFLECTIONS
|
||||||
export const inflectionTableGame1 = makeGameRecord({
|
export const inflectionTableGame1 = makeGameRecord({
|
||||||
title: `Write the inflections - Pattern #1`,
|
title: "Write the inflections - Pattern #1",
|
||||||
id: "write-inflections-1",
|
id: "write-inflections-1",
|
||||||
link: "/inflection/inflection-patterns/#1-basic",
|
link: "/inflection/inflection-patterns/#1-basic",
|
||||||
level: 1,
|
level: 1,
|
||||||
SubCore: InflectionsWriting,
|
SubCore: InflectionsWriting,
|
||||||
});
|
});
|
||||||
export const inflectionTableGame2 = makeGameRecord({
|
export const inflectionTableGame2 = makeGameRecord({
|
||||||
title: `Write the inflections - Pattern #2`,
|
title: "Write the inflections - Pattern #2",
|
||||||
id: "write-inflections-2",
|
id: "write-inflections-2",
|
||||||
link: "/inflection/inflection-patterns/#2-words-ending-in-an-unstressed-ی---ey",
|
link: "/inflection/inflection-patterns/#2-words-ending-in-an-unstressed-ی---ey",
|
||||||
level: 2,
|
level: 2,
|
||||||
SubCore: InflectionsWriting,
|
SubCore: InflectionsWriting,
|
||||||
});
|
});
|
||||||
export const inflectionTableGame3 = makeGameRecord({
|
export const inflectionTableGame3 = makeGameRecord({
|
||||||
title: `Write the inflections - Pattern #3`,
|
title: "Write the inflections - Pattern #3",
|
||||||
id: "write-inflections-3",
|
id: "write-inflections-3",
|
||||||
link: "/inflection/inflection-patterns/#3-words-ending-in-a-stressed-ی---éy",
|
link: "/inflection/inflection-patterns/#3-words-ending-in-a-stressed-ی---éy",
|
||||||
level: 3,
|
level: 3,
|
||||||
SubCore: InflectionsWriting,
|
SubCore: InflectionsWriting,
|
||||||
});
|
});
|
||||||
export const inflectionTableGame4 = makeGameRecord({
|
export const inflectionTableGame4 = makeGameRecord({
|
||||||
title: `Write the inflections - Pattern #4`,
|
title: "Write the inflections - Pattern #4",
|
||||||
id: "write-inflections-4",
|
id: "write-inflections-4",
|
||||||
link: "/inflection/inflection-patterns/#4-words-with-the-pashtoon-pattern",
|
link: "/inflection/inflection-patterns/#4-words-with-the-pashtoon-pattern",
|
||||||
level: 4,
|
level: 4,
|
||||||
SubCore: InflectionsWriting,
|
SubCore: InflectionsWriting,
|
||||||
});
|
});
|
||||||
export const inflectionTableGame5 = makeGameRecord({
|
export const inflectionTableGame5 = makeGameRecord({
|
||||||
title: `Write the inflections - Pattern #5`,
|
title: "Write the inflections - Pattern #5",
|
||||||
id: "write-inflections-5",
|
id: "write-inflections-5",
|
||||||
link: "/inflection/inflection-patterns/#5-shorter-words-that-squish",
|
link: "/inflection/inflection-patterns/#5-shorter-words-that-squish",
|
||||||
level: 5,
|
level: 5,
|
||||||
SubCore: InflectionsWriting,
|
SubCore: InflectionsWriting,
|
||||||
});
|
});
|
||||||
export const inflectionTableGame6 = makeGameRecord({
|
export const inflectionTableGame6 = makeGameRecord({
|
||||||
title: `Write the inflections - Pattern #6`,
|
title: "Write the inflections - Pattern #6",
|
||||||
id: "write-inflections-6",
|
id: "write-inflections-6",
|
||||||
link: "/inflection/inflection-patterns/#6-inanimate-feminine-nouns-ending-in-ي---ee",
|
link: "/inflection/inflection-patterns/#6-inanimate-feminine-nouns-ending-in-ي---ee",
|
||||||
level: 6,
|
level: 6,
|
||||||
|
@ -340,6 +341,61 @@ export const verbFormulasGame = makeGameRecord({
|
||||||
SubCore: VerbFormulas,
|
SubCore: VerbFormulas,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const intransitivePresentPerfectGameOne = makeGameRecord({
|
||||||
|
title: "Write the present perfect verb - intransitive (one)",
|
||||||
|
id: "present-perfect-intransitive-one",
|
||||||
|
link: "/verbs/perfect-verbs-intro/",
|
||||||
|
level: {
|
||||||
|
level: 1,
|
||||||
|
type: "intransitive",
|
||||||
|
},
|
||||||
|
SubCore: PerfectVerbsIntransitive,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const intransitivePresentPerfectGameMix = makeGameRecord({
|
||||||
|
title: "Write the present perfect verb - intransitive (mix)",
|
||||||
|
id: "present-perfect-intransitive-mix",
|
||||||
|
link: "/verbs/perfect-verbs-intro/",
|
||||||
|
level: {
|
||||||
|
level: 2,
|
||||||
|
type: "intransitive",
|
||||||
|
},
|
||||||
|
SubCore: PerfectVerbsIntransitive,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const presentPerfectGame = makeGameRecord({
|
||||||
|
title: "Write the present perfect verb - transitive/intransitive mix",
|
||||||
|
id: "present-perfect",
|
||||||
|
link: "/verbs/perfect-verbs-intro/",
|
||||||
|
level: {
|
||||||
|
level: 2,
|
||||||
|
type: "transitive-intransitive",
|
||||||
|
},
|
||||||
|
SubCore: PerfectVerbsIntransitive,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const perfectGameOne = makeGameRecord({
|
||||||
|
title: "Write the perfect verb - all perfect tenses (one verb)",
|
||||||
|
id: "all-perfect-one",
|
||||||
|
link: "/verbs/all-perfect-verbs/",
|
||||||
|
level: {
|
||||||
|
level: 1,
|
||||||
|
type: "all-tenses",
|
||||||
|
},
|
||||||
|
SubCore: PerfectVerbsIntransitive,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const perfectGameMix = makeGameRecord({
|
||||||
|
title: "Write the perfect verb - all perfect tenses (mix)",
|
||||||
|
id: "all-perfect-mix",
|
||||||
|
link: "/verbs/all-perfect-verbs/",
|
||||||
|
level: {
|
||||||
|
level: 2,
|
||||||
|
type: "all-tenses",
|
||||||
|
},
|
||||||
|
SubCore: PerfectVerbsIntransitive,
|
||||||
|
});
|
||||||
|
|
||||||
const games: { chapter: string, items: GameRecord[] }[] = [
|
const games: { chapter: string, items: GameRecord[] }[] = [
|
||||||
{
|
{
|
||||||
chapter: "Nouns",
|
chapter: "Nouns",
|
||||||
|
@ -407,6 +463,16 @@ const games: { chapter: string, items: GameRecord[] }[] = [
|
||||||
verbFormulasGame,
|
verbFormulasGame,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
chapter: "Perfect Verbs",
|
||||||
|
items: [
|
||||||
|
intransitivePresentPerfectGameOne,
|
||||||
|
intransitivePresentPerfectGameMix,
|
||||||
|
presentPerfectGame,
|
||||||
|
perfectGameOne,
|
||||||
|
perfectGameMix,
|
||||||
|
],
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// check to make sure we have no duplicate game keys
|
// check to make sure we have no duplicate game keys
|
||||||
|
|
|
@ -0,0 +1,453 @@
|
||||||
|
import { useState } from "react";
|
||||||
|
import {
|
||||||
|
comparePs,
|
||||||
|
} from "../../lib/game-utils";
|
||||||
|
import GameCore from "../GameCore";
|
||||||
|
import {
|
||||||
|
Types as T,
|
||||||
|
defaultTextOptions as opts,
|
||||||
|
makeNounSelection,
|
||||||
|
randFromArray,
|
||||||
|
flattenLengths,
|
||||||
|
randomPerson,
|
||||||
|
InlinePs,
|
||||||
|
grammarUnits,
|
||||||
|
renderVP,
|
||||||
|
makeVPSelectionState,
|
||||||
|
compileVP,
|
||||||
|
blockUtils,
|
||||||
|
concatPsString,
|
||||||
|
isInvalidSubjObjCombo,
|
||||||
|
removeFVarients,
|
||||||
|
getEnglishVerb,
|
||||||
|
RootsAndStems,
|
||||||
|
getVerbInfo,
|
||||||
|
defaultTextOptions,
|
||||||
|
humanReadableVerbForm,
|
||||||
|
blank,
|
||||||
|
kidsBlank,
|
||||||
|
isPashtoScript,
|
||||||
|
} from "@lingdocs/ps-react";
|
||||||
|
import { isPastTense, isThirdPerson } from "@lingdocs/ps-react";
|
||||||
|
import { maybeShuffleArray } from "../../lib/shuffle-array";
|
||||||
|
import { getVerbFromBlocks } from "@lingdocs/ps-react/dist/lib/src/phrase-building/blocks-utils";
|
||||||
|
import { baParticle } from "@lingdocs/ps-react/dist/lib/src/grammar-units";
|
||||||
|
import { intransitivePastVerbs } from "../../content/verbs/basic-present-verbs";
|
||||||
|
import { makePool } from "../../lib/pool";
|
||||||
|
import { wordQuery } from "../../words/words";
|
||||||
|
import { isImperativeTense } from "@lingdocs/ps-react/dist/lib/src/type-predicates";
|
||||||
|
|
||||||
|
const kidsColor = "#017BFE";
|
||||||
|
|
||||||
|
const amount = 12;
|
||||||
|
const timeLimit = 140;
|
||||||
|
|
||||||
|
type Question = {
|
||||||
|
rendered: T.VPRendered,
|
||||||
|
phrase: { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string[] },
|
||||||
|
};
|
||||||
|
|
||||||
|
const transitivePastVerbs = wordQuery("verbs", [
|
||||||
|
"leedul",
|
||||||
|
"wahul",
|
||||||
|
"khoRul",
|
||||||
|
"shărmawul",
|
||||||
|
"pejzandul",
|
||||||
|
"taRul",
|
||||||
|
]);
|
||||||
|
|
||||||
|
const verbs = wordQuery("verbs", [
|
||||||
|
"leekul",
|
||||||
|
"wahul",
|
||||||
|
"leedul",
|
||||||
|
"awredul",
|
||||||
|
"khoRul",
|
||||||
|
"akhistul",
|
||||||
|
"katul",
|
||||||
|
"lwedul",
|
||||||
|
]);
|
||||||
|
|
||||||
|
const nouns = wordQuery("nouns", [
|
||||||
|
"saRey",
|
||||||
|
"xudza",
|
||||||
|
"maashoom",
|
||||||
|
"puxtoon",
|
||||||
|
"Ustaaz",
|
||||||
|
"DaakTar",
|
||||||
|
"halik",
|
||||||
|
]);
|
||||||
|
|
||||||
|
const persons: T.Person[] = [
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||||
|
];
|
||||||
|
|
||||||
|
type PerfectGameLevel = {
|
||||||
|
/* 1 is just a single verb, 2 picks a random verb for every question */
|
||||||
|
level: 1 | 2,
|
||||||
|
type: "intransitive" | "transitive-intransitive" | "all-tenses",
|
||||||
|
}
|
||||||
|
type VerbPoolName = "basic" | "transitivePast" | "intransitivePast" | "mixedPast" | "mixedAll";
|
||||||
|
|
||||||
|
type LevelInfo = {
|
||||||
|
description: string | JSX.Element,
|
||||||
|
tense: T.PerfectTense | "allTenses",
|
||||||
|
pool: VerbPoolName,
|
||||||
|
}
|
||||||
|
|
||||||
|
const levelInfos: Record<PerfectGameLevel["type"], LevelInfo> = {
|
||||||
|
"intransitive": {
|
||||||
|
description: "present perfect form of the verb",
|
||||||
|
tense: "presentPerfect",
|
||||||
|
pool: "intransitivePast",
|
||||||
|
},
|
||||||
|
"transitive-intransitive": {
|
||||||
|
description: "present perfect form of the verb",
|
||||||
|
tense: "presentPerfect",
|
||||||
|
pool: "mixedPast",
|
||||||
|
},
|
||||||
|
"all-tenses": {
|
||||||
|
description: "correct perfect form of the verb",
|
||||||
|
tense: "allTenses",
|
||||||
|
pool: "mixedPast",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Level where you create the formulas (seperate file)
|
||||||
|
// level where you choose the right situation
|
||||||
|
|
||||||
|
const VerbGame: GameSubCore<PerfectGameLevel> = ({ id, link, level, inChapter }: {
|
||||||
|
inChapter: boolean,
|
||||||
|
id: string,
|
||||||
|
link: string,
|
||||||
|
level: PerfectGameLevel,
|
||||||
|
}) => {
|
||||||
|
const levelInfo = levelInfos[level.type];
|
||||||
|
const personPool = makePool(persons);
|
||||||
|
const verbPools: Record<VerbPoolName, () => T.VerbEntry> = {
|
||||||
|
basic: makePool(verbs, 15),
|
||||||
|
transitivePast: makePool(transitivePastVerbs, 15),
|
||||||
|
intransitivePast: makePool(intransitivePastVerbs, 15),
|
||||||
|
mixedPast: makePool([...transitivePastVerbs, ...intransitivePastVerbs], 15),
|
||||||
|
mixedAll: makePool([...verbs, ...transitivePastVerbs, ...intransitivePastVerbs], 15),
|
||||||
|
};
|
||||||
|
const tensePool = makePool<T.PerfectTense>([
|
||||||
|
"presentPerfect", "pastPerfect", "subjunctivePerfect", "habitualPerfect",
|
||||||
|
"pastPerfect", "futurePerfect", "wouldBePerfect", "pastSubjunctivePerfect",
|
||||||
|
"wouldHaveBeenPerfect",
|
||||||
|
]);
|
||||||
|
const oneVerb: T.VerbEntry = verbPools[levelInfo.pool]();
|
||||||
|
const getVerb = level.level === 1
|
||||||
|
? () => oneVerb
|
||||||
|
: () => verbPools[levelInfo.pool]();
|
||||||
|
function makeRandomNoun(): T.NounSelection {
|
||||||
|
const n = makeNounSelection(randFromArray(nouns), undefined);
|
||||||
|
return {
|
||||||
|
...n,
|
||||||
|
gender: n.genderCanChange ? randFromArray(["masc", "fem"]) : n.gender,
|
||||||
|
number: n.numberCanChange ? randFromArray(["singular", "plural"]) : n.number,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function makeRandomVPS(tense: T.PerfectTense): T.VPSelectionComplete {
|
||||||
|
function personToNPSelection(p: T.Person): T.NPSelection {
|
||||||
|
if (isThirdPerson(p)) {
|
||||||
|
return {
|
||||||
|
type: "NP",
|
||||||
|
selection: randFromArray([
|
||||||
|
() => makePronounS(p),
|
||||||
|
makeRandomNoun,
|
||||||
|
() => makePronounS(p),
|
||||||
|
])(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
type: "NP",
|
||||||
|
selection: makePronounS(p),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function makePronounS(p: T.Person): T.PronounSelection {
|
||||||
|
return {
|
||||||
|
type: "pronoun",
|
||||||
|
person: p,
|
||||||
|
distance: randFromArray(["far", "near", "far"]),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const verb = getVerb();
|
||||||
|
const king = personPool();
|
||||||
|
let servant: T.Person;
|
||||||
|
do {
|
||||||
|
servant = randomPerson();
|
||||||
|
} while (isInvalidSubjObjCombo(king, servant));
|
||||||
|
return makeVPS({
|
||||||
|
verb,
|
||||||
|
king: personToNPSelection(king),
|
||||||
|
servant: personToNPSelection(servant),
|
||||||
|
tense,
|
||||||
|
defaultTransitivity: level.type.startsWith("transitive")
|
||||||
|
? "transitive"
|
||||||
|
: "grammatically transitive",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function getQuestion(): Question {
|
||||||
|
const VPS = makeRandomVPS(levelInfo.tense === "allTenses"
|
||||||
|
? tensePool()
|
||||||
|
: levelInfo.tense
|
||||||
|
);
|
||||||
|
const VP = renderVP(VPS);
|
||||||
|
const compiled = compileVP(
|
||||||
|
VP,
|
||||||
|
{ removeKing: false, shrinkServant: false },
|
||||||
|
true,
|
||||||
|
{ ba: levelInfo.tense === "allTenses", verb: true, negative: true },
|
||||||
|
);
|
||||||
|
const phrase = {
|
||||||
|
ps: compiled.ps,
|
||||||
|
e: compiled.e,
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
rendered: VP,
|
||||||
|
phrase,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function Display({ question, callback }: QuestionDisplayProps<Question>) {
|
||||||
|
const [answer, setAnswer] = useState<string>("");
|
||||||
|
const [withBa, setWithBa] = useState<boolean>(false);
|
||||||
|
const handleInput = ({ target: { value }}: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
if (value === "به " || value === "به ") {
|
||||||
|
setWithBa(true);
|
||||||
|
setAnswer("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setAnswer(value);
|
||||||
|
}
|
||||||
|
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const correct = comparePs(answer, getVerbPs(question.rendered))
|
||||||
|
&& (withBa === verbHasBa(question.rendered));
|
||||||
|
if (correct) {
|
||||||
|
setAnswer("");
|
||||||
|
}
|
||||||
|
callback(correct);
|
||||||
|
}
|
||||||
|
// useEffect(() => {
|
||||||
|
// if (level === "allProduce") setWithBa(false);
|
||||||
|
// }, [question]);
|
||||||
|
return <div>
|
||||||
|
<QuestionDisplay question={question} userAnswer={{
|
||||||
|
withBa,
|
||||||
|
answer,
|
||||||
|
}} />
|
||||||
|
<form onSubmit={handleSubmit}>
|
||||||
|
{level.type === "all-tenses" && <div className="form-check mt-1">
|
||||||
|
<input
|
||||||
|
id="baCheckbox"
|
||||||
|
className="form-check-input"
|
||||||
|
type="checkbox"
|
||||||
|
checked={withBa}
|
||||||
|
onChange={e => setWithBa(e.target.checked)}
|
||||||
|
/>
|
||||||
|
<label className="form-check-label text-muted" htmlFor="baCheckbox">
|
||||||
|
with <InlinePs opts={opts}>{grammarUnits.baParticle}</InlinePs> in the <span style={{ color: kidsColor }}>kids' section</span>
|
||||||
|
</label>
|
||||||
|
</div>}
|
||||||
|
<div className="my-1" style={{ maxWidth: "200px", margin: "0 auto" }}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="form-control"
|
||||||
|
autoComplete="off"
|
||||||
|
autoCapitalize="off"
|
||||||
|
spellCheck="false"
|
||||||
|
dir="auto"
|
||||||
|
value={answer}
|
||||||
|
onChange={handleInput}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="text-center my-2">
|
||||||
|
{/* <div> */}
|
||||||
|
<button className="btn btn-primary" type="submit">submit ↵</button>
|
||||||
|
{/* </div> */}
|
||||||
|
{/* <div className="text-muted small text-center mt-2">
|
||||||
|
Type <kbd>Enter</kbd> to check
|
||||||
|
</div> */}
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
function Instructions() {
|
||||||
|
const desc = levelInfo.description;
|
||||||
|
return <div>
|
||||||
|
<p className="lead">
|
||||||
|
Write the {desc} verb to complete the phrase
|
||||||
|
{desc ? "" : " (all tenses)"}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
return <GameCore
|
||||||
|
inChapter={inChapter}
|
||||||
|
studyLink={link}
|
||||||
|
getQuestion={getQuestion}
|
||||||
|
id={id}
|
||||||
|
Display={Display}
|
||||||
|
DisplayCorrectAnswer={DisplayCorrectAnswer}
|
||||||
|
timeLimit={timeLimit}
|
||||||
|
amount={amount}
|
||||||
|
Instructions={Instructions}
|
||||||
|
/>
|
||||||
|
};
|
||||||
|
|
||||||
|
export default VerbGame;
|
||||||
|
|
||||||
|
function QuestionDisplay({ question, userAnswer }: {
|
||||||
|
question: Question,
|
||||||
|
userAnswer: { withBa: boolean, answer: string },
|
||||||
|
}) {
|
||||||
|
const ps = addUserAnswer(
|
||||||
|
userAnswer,
|
||||||
|
flattenLengths(question.phrase.ps)[0]
|
||||||
|
);
|
||||||
|
const v = getVerbFromBlocks(question.rendered.blocks);
|
||||||
|
const vEntry = v.block.verb.entry;
|
||||||
|
const infoV = getVerbInfo(vEntry)
|
||||||
|
const info = "grammaticallyTransitive" in infoV
|
||||||
|
? infoV.grammaticallyTransitive
|
||||||
|
: "stative" in infoV
|
||||||
|
? infoV.stative
|
||||||
|
: infoV;
|
||||||
|
return <div className="mb-3 mt-2">
|
||||||
|
<div className="mb-2">
|
||||||
|
<div>{vEntry.p} - {removeFVarients(vEntry.f)} <span className="text-muted">{vEntry.c}</span></div>
|
||||||
|
<div>"{getEnglishVerb(vEntry)}"</div>
|
||||||
|
</div>
|
||||||
|
<details style={{ marginBottom: 0 }}>
|
||||||
|
<summary>🌳 Show roots and stems</summary>
|
||||||
|
<RootsAndStems info={info} textOptions={defaultTextOptions} />
|
||||||
|
</details>
|
||||||
|
<div dir="rtl">{ps.p}</div>
|
||||||
|
<div dir="ltr">{ps.f}</div>
|
||||||
|
{question.phrase.e && <div className="text-muted mt-2">
|
||||||
|
{question.phrase.e.map(x => <div key={Math.random()}>
|
||||||
|
{x}
|
||||||
|
</div>)}
|
||||||
|
</div>}
|
||||||
|
<div>{humanReadableVerbForm(v.block.tense)}</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function DisplayCorrectAnswer({ question }: { question: Question }): JSX.Element {
|
||||||
|
return <div>
|
||||||
|
<div>
|
||||||
|
{getVerbPs(question.rendered).reduce(((accum, curr, i): JSX.Element[] => (
|
||||||
|
[
|
||||||
|
...accum,
|
||||||
|
...i > 0 ? [<span className="text-muted"> or </span>] : [],
|
||||||
|
<span>{curr.p} - {curr.f}</span>,
|
||||||
|
]
|
||||||
|
)), [] as JSX.Element[])}
|
||||||
|
</div>
|
||||||
|
<div><strong>{verbHasBa(question.rendered) ? "with" : "without"}</strong> a <InlinePs opts={opts}>{grammarUnits.baParticle}</InlinePs> in the kids' section.</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
// function modExs(exs: T.PsString[], withBa: boolean): { p: JSX.Element, f: JSX.Element }[] {
|
||||||
|
// return exs.map(ps => {
|
||||||
|
// if (!ps.p.includes(" ___ ")) {
|
||||||
|
// return {
|
||||||
|
// p: <>{ps.p}</>,
|
||||||
|
// f: <>{ps.f}</>,
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
// const splitP = ps.p.split(" ___ ");
|
||||||
|
// const splitF = ps.f.split(" ___ ");
|
||||||
|
// return {
|
||||||
|
// p: <>{splitP[0]} <span style={{ color: kidsColor }}>{withBa ? "به" : "__"}</span> {splitP[1]}</>,
|
||||||
|
// f: <>{splitF[0]} <span style={{ color: kidsColor }}>{withBa ? "ba" : "__"}</span> {splitF[1]}</>,
|
||||||
|
// };
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
function addUserAnswer(a: { withBa: boolean, answer: string }, ps: T.PsString): T.PsString {
|
||||||
|
function addBa(x: T.PsString) {
|
||||||
|
if (!a.withBa) return x;
|
||||||
|
return {
|
||||||
|
p: x.p.replace(kidsBlank.p, baParticle.p),
|
||||||
|
f: x.f.replace(kidsBlank.f, baParticle.f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function addAnswer(x: T.PsString): T.PsString {
|
||||||
|
if (!a.answer) return x;
|
||||||
|
const field = isPashtoScript(a.answer) ? "p" : "f";
|
||||||
|
return {
|
||||||
|
...x,
|
||||||
|
[field]: x[field].replace(blank[field], a.answer),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return addAnswer(addBa(ps));
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeVPS({ verb, king, servant, tense, defaultTransitivity }: {
|
||||||
|
verb: T.VerbEntry,
|
||||||
|
king: T.NPSelection,
|
||||||
|
servant: T.NPSelection,
|
||||||
|
tense: T.PerfectTense,
|
||||||
|
defaultTransitivity: "transitive" | "grammatically transitive"
|
||||||
|
}): T.VPSelectionComplete {
|
||||||
|
const vps = makeVPSelectionState(verb);
|
||||||
|
const transitivity = (vps.verb.transitivity === "transitive" && vps.verb.canChangeTransitivity)
|
||||||
|
? defaultTransitivity
|
||||||
|
: vps.verb.transitivity;
|
||||||
|
const ergative = vps.verb.transitivity !== "intransitive" && isPastTense(tense);
|
||||||
|
const subject = ergative ? servant : king;
|
||||||
|
const object = ergative ? king : servant;
|
||||||
|
return {
|
||||||
|
...vps,
|
||||||
|
verb: {
|
||||||
|
...vps.verb,
|
||||||
|
negative: isImperativeTense(tense)
|
||||||
|
? randFromArray([false, false, true])
|
||||||
|
: false,
|
||||||
|
transitivity,
|
||||||
|
tense,
|
||||||
|
},
|
||||||
|
blocks: maybeShuffleArray([
|
||||||
|
{
|
||||||
|
key: Math.random(),
|
||||||
|
block: {
|
||||||
|
type: "subjectSelection",
|
||||||
|
selection: subject,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: Math.random(),
|
||||||
|
block: {
|
||||||
|
type: "objectSelection",
|
||||||
|
selection: transitivity === "intransitive"
|
||||||
|
? "none"
|
||||||
|
: transitivity === "grammatically transitive"
|
||||||
|
? T.Person.ThirdPlurMale
|
||||||
|
: object,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getVerbPs({ blocks }: T.VPRendered): T.PsString[] {
|
||||||
|
const { perfectiveHead, verb } = blockUtils.getVerbAndHeadFromBlocks(blocks);
|
||||||
|
const mU = blocks[0].find(b => b.block.type === "negative" && b.block.imperative);
|
||||||
|
function vBase() {
|
||||||
|
if (!perfectiveHead) {
|
||||||
|
return flattenLengths(verb.block.ps);
|
||||||
|
}
|
||||||
|
return flattenLengths(verb.block.ps).map(r => concatPsString(perfectiveHead.ps, r));
|
||||||
|
}
|
||||||
|
if (mU) {
|
||||||
|
return vBase().map(b => concatPsString({ p: "مه", f: "mú" }, " ", b));
|
||||||
|
}
|
||||||
|
return vBase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function verbHasBa({ blocks }: T.VPRendered): boolean {
|
||||||
|
const verb = blockUtils.getVerbFromBlocks(blocks);
|
||||||
|
return verb.block.hasBa;
|
||||||
|
}
|
|
@ -266,7 +266,7 @@ const VerbGame: GameSubCore<VerbGameLevel> = ({ id, link, level, inChapter }: {
|
||||||
</div>
|
</div>
|
||||||
<div className="text-center my-2">
|
<div className="text-center my-2">
|
||||||
{/* <div> */}
|
{/* <div> */}
|
||||||
<button className="btn btn-primary" type="submit">return ↵</button>
|
<button className="btn btn-primary" type="submit">submit ↵</button>
|
||||||
{/* </div> */}
|
{/* </div> */}
|
||||||
{/* <div className="text-muted small text-center mt-2">
|
{/* <div className="text-muted small text-center mt-2">
|
||||||
Type <kbd>Enter</kbd> to check
|
Type <kbd>Enter</kbd> to check
|
||||||
|
|
Loading…
Reference in New Issue