with sandwiches game
This commit is contained in:
parent
dd2a69985b
commit
89261434ee
|
@ -7,7 +7,7 @@
|
||||||
"@formkit/auto-animate": "^1.0.0-beta.1",
|
"@formkit/auto-animate": "^1.0.0-beta.1",
|
||||||
"@fortawesome/fontawesome-free": "^5.15.4",
|
"@fortawesome/fontawesome-free": "^5.15.4",
|
||||||
"@lingdocs/lingdocs-main": "^0.3.3",
|
"@lingdocs/lingdocs-main": "^0.3.3",
|
||||||
"@lingdocs/ps-react": "^5.3.3",
|
"@lingdocs/ps-react": "^5.4.1",
|
||||||
"@testing-library/jest-dom": "^5.11.4",
|
"@testing-library/jest-dom": "^5.11.4",
|
||||||
"@testing-library/react": "^11.1.0",
|
"@testing-library/react": "^11.1.0",
|
||||||
"@testing-library/user-event": "^12.1.10",
|
"@testing-library/user-event": "^12.1.10",
|
||||||
|
|
|
@ -427,6 +427,13 @@ export const npWithAdjectivesNoHints = makeGameRecord({
|
||||||
level: "no-hints",
|
level: "no-hints",
|
||||||
SubCore: NPAdjWriting,
|
SubCore: NPAdjWriting,
|
||||||
});
|
});
|
||||||
|
export const npWithAdjectivesInSandwiches = makeGameRecord({
|
||||||
|
title: "Write the adjective and noun togehter in sandwiches 🥪",
|
||||||
|
id: "adjective-nps-in-sandwiches",
|
||||||
|
link: "/phrase-structure/ap/#sandwich-",
|
||||||
|
level: "sandwiches",
|
||||||
|
SubCore: NPAdjWriting,
|
||||||
|
});
|
||||||
|
|
||||||
const games: { chapter: string, items: GameRecord[] }[] = [
|
const games: { chapter: string, items: GameRecord[] }[] = [
|
||||||
{
|
{
|
||||||
|
@ -512,6 +519,7 @@ const games: { chapter: string, items: GameRecord[] }[] = [
|
||||||
epWithAdjectives,
|
epWithAdjectives,
|
||||||
npWithAdjectivesHints,
|
npWithAdjectivesHints,
|
||||||
npWithAdjectivesNoHints,
|
npWithAdjectivesNoHints,
|
||||||
|
npWithAdjectivesInSandwiches,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
@ -3,6 +3,11 @@ import {
|
||||||
Types as T,
|
Types as T,
|
||||||
renderNPSelection,
|
renderNPSelection,
|
||||||
getEnglishFromRendered,
|
getEnglishFromRendered,
|
||||||
|
randFromArray,
|
||||||
|
getPashtoFromRendered,
|
||||||
|
renderAPSelection,
|
||||||
|
InlinePs,
|
||||||
|
defaultTextOptions as opts,
|
||||||
concatPsString,
|
concatPsString,
|
||||||
} from "@lingdocs/ps-react";
|
} from "@lingdocs/ps-react";
|
||||||
import { makeNPAdjGenerator } from "../../lib/np-adj-generator";
|
import { makeNPAdjGenerator } from "../../lib/np-adj-generator";
|
||||||
|
@ -14,12 +19,82 @@ const amount = 15;
|
||||||
const timeLimit = 230;
|
const timeLimit = 230;
|
||||||
|
|
||||||
type Question = {
|
type Question = {
|
||||||
selection: T.NPSelection,
|
selection: T.NPSelection | T.APSelection,
|
||||||
answer: T.PsString[],
|
answer: T.PsString[],
|
||||||
english: string,
|
english: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
type Level = "hints" | "no-hints";
|
type Level = "hints" | "no-hints" | "sandwiches";
|
||||||
|
|
||||||
|
export const sandwiches: T.Sandwich[] = [
|
||||||
|
{
|
||||||
|
type: "sandwich",
|
||||||
|
before: { p: "له", f: "la" },
|
||||||
|
after: { p: "نه", f: "na" },
|
||||||
|
e: "from",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "sandwich",
|
||||||
|
before: { p: "له", f: "la" },
|
||||||
|
after: { p: "څخه", f: "tsuxa" },
|
||||||
|
e: "from",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "sandwich",
|
||||||
|
before: { p: "له", f: "la" },
|
||||||
|
after: { p: "سره", f: "sara" },
|
||||||
|
e: "with",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "sandwich",
|
||||||
|
before: undefined,
|
||||||
|
after: { p: "ته", f: "ta" },
|
||||||
|
e: "to",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "sandwich",
|
||||||
|
before: { p: "د", f: "du" },
|
||||||
|
after: { p: "لپاره", f: "lapaara" },
|
||||||
|
e: "for",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "sandwich",
|
||||||
|
before: { p: "د", f: "du" },
|
||||||
|
after: { p: "په څانګ", f: "pu tsaang" },
|
||||||
|
e: "beside",
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// type: "sandwich",
|
||||||
|
// before: { p: "په", f: "pu" },
|
||||||
|
// after: { p: "کې", f: "ke" },
|
||||||
|
// e: "in",
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
type: "sandwich",
|
||||||
|
before: { p: "د", f: "du" },
|
||||||
|
after: { p: "لاندې", f: "laande" },
|
||||||
|
e: "under",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "sandwich",
|
||||||
|
before: { p: "د", f: "du" },
|
||||||
|
after: { p: "په شان", f: "pu shaan" },
|
||||||
|
e: "like",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "sandwich",
|
||||||
|
before: { p: "د", f: "du" },
|
||||||
|
after: { p: "غوندې", f: "ghwunde" },
|
||||||
|
e: "like",
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// type: "sandwich",
|
||||||
|
// before: { p: "د", f: "du" },
|
||||||
|
// after: { p: "په اړه", f: "pu aRa" },
|
||||||
|
// e: "about",
|
||||||
|
// },
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
// LEVELS
|
// LEVELS
|
||||||
// - without plurals
|
// - without plurals
|
||||||
|
@ -35,18 +110,20 @@ const NPAdjWriting: GameSubCore<Level> = ({ inChapter, id, link, level }: {
|
||||||
|
|
||||||
function getQuestion(): Question {
|
function getQuestion(): Question {
|
||||||
const np = npPool();
|
const np = npPool();
|
||||||
const rendered = renderNPSelection(np, false, false, "subject", "none", false);
|
const selection: T.NPSelection | T.APSelection = level === "sandwiches"
|
||||||
const renderedAdj: T.Rendered<T.AdjectiveSelection> | undefined = rendered.selection.adjectives && rendered.selection.adjectives[0];
|
? {
|
||||||
if (!renderedAdj) {
|
type: "AP",
|
||||||
throw new Error("error getting rendered adjective");
|
selection: {
|
||||||
}
|
...randFromArray(sandwiches),
|
||||||
const answer = renderedAdj.ps.flatMap((adjPs) => (
|
inside: np,
|
||||||
rendered.selection.ps.map((nounPs) => (
|
},
|
||||||
concatPsString(adjPs, " ", nounPs)
|
} : np;
|
||||||
))
|
const rendered: T.Rendered<T.NPSelection> | T.Rendered<T.APSelection> = selection.type === "AP"
|
||||||
));
|
? renderAPSelection(selection, 0) // WOULD BE CLEANER IF THIS WAS JUST A PURE SANDWICH, NOT AT AP
|
||||||
|
: renderNPSelection(np, false, false, "subject", "none", false);
|
||||||
|
const answer = getPashtoFromRendered(rendered, false);
|
||||||
return {
|
return {
|
||||||
selection: np,
|
selection,
|
||||||
answer,
|
answer,
|
||||||
english: getEnglishFromRendered(rendered) || "ERROR",
|
english: getEnglishFromRendered(rendered) || "ERROR",
|
||||||
};
|
};
|
||||||
|
@ -62,20 +139,29 @@ const NPAdjWriting: GameSubCore<Level> = ({ inChapter, id, link, level }: {
|
||||||
}
|
}
|
||||||
callback(correct);
|
callback(correct);
|
||||||
}
|
}
|
||||||
if (question.selection.type !== "NP" || question.selection.selection.type !== "noun") {
|
if (!(
|
||||||
throw new Error("QUESTION ERROR");
|
(question.selection.type === "AP" && question.selection.selection.type === "sandwich" && question.selection.selection.inside.selection.type === "noun")
|
||||||
|
||
|
||||||
|
(question.selection.type === "NP" && question.selection.selection.type === "noun")
|
||||||
|
)) {
|
||||||
|
throw new Error("QUESTION ERROR - BAD SELECTION")
|
||||||
}
|
}
|
||||||
const nounEntry = question.selection.selection.entry;
|
const nounSelection: T.NounSelection = question.selection.type === "AP"
|
||||||
const adjEntry: T.AdjectiveEntry | undefined = question.selection.selection.adjectives[0]?.entry;
|
? question.selection.selection.inside.selection as T.NounSelection // ts being dumb
|
||||||
|
: question.selection.selection;
|
||||||
|
const adjEntry: T.AdjectiveEntry | undefined = nounSelection.adjectives[0]?.entry;
|
||||||
if (!adjEntry) {
|
if (!adjEntry) {
|
||||||
throw new Error("QUESTION ERROR - MISSING ADJECTIVE");
|
throw new Error("QUESTION ERROR - MISSING ADJECTIVE");
|
||||||
}
|
}
|
||||||
const handleInput = ({ target: { value }}: React.ChangeEvent<HTMLInputElement>) => {
|
const handleInput = ({ target: { value }}: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
setAnswer(value);
|
setAnswer(value);
|
||||||
}
|
}
|
||||||
|
const sandwich = question.selection.type === "AP"
|
||||||
|
? question.selection.selection
|
||||||
|
: undefined;
|
||||||
return <div>
|
return <div>
|
||||||
<div className="my-2" style={{ maxWidth: "300px", margin: "0 auto" }}>
|
<div className="my-2" style={{ maxWidth: "300px", margin: "0 auto" }}>
|
||||||
<div className="d-flex flex-row justify-content-center">
|
<div className="d-flex flex-row justify-content-center" style={{ gap: "1rem"}}>
|
||||||
<WordCard
|
<WordCard
|
||||||
showHint={level === "hints"}
|
showHint={level === "hints"}
|
||||||
entry={adjEntry}
|
entry={adjEntry}
|
||||||
|
@ -83,10 +169,15 @@ const NPAdjWriting: GameSubCore<Level> = ({ inChapter, id, link, level }: {
|
||||||
/>
|
/>
|
||||||
<WordCard
|
<WordCard
|
||||||
showHint={level === "hints"}
|
showHint={level === "hints"}
|
||||||
entry={nounEntry}
|
entry={nounSelection.entry}
|
||||||
selection={question.selection.selection}
|
selection={nounSelection}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{sandwich && <div className="mt-2">
|
||||||
|
<InlinePs opts={opts}>
|
||||||
|
{concatPsString(sandwich.before, " ... ", sandwich.after)}
|
||||||
|
</InlinePs>
|
||||||
|
</div>}
|
||||||
<div className="my-3 h5">
|
<div className="my-3 h5">
|
||||||
{question.english}
|
{question.english}
|
||||||
</div>
|
</div>
|
||||||
|
@ -113,7 +204,7 @@ const NPAdjWriting: GameSubCore<Level> = ({ inChapter, id, link, level }: {
|
||||||
|
|
||||||
function Instructions() {
|
function Instructions() {
|
||||||
return <div>
|
return <div>
|
||||||
<p className="lead">Write the adjective and noun together with the proper inflections.</p>
|
<p className="lead">Write the {level === "sandwiches" ? "sandwich including the" : ""} adjective and noun together with the proper inflections.</p>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,10 @@ export function compareF(input: string, answer: string): boolean {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function comparePs(inputRaw: string, answer: T.SingleOrLengthOpts<T.PsString | T.PsString[]>): boolean {
|
export function comparePs(inputRaw: string, answer: T.SingleOrLengthOpts<T.PsString | T.PsString[]>): boolean {
|
||||||
const input = inputRaw.replace(/\s+/g, " ");
|
function cleanSpaces(s: string): string {
|
||||||
|
return s.replace(/\s+/g, " ");
|
||||||
|
}
|
||||||
|
const input = cleanSpaces(inputRaw);
|
||||||
if ("long" in answer) {
|
if ("long" in answer) {
|
||||||
return comparePs(input, flattenLengths(answer));
|
return comparePs(input, flattenLengths(answer));
|
||||||
}
|
}
|
||||||
|
@ -39,5 +42,5 @@ export function comparePs(inputRaw: string, answer: T.SingleOrLengthOpts<T.PsStr
|
||||||
const stand = standardizePhonetics(
|
const stand = standardizePhonetics(
|
||||||
standardizePashto(input)
|
standardizePashto(input)
|
||||||
).trim();
|
).trim();
|
||||||
return stand === answer.p || compareF(stand, answer.f);
|
return stand === cleanSpaces(answer.p) || compareF(stand, cleanSpaces(answer.f));
|
||||||
}
|
}
|
|
@ -2726,10 +2726,10 @@
|
||||||
rambda "^6.7.0"
|
rambda "^6.7.0"
|
||||||
react-select "^5.2.2"
|
react-select "^5.2.2"
|
||||||
|
|
||||||
"@lingdocs/ps-react@^5.3.3":
|
"@lingdocs/ps-react@^5.4.1":
|
||||||
version "5.3.3"
|
version "5.4.1"
|
||||||
resolved "https://npm.lingdocs.com/@lingdocs%2fps-react/-/ps-react-5.3.3.tgz#05066c27059b5133dc0028d733d6dddfbfc9f9b0"
|
resolved "https://npm.lingdocs.com/@lingdocs%2fps-react/-/ps-react-5.4.1.tgz#60ce096dd36910d04523af3c7e74143a583743f2"
|
||||||
integrity sha512-qsX9iRqSc62JGDuBNvddfZgX3Skk5MM8XtuaydnyK3A7LZrP9VuiJZ0+k6zvi2shi+Gg52aAEPJstEieycBKrA==
|
integrity sha512-wczQzyO/BYasmpf67R4FgjTG2OC9o++jeIQM7bMThl52Zw9rexDEy3H1+WITRdVOf+Ug//8YiAhpBlrB/nBmAA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@formkit/auto-animate" "^1.0.0-beta.3"
|
"@formkit/auto-animate" "^1.0.0-beta.3"
|
||||||
classnames "^2.2.6"
|
classnames "^2.2.6"
|
||||||
|
|
Loading…
Reference in New Issue