Skip to content

Commit a019c7c

Browse files
committed
Improvements to autocomplete redirects. See #1380
1 parent ffb8f8d commit a019c7c

File tree

2 files changed

+117
-65
lines changed

2 files changed

+117
-65
lines changed

web/js/codeworld_shared.js

Lines changed: 59 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -545,62 +545,73 @@ function registerStandardHints(successFunc) {
545545
}
546546
}
547547

548-
// If there's a chance to find an exact match, clear out the fuzzy matches
549-
// so that the exact match is chosen.
550-
if (found[0].length + found[1].length === 1) {
551-
found[2] = [];
552-
}
553-
554-
const options = found[0].concat(found[1], found[2]);
555-
548+
let options = found[0].concat(found[1], found[2]);
549+
let foundReplacementPrefix = false;
556550
options.forEach((candidate) => {
557551
const { text } = candidate;
558-
const originalTermCost = substitutionCost(
559-
token.string,
560-
text,
561-
term.length
562-
);
552+
candidate.cost = substitutionCost(token.string, text, term.length);
563553

564-
for (const [module, mapping] of Object.entries(replacementTerms)) {
565-
if (window.codeWorldSymbols[text]) {
566-
const mappedTerms =
567-
Object.prototype.hasOwnProperty.call(mapping, text) &&
568-
mapping[text];
569-
const { definingModule } = window.codeWorldSymbols[text];
570-
571-
if (mappedTerms && definingModule && definingModule === module) {
572-
const mappedTermsWithCosts = mappedTerms.map((mappedTerm) => {
573-
return {
574-
replacementExplanation: mappedTerm.explanation,
575-
cost: substitutionCost(
576-
token.string,
577-
mappedTerm.value ? mappedTerm.value : mappedTerm,
578-
term.length,
579-
true
580-
),
581-
};
582-
});
554+
if (!window.codeWorldSymbols[text]) {
555+
return;
556+
}
583557

584-
const lowestCost = Math.min(
585-
...mappedTermsWithCosts.map(({ cost }) => cost),
586-
originalTermCost
587-
);
588-
candidate.cost = lowestCost;
589-
590-
const winningMappedTerm = mappedTermsWithCosts.find(
591-
({ cost }) => cost === lowestCost
592-
);
593-
if (winningMappedTerm) {
594-
candidate.replacementExplanation =
595-
winningMappedTerm.replacementExplanation;
596-
}
597-
} else {
598-
candidate.cost = originalTermCost;
599-
}
558+
const { definingModule } = window.codeWorldSymbols[text];
559+
if (!definingModule) {
560+
return;
561+
}
562+
563+
const mapping = replacementTerms[definingModule];
564+
const mappedTerms =
565+
Object.prototype.hasOwnProperty.call(mapping, text) && mapping[text];
566+
567+
if (!mappedTerms) {
568+
return;
569+
}
570+
571+
const mappedTermsWithCosts = mappedTerms.map((mappedTerm) => {
572+
const replacementWord = mappedTerm.value
573+
? mappedTerm.value
574+
: mappedTerm;
575+
if (replacementWord.startsWith(term)) {
576+
foundReplacementPrefix = true;
600577
}
578+
579+
return {
580+
replacementExplanation: mappedTerm.explanation,
581+
cost: substitutionCost(
582+
token.string,
583+
mappedTerm.value ? mappedTerm.value : mappedTerm,
584+
term.length,
585+
true
586+
),
587+
};
588+
});
589+
590+
const lowestCost = Math.min(
591+
...mappedTermsWithCosts.map(({ cost }) => cost),
592+
candidate.cost
593+
);
594+
candidate.cost = lowestCost;
595+
596+
const winningMappedTerm = mappedTermsWithCosts.find(
597+
({ cost }) => cost === lowestCost
598+
);
599+
if (winningMappedTerm) {
600+
candidate.replacementExplanation =
601+
winningMappedTerm.replacementExplanation;
601602
}
602603
});
603604

605+
// If there's a chance to complete an exact prefix, clear out the fuzzy
606+
// matches so that the exact match is chosen.
607+
if (
608+
found[0].length === 0 &&
609+
found[1].length === 1 &&
610+
!foundReplacementPrefix
611+
) {
612+
options = found[1];
613+
}
614+
604615
if (options.length > 0) {
605616
options.sort((a, b) => {
606617
if (a.cost < b.cost) return -1;

web/replacement_terms.json

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
{
22
"Prelude": {
3-
"abs": ["positive", "magnitude"],
3+
"abs": ["positive", "magnitude", "absoluteValue"],
44
"acos": ["arccos"],
55
"activityOf": ["interactionOf"],
6-
"arc": ["semicircle"],
6+
"arc": [
7+
{
8+
"value": "semicircle",
9+
"explanation": "Hint: A semicircle is an arc with the start and end angles 180 degrees apart."
10+
}
11+
],
712
"asin": ["arcsin"],
813
"atan": ["arctan"],
914
"mixed": ["blend"],
@@ -17,23 +22,59 @@
1722
"polygon": [
1823
{
1924
"value": "triangle",
20-
"explanation": "A triangle is a polygon with three vertices."
25+
"explanation": "Hint: A triangle is a polygon with three vertices."
26+
},
27+
{
28+
"value": "quadrilateral",
29+
"explanation": "Hint: A quadrilateral is a polygon with four vertices."
30+
},
31+
{
32+
"value": "parallelogram",
33+
"explanation": "Hint: A parallelogram is a polygon with four vertices and parallel sides."
2134
},
22-
"quadrilateral",
23-
"parallelogram",
24-
"trapezoid",
25-
"rhombus",
26-
"pentagon",
27-
"hexagon",
28-
"heptagon",
29-
"octagon"
35+
{
36+
"value": "trapezoid",
37+
"explanation": "Hint: A trapezoid is a polygon with four vertices and one pair of parallel sides."
38+
},
39+
{
40+
"value": "rhombus",
41+
"explanation": "Hint: A rhombus is a polygon with four vertices and equal side lengths."
42+
},
43+
{
44+
"value": "pentagon",
45+
"explanation": "Hint: A pentagon is a polygon with five vertices."
46+
},
47+
{
48+
"value": "hexagon",
49+
"explanation": "Hint: A hexagon is a polygon with six vertices."
50+
},
51+
{
52+
"value": "heptagon",
53+
"explanation": "Hint: A heptagon is a polygon with seven vertices."
54+
},
55+
{
56+
"value": "octagon",
57+
"explanation": "Hint: An octagon is a polygon with eight vertices."
58+
}
3059
],
3160
"polyline": ["line"],
3261
"program": ["main"],
33-
"rectangle": ["square"],
34-
"rotated": ["turn"],
35-
"scaled": ["stretch", "reflect", "ellipse"],
36-
"sector": ["solidArc"],
62+
"rectangle": [
63+
{
64+
"value": "square",
65+
"explanation": "Hint: A square is a rectangle with the height and width equal."
66+
}
67+
],
68+
"reflected": ["mirror", "flip"],
69+
"rotated": ["turn", "flip"],
70+
"scaled": [
71+
"stretch",
72+
{
73+
"value": "ellipse",
74+
"explanation": "Hint: An ellipse is a scaled circle."
75+
}
76+
],
77+
"sector": ["solidArc", "pie"],
3778
"sin": ["sine"],
3879
"solidClosedCurve": ["solidCurve", "solidLoop", "solidOval"],
3980
"solidPolygon": [
@@ -48,7 +89,7 @@
4889
"solidOctagon"
4990
],
5091
"solidRectangle": ["solidSquare"],
51-
"sqrt": ["root", "radical"],
92+
"sqrt": ["root", "radical", "squareRoot"],
5293
"tan": ["tangent"],
5394
"thickClosedCurve": ["thickLoop", "thickOval"],
5495
"thickPolygon": [
@@ -64,6 +105,6 @@
64105
],
65106
"thickPolyline": ["thickLine"],
66107
"thickRectangle": ["thickSquare"],
67-
"translated": ["move"]
108+
"translated": ["move", "shift", "position"]
68109
}
69110
}

0 commit comments

Comments
 (0)