math-exercises 3.0.152 → 3.0.154
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/exercises/exercise.d.ts +2 -0
- package/lib/exercises/exercise.d.ts.map +1 -1
- package/lib/exercises/math/calculLitteral/equation/index.d.ts +1 -1
- package/lib/exercises/math/calculLitteral/equation/index.d.ts.map +1 -1
- package/lib/exercises/math/calculLitteral/equation/index.js +1 -1
- package/lib/exercises/math/calculLitteral/equation/square/equationSimpleSquare.d.ts +10 -0
- package/lib/exercises/math/calculLitteral/equation/square/equationSimpleSquare.d.ts.map +1 -0
- package/lib/exercises/math/calculLitteral/equation/square/equationSimpleSquare.js +183 -0
- package/lib/exercises/math/calculLitteral/equation/square/equationSquareWithSteps.d.ts +10 -0
- package/lib/exercises/math/calculLitteral/equation/square/equationSquareWithSteps.d.ts.map +1 -0
- package/lib/exercises/math/calculLitteral/equation/square/equationSquareWithSteps.js +173 -0
- package/lib/exercises/math/calculLitteral/equation/square/index.d.ts +3 -0
- package/lib/exercises/math/calculLitteral/equation/square/index.d.ts.map +1 -0
- package/lib/exercises/math/calculLitteral/equation/square/index.js +2 -0
- package/lib/exercises/math/functions/sqrt/squareRootCalculation.d.ts.map +1 -1
- package/lib/exercises/math/functions/sqrt/squareRootCalculation.js +4 -2
- package/lib/exercises/math/geometry/euclidian/homothetyFactorFromPoints.d.ts +15 -0
- package/lib/exercises/math/geometry/euclidian/homothetyFactorFromPoints.d.ts.map +1 -0
- package/lib/exercises/math/geometry/euclidian/homothetyFactorFromPoints.js +301 -0
- package/lib/exercises/math/geometry/euclidian/index.d.ts +7 -0
- package/lib/exercises/math/geometry/euclidian/index.d.ts.map +1 -1
- package/lib/exercises/math/geometry/euclidian/index.js +7 -0
- package/lib/exercises/math/geometry/euclidian/pinPointFromAxialOrCentralSymmetry.d.ts +21 -0
- package/lib/exercises/math/geometry/euclidian/pinPointFromAxialOrCentralSymmetry.d.ts.map +1 -0
- package/lib/exercises/math/geometry/euclidian/pinPointFromAxialOrCentralSymmetry.js +406 -0
- package/lib/exercises/math/geometry/euclidian/pinPointFromRotation.d.ts +18 -0
- package/lib/exercises/math/geometry/euclidian/pinPointFromRotation.d.ts.map +1 -0
- package/lib/exercises/math/geometry/euclidian/pinPointFromRotation.js +315 -0
- package/lib/exercises/math/geometry/euclidian/pinPointFromTranslation.d.ts +20 -0
- package/lib/exercises/math/geometry/euclidian/pinPointFromTranslation.d.ts.map +1 -0
- package/lib/exercises/math/geometry/euclidian/pinPointFromTranslation.js +314 -0
- package/lib/exercises/math/geometry/euclidian/pinSegmentFromRotation.d.ts +18 -0
- package/lib/exercises/math/geometry/euclidian/pinSegmentFromRotation.d.ts.map +1 -0
- package/lib/exercises/math/geometry/euclidian/pinSegmentFromRotation.js +387 -0
- package/lib/exercises/math/geometry/euclidian/recognizeAngleFromRotation.d.ts +18 -0
- package/lib/exercises/math/geometry/euclidian/recognizeAngleFromRotation.d.ts.map +1 -0
- package/lib/exercises/math/geometry/euclidian/recognizeAngleFromRotation.js +309 -0
- package/lib/exercises/math/geometry/euclidian/recognizeHomothetyCenter.d.ts +17 -0
- package/lib/exercises/math/geometry/euclidian/recognizeHomothetyCenter.d.ts.map +1 -0
- package/lib/exercises/math/geometry/euclidian/recognizeHomothetyCenter.js +301 -0
- package/lib/exercises/math/geometry/euclidianConstructions/buildPointFromAxialSymetry.d.ts.map +1 -1
- package/lib/exercises/math/geometry/euclidianConstructions/buildPointFromAxialSymetry.js +22 -8
- package/lib/exercises/math/geometry/euclidianConstructions/buildPointFromCentralSymmetry.d.ts +11 -0
- package/lib/exercises/math/geometry/euclidianConstructions/buildPointFromCentralSymmetry.d.ts.map +1 -0
- package/lib/exercises/math/geometry/euclidianConstructions/buildPointFromCentralSymmetry.js +169 -0
- package/lib/exercises/math/geometry/euclidianConstructions/index.d.ts +2 -0
- package/lib/exercises/math/geometry/euclidianConstructions/index.d.ts.map +1 -1
- package/lib/exercises/math/geometry/euclidianConstructions/index.js +2 -0
- package/lib/exercises/math/geometry/euclidianConstructions/placeHomothetyCenter.d.ts +16 -0
- package/lib/exercises/math/geometry/euclidianConstructions/placeHomothetyCenter.d.ts.map +1 -0
- package/lib/exercises/math/geometry/euclidianConstructions/placeHomothetyCenter.js +309 -0
- package/lib/exercises/math/probaStat/basicProbas/index.js +1 -0
- package/lib/exercises/math/probaStat/basicProbas/pickEquiprobableSituations.d.ts +11 -0
- package/lib/exercises/math/probaStat/basicProbas/pickEquiprobableSituations.d.ts.map +1 -0
- package/lib/exercises/math/probaStat/basicProbas/pickEquiprobableSituations.js +136 -0
- package/lib/exercises/math/probaStat/basicProbas/pickEquiprobableTo.d.ts.map +1 -1
- package/lib/exercises/math/probaStat/basicProbas/pickEquiprobableTo.js +3 -79
- package/lib/exercises/math/probaStat/stats1var/averageWithClasses.d.ts +9 -0
- package/lib/exercises/math/probaStat/stats1var/averageWithClasses.d.ts.map +1 -0
- package/lib/exercises/math/probaStat/stats1var/averageWithClasses.js +140 -0
- package/lib/exercises/math/probaStat/stats1var/averageWithTableWithContext.d.ts +8 -0
- package/lib/exercises/math/probaStat/stats1var/averageWithTableWithContext.d.ts.map +1 -0
- package/lib/exercises/math/probaStat/stats1var/averageWithTableWithContext.js +113 -0
- package/lib/exercises/math/probaStat/stats1var/index.d.ts +2 -0
- package/lib/exercises/math/probaStat/stats1var/index.d.ts.map +1 -1
- package/lib/exercises/math/probaStat/stats1var/index.js +2 -0
- package/lib/exercises/math/probaStat/stats1var/medianWithList.js +4 -4
- package/lib/exercises/math/scratch/index.d.ts +3 -0
- package/lib/exercises/math/scratch/index.d.ts.map +1 -1
- package/lib/exercises/math/scratch/index.js +3 -0
- package/lib/exercises/math/scratch/scratchListElemAtIndex.d.ts +13 -0
- package/lib/exercises/math/scratch/scratchListElemAtIndex.d.ts.map +1 -0
- package/lib/exercises/math/scratch/scratchListElemAtIndex.js +189 -0
- package/lib/exercises/math/scratch/scratchListElemAtIndex2.d.ts +23 -0
- package/lib/exercises/math/scratch/scratchListElemAtIndex2.d.ts.map +1 -0
- package/lib/exercises/math/scratch/scratchListElemAtIndex2.js +207 -0
- package/lib/exercises/math/scratch/scratchListFilter.d.ts +13 -0
- package/lib/exercises/math/scratch/scratchListFilter.d.ts.map +1 -0
- package/lib/exercises/math/scratch/scratchListFilter.js +397 -0
- package/lib/exercises/math/spaceGeometry/basis/findSpacePointOnRectangularPrism.d.ts +14 -0
- package/lib/exercises/math/spaceGeometry/basis/findSpacePointOnRectangularPrism.d.ts.map +1 -0
- package/lib/exercises/math/spaceGeometry/basis/findSpacePointOnRectangularPrism.js +347 -0
- package/lib/exercises/math/spaceGeometry/basis/index.d.ts +1 -0
- package/lib/exercises/math/spaceGeometry/basis/index.d.ts.map +1 -1
- package/lib/exercises/math/spaceGeometry/basis/index.js +1 -0
- package/lib/exercises/math/spaceGeometry/index.d.ts +2 -0
- package/lib/exercises/math/spaceGeometry/index.d.ts.map +1 -1
- package/lib/exercises/math/spaceGeometry/index.js +2 -0
- package/lib/exercises/math/spaceGeometry/sections/areaOfConeSection.js +3 -3
- package/lib/exercises/math/spaceGeometry/solids/index.d.ts +3 -0
- package/lib/exercises/math/spaceGeometry/solids/index.d.ts.map +1 -0
- package/lib/exercises/math/spaceGeometry/solids/index.js +2 -0
- package/lib/exercises/math/spaceGeometry/solids/recognizeSolidFrom3D.d.ts +15 -0
- package/lib/exercises/math/spaceGeometry/solids/recognizeSolidFrom3D.d.ts.map +1 -0
- package/lib/exercises/math/spaceGeometry/solids/recognizeSolidFrom3D.js +440 -0
- package/lib/exercises/math/spaceGeometry/solids/recognizeSolidFromSolidPattern.d.ts +11 -0
- package/lib/exercises/math/spaceGeometry/solids/recognizeSolidFromSolidPattern.d.ts.map +1 -0
- package/lib/exercises/math/spaceGeometry/solids/recognizeSolidFromSolidPattern.js +1089 -0
- package/lib/exercises/math/spaceGeometry/sphere/index.d.ts +2 -0
- package/lib/exercises/math/spaceGeometry/sphere/index.d.ts.map +1 -0
- package/lib/exercises/math/spaceGeometry/sphere/index.js +2 -0
- package/lib/exercises/math/spaceGeometry/sphere/pickIsPointInSphereOrBall.d.ts +9 -0
- package/lib/exercises/math/spaceGeometry/sphere/pickIsPointInSphereOrBall.d.ts.map +1 -0
- package/lib/exercises/math/spaceGeometry/sphere/pickIsPointInSphereOrBall.js +127 -0
- package/lib/exercises/math/spaceGeometry/sphere/sphereLatLonReading.d.ts +14 -0
- package/lib/exercises/math/spaceGeometry/sphere/sphereLatLonReading.d.ts.map +1 -0
- package/lib/exercises/math/spaceGeometry/sphere/sphereLatLonReading.js +390 -0
- package/lib/geogebra/geogebraConstructor.d.ts +2 -0
- package/lib/geogebra/geogebraConstructor.d.ts.map +1 -1
- package/lib/geogebra/geogebraConstructor.js +6 -0
- package/lib/geogebra/probas/probaWheelGGBCommands.d.ts +7 -0
- package/lib/geogebra/probas/probaWheelGGBCommands.d.ts.map +1 -0
- package/lib/geogebra/probas/probaWheelGGBCommands.js +79 -0
- package/lib/index.d.ts +171 -5
- package/lib/index.d.ts.map +1 -1
- package/lib/math/geometry/point.d.ts +6 -0
- package/lib/math/geometry/point.d.ts.map +1 -1
- package/lib/math/geometry/point.js +28 -0
- package/lib/server.js +4 -1
- package/lib/tree/nodes/equations/equalNode.d.ts +1 -1
- package/lib/tree/nodes/equations/equalNode.d.ts.map +1 -1
- package/lib/tree/nodes/equations/equalNode.js +0 -1
- package/lib/tree/utilities/nodeSimplifier.d.ts +1 -1
- package/lib/utils/arrays/arrayZip.d.ts +2 -0
- package/lib/utils/arrays/arrayZip.d.ts.map +1 -0
- package/lib/utils/arrays/arrayZip.js +12 -0
- package/package.json +1 -1
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
import { toolBarConstructor } from "../../../../exercises/utils/geogebra/toolBarConstructor.js";
|
|
2
|
+
import { getDistinctQuestions } from "../../../../exercises/utils/getDistinctQuestions.js";
|
|
3
|
+
import { blueMain, greenMain, orange } from "../../../../geogebra/colors.js";
|
|
4
|
+
import { GeogebraConstructor } from "../../../../geogebra/geogebraConstructor.js";
|
|
5
|
+
import { Point, PointConstructor, } from "../../../../math/geometry/point.js";
|
|
6
|
+
import { Segment } from "../../../../math/geometry/segment.js";
|
|
7
|
+
import { Vector } from "../../../../math/geometry/vector.js";
|
|
8
|
+
import { randint } from "../../../../math/utils/random/randint.js";
|
|
9
|
+
import { round } from "../../../../math/utils/round.js";
|
|
10
|
+
import { abs } from "../../../../tree/nodes/functions/absNode.js";
|
|
11
|
+
import { NodeConstructor, } from "../../../../tree/nodes/nodeConstructor.js";
|
|
12
|
+
import { PiNode } from "../../../../tree/nodes/numbers/piNode.js";
|
|
13
|
+
import { add } from "../../../../tree/nodes/operators/addNode.js";
|
|
14
|
+
import { frac } from "../../../../tree/nodes/operators/fractionNode.js";
|
|
15
|
+
import { multiply } from "../../../../tree/nodes/operators/multiplyNode.js";
|
|
16
|
+
import { substract } from "../../../../tree/nodes/operators/substractNode.js";
|
|
17
|
+
import { random, randomMany } from "../../../../utils/alea/random.js";
|
|
18
|
+
import { shuffle } from "../../../../utils/alea/shuffle.js";
|
|
19
|
+
import { arrayRotation } from "../../../../utils/arrays/rotation.js";
|
|
20
|
+
function createSnowflakeDict(namesPool, angleInDegreesOffset = 0) {
|
|
21
|
+
function* generateNames(namesPool) {
|
|
22
|
+
let i = 0;
|
|
23
|
+
while (i < namesPool.length) {
|
|
24
|
+
yield namesPool[i];
|
|
25
|
+
i++;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const nameGen = generateNames(namesPool);
|
|
29
|
+
const pointOrigin = new Point(nameGen.next().value, 0, 0);
|
|
30
|
+
const baseLength = 1;
|
|
31
|
+
const pointsRound1 = (() => {
|
|
32
|
+
const anglesInDegrees = [...Array(6).keys()].map((i) => 60 * i + 30 + angleInDegreesOffset);
|
|
33
|
+
const radius = baseLength;
|
|
34
|
+
return anglesInDegrees.map((angleInDegrees) => PointConstructor.fromPointRadiusAndAngle(nameGen.next().value, pointOrigin, radius, angleInDegrees));
|
|
35
|
+
})();
|
|
36
|
+
const pointsRound2 = (() => {
|
|
37
|
+
const anglesInDegrees = [...Array(6).keys()].map((i) => 60 * i + 0 + angleInDegreesOffset);
|
|
38
|
+
const radius = (2 * baseLength * (Math.sqrt(3) / 2.0)).toTree();
|
|
39
|
+
return anglesInDegrees.map((angleInDegrees) => PointConstructor.fromPointRadiusAndAngle(nameGen.next().value, pointOrigin, radius, angleInDegrees));
|
|
40
|
+
})();
|
|
41
|
+
const segmentsRound1 = pointsRound1.map((pointRound1) => [
|
|
42
|
+
pointOrigin,
|
|
43
|
+
pointRound1,
|
|
44
|
+
]);
|
|
45
|
+
const pointsRound2Rotated1 = arrayRotation(pointsRound2, 1);
|
|
46
|
+
const segmentsRound2 = pointsRound1.flatMap((pointRound1, i) => [
|
|
47
|
+
[pointRound1, pointsRound2[i]],
|
|
48
|
+
[pointRound1, pointsRound2Rotated1[i]],
|
|
49
|
+
]);
|
|
50
|
+
return {
|
|
51
|
+
points: [pointOrigin, ...pointsRound1, ...pointsRound2],
|
|
52
|
+
segments: [...segmentsRound1, ...segmentsRound2],
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const createVector = (from, to, name, precision = 8) => {
|
|
56
|
+
return new Vector(name, round(substract(to.x, from.x).evaluate(), precision).toTree(), round(substract(to.y, from.y).evaluate(), precision).toTree());
|
|
57
|
+
};
|
|
58
|
+
const createPoint = (x, y, name, precision = 8) => {
|
|
59
|
+
return new Point(name, round(x, precision), round(y, precision));
|
|
60
|
+
};
|
|
61
|
+
const rotatePoint = (target, angle, center, name, precision = 8) => {
|
|
62
|
+
const vSrc = createVector(center, target, "vSrc", precision);
|
|
63
|
+
const vRotated = vSrc.rotate(angle, "vRotated");
|
|
64
|
+
return createPoint(add(center.x, vRotated.x).evaluate(), add(center.y, vRotated.y).evaluate(), name, precision);
|
|
65
|
+
};
|
|
66
|
+
const getGGBCoreCommands = (identifiers) => {
|
|
67
|
+
const { pointsDict, segments } = identifiers;
|
|
68
|
+
const points = Object.values(pointsDict).map((pointIds) => PointConstructor.fromIdentifiers(pointIds));
|
|
69
|
+
return [
|
|
70
|
+
...points.flatMap((point) => [
|
|
71
|
+
...point.toGGBCommand(),
|
|
72
|
+
`SetVisibleInView(${point.name}, 1, false)`,
|
|
73
|
+
`T_{${point.name}} = Text("${point.name}", (${point.x.evaluate() + 0.15},${point.y.evaluate() + 0.15}), false, true, 0, 0)`,
|
|
74
|
+
]),
|
|
75
|
+
...segments.flatMap((segment) => {
|
|
76
|
+
const [A, B] = segment.split("");
|
|
77
|
+
return [
|
|
78
|
+
`S_{${segment}} = Segment(${A}, ${B})`,
|
|
79
|
+
`SetLineThickness(S_{${segment}},3)`,
|
|
80
|
+
];
|
|
81
|
+
}),
|
|
82
|
+
];
|
|
83
|
+
};
|
|
84
|
+
const getStrForTransformation = (transformationIds) => {
|
|
85
|
+
switch (transformationIds.type) {
|
|
86
|
+
case "rotation": {
|
|
87
|
+
const nodeAngleInDegrees = NodeConstructor.fromIdentifiers(transformationIds.angleInDegrees);
|
|
88
|
+
const isPositiveAngle = nodeAngleInDegrees.evaluate() >= 0;
|
|
89
|
+
const strClockwise = isPositiveAngle ? "anti-horaire" : "horaire";
|
|
90
|
+
const absAngleInDegrees = abs(nodeAngleInDegrees).simplify();
|
|
91
|
+
return `la rotation de centre $${transformationIds.point1.name}$ et d'angle $${absAngleInDegrees.toTex()}°$ dans le sens ${strClockwise}`;
|
|
92
|
+
}
|
|
93
|
+
default:
|
|
94
|
+
throw new Error("Unsupported transformation type: " + transformationIds.type);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const getObjectWithName = (nameObj, pointsDict) => {
|
|
98
|
+
const namePoints = nameObj.split("");
|
|
99
|
+
const points = namePoints.map((namePoint) => PointConstructor.fromIdentifiers(pointsDict[namePoint]));
|
|
100
|
+
return new Segment(points[0], points[1]);
|
|
101
|
+
};
|
|
102
|
+
const getInstruction = (identifiers) => {
|
|
103
|
+
const { nameObjSrc, transformationIds } = identifiers;
|
|
104
|
+
return `Sur la figure ci-dessous, tous les losanges sont superposables.
|
|
105
|
+
Placer l'image du segment $[${nameObjSrc}]$ par ${getStrForTransformation(transformationIds)}.`;
|
|
106
|
+
};
|
|
107
|
+
const getHint = (identifiers) => {
|
|
108
|
+
const { nameObjSrc, transformationIds } = identifiers;
|
|
109
|
+
const [namePointA, namePointB] = nameObjSrc.split("");
|
|
110
|
+
return `Cherche l'image de $${namePointA}$ par ${getStrForTransformation(transformationIds)}. Même chose pour $${namePointB}$.`;
|
|
111
|
+
};
|
|
112
|
+
const getCorrection = (identifiers) => {
|
|
113
|
+
const { nameObjSrc, nameObjDst, transformationIds, pointsDict } = identifiers;
|
|
114
|
+
const pointsIds = Object.values(pointsDict);
|
|
115
|
+
return `L'angle $\\widehat{${pointsIds[1].name}${pointsIds[0].name}${pointsIds[2].name}}$ vaut $60°$.
|
|
116
|
+
L'image de $${nameObjSrc[0]}$ par ${getStrForTransformation(transformationIds)} est $${nameObjDst[1]}$ et celle de $${nameObjSrc[0]}$ est $${nameObjDst[1]}$.
|
|
117
|
+
L'image de $[${nameObjSrc}]$ par ${getStrForTransformation(transformationIds)} est donc $[${nameObjDst}]$.`;
|
|
118
|
+
};
|
|
119
|
+
const getSegmentSrc = (identifiers) => {
|
|
120
|
+
const { nameObjSrc, pointsDict } = identifiers;
|
|
121
|
+
return getObjectWithName(nameObjSrc, pointsDict);
|
|
122
|
+
};
|
|
123
|
+
const getSegmentDst = (identifiers) => {
|
|
124
|
+
const { nameObjDst, pointsDict } = identifiers;
|
|
125
|
+
return getObjectWithName(nameObjDst, pointsDict);
|
|
126
|
+
};
|
|
127
|
+
const getGGBAnswer = (identifiers) => {
|
|
128
|
+
const { transformationIds } = identifiers;
|
|
129
|
+
const nodeAngleInDegrees = NodeConstructor.fromIdentifiers(transformationIds.angleInDegrees);
|
|
130
|
+
const isPositiveAngle = nodeAngleInDegrees.evaluate() >= 0;
|
|
131
|
+
const absAngleInDegrees = abs(nodeAngleInDegrees).simplify();
|
|
132
|
+
const segmentSrc = getSegmentSrc(identifiers);
|
|
133
|
+
const segmentDst = getSegmentDst(identifiers);
|
|
134
|
+
let [pointSrc, pointDst] = [segmentSrc, segmentDst].map((segment) => segment.pointA);
|
|
135
|
+
const isBothPointsSameAsCenter = [pointSrc, pointDst].every((point) => point.name === transformationIds.point1.name);
|
|
136
|
+
if (isBothPointsSameAsCenter) {
|
|
137
|
+
[pointSrc, pointDst] = [segmentSrc, segmentDst].map((segment) => segment.pointB);
|
|
138
|
+
}
|
|
139
|
+
const ggbAnswer = [
|
|
140
|
+
...getGGBCoreCommands(identifiers),
|
|
141
|
+
//transformation
|
|
142
|
+
...(() => {
|
|
143
|
+
switch (transformationIds.type) {
|
|
144
|
+
case "rotation":
|
|
145
|
+
{
|
|
146
|
+
const pointCenter = PointConstructor.fromIdentifiers(transformationIds.point1);
|
|
147
|
+
return [
|
|
148
|
+
//pointCenter
|
|
149
|
+
`SetVisibleInView(T_${pointCenter.name}, 1, false)`,
|
|
150
|
+
`SetVisibleInView(${pointCenter.name}, 1, true)`,
|
|
151
|
+
...pointCenter.toGGBCommand({ color: `${orange}`, size: 5 }),
|
|
152
|
+
//segment1
|
|
153
|
+
`S1_{${pointCenter.name}${pointSrc.name}} = Segment(${pointCenter.name},${pointSrc.name})`,
|
|
154
|
+
`SetColor(S1_{${pointCenter.name}${pointSrc.name}},"${orange}")`,
|
|
155
|
+
//segment2
|
|
156
|
+
`S1_{${pointCenter.name}${pointDst.name}} = Segment(${pointCenter.name},${pointDst.name})`,
|
|
157
|
+
`SetColor(S1_{${pointCenter.name}${pointDst.name}},"${orange}")`,
|
|
158
|
+
//angle
|
|
159
|
+
isPositiveAngle
|
|
160
|
+
? `AA_{${pointSrc.name}${pointCenter.name}${pointDst.name}} = Angle(${pointSrc.name},${pointCenter.name},${pointDst.name})`
|
|
161
|
+
: `AA_{${pointSrc.name}${pointCenter.name}${pointDst.name}} = Angle(${pointDst.name},${pointCenter.name},${pointSrc.name})`,
|
|
162
|
+
`SetColor(AA_{${pointSrc.name}${pointCenter.name}${pointDst.name}},"${orange}")`,
|
|
163
|
+
`SetCaption(AA_{${pointSrc.name}${pointCenter.name}${pointDst.name}},"$${absAngleInDegrees.toTex()}°$")`,
|
|
164
|
+
`ShowLabel(AA_{${pointSrc.name}${pointCenter.name}${pointDst.name}}, true)`,
|
|
165
|
+
//arc
|
|
166
|
+
`C_{${pointCenter.name}${pointSrc.name}} = Circle(${pointCenter.name},${pointSrc.name})`,
|
|
167
|
+
`SetVisibleInView(C_{${pointCenter.name}${pointSrc.name}}, 1, false)`,
|
|
168
|
+
isPositiveAngle
|
|
169
|
+
? `AR_{${pointCenter.name}${pointSrc.name}} = Arc( C_{${pointCenter.name}${pointSrc.name}} , ${pointSrc.name} , ${pointDst.name} )`
|
|
170
|
+
: `AR_{${pointCenter.name}${pointSrc.name}} = Arc( C_{${pointCenter.name}${pointSrc.name}} , ${pointDst.name} , ${pointSrc.name} )`,
|
|
171
|
+
`SetColor(AR_{${pointCenter.name}${pointSrc.name}},"${orange}")`,
|
|
172
|
+
];
|
|
173
|
+
}
|
|
174
|
+
break;
|
|
175
|
+
default:
|
|
176
|
+
throw new Error("Unsupported transformation type: " + transformationIds.type);
|
|
177
|
+
}
|
|
178
|
+
})(),
|
|
179
|
+
//segmentSrc
|
|
180
|
+
`S_{src}=Segment(${segmentSrc.pointA.name},${segmentSrc.pointB.name})`,
|
|
181
|
+
`SetFixed(S_{src},true)`,
|
|
182
|
+
`ShowLabel(S_{src},false)`,
|
|
183
|
+
`SetColor(S_{src},"${blueMain}")`,
|
|
184
|
+
//segmentSrc.pointA
|
|
185
|
+
`SetVisibleInView(T_${segmentSrc.pointA.name}, 1, false)`,
|
|
186
|
+
`SetVisibleInView(${segmentSrc.pointA.name}, 1, true)`,
|
|
187
|
+
`SetColor(${segmentSrc.pointA.name}, "${blueMain}")`,
|
|
188
|
+
//segmentSrc.pointB
|
|
189
|
+
`SetVisibleInView(T_${segmentSrc.pointB.name}, 1, false)`,
|
|
190
|
+
`SetVisibleInView(${segmentSrc.pointB.name}, 1, true)`,
|
|
191
|
+
`SetColor(${segmentSrc.pointB.name}, "${blueMain}")`,
|
|
192
|
+
//segmentDst
|
|
193
|
+
`S_{dst}=Segment(${segmentDst.pointA.name},${segmentDst.pointB.name})`,
|
|
194
|
+
`SetFixed(S_{dst},true)`,
|
|
195
|
+
`ShowLabel(S_{dst},false)`,
|
|
196
|
+
`SetColor(S_{dst},"${greenMain}")`,
|
|
197
|
+
//segmentDst.pointA
|
|
198
|
+
`SetVisibleInView(T_${segmentDst.pointA.name}, 1, false)`,
|
|
199
|
+
`SetVisibleInView(${segmentDst.pointA.name}, 1, true)`,
|
|
200
|
+
`SetColor(${segmentDst.pointA.name}, "${greenMain}")`,
|
|
201
|
+
//segmentDst.pointB
|
|
202
|
+
`SetVisibleInView(T_${segmentDst.pointB.name}, 1, false)`,
|
|
203
|
+
`SetVisibleInView(${segmentDst.pointB.name}, 1, true)`,
|
|
204
|
+
`SetColor(${segmentDst.pointB.name}, "${greenMain}")`,
|
|
205
|
+
];
|
|
206
|
+
return ggbAnswer;
|
|
207
|
+
};
|
|
208
|
+
const getCorrectionGGBOptions = (identifiers) => {
|
|
209
|
+
const points = Object.values(identifiers.pointsDict).map((p) => PointConstructor.fromIdentifiers(p));
|
|
210
|
+
const ggb = new GeogebraConstructor({
|
|
211
|
+
hideAxes: true,
|
|
212
|
+
isGridSimple: true,
|
|
213
|
+
commands: getGGBAnswer(identifiers),
|
|
214
|
+
fontSize: 16,
|
|
215
|
+
});
|
|
216
|
+
return ggb.getOptions({
|
|
217
|
+
coords: ggb.getCoordsForPoints(points),
|
|
218
|
+
});
|
|
219
|
+
};
|
|
220
|
+
const getStudentGGBOptions = (identifiers) => {
|
|
221
|
+
const points = Object.values(identifiers.pointsDict).map((p) => PointConstructor.fromIdentifiers(p));
|
|
222
|
+
const studentGGB = new GeogebraConstructor({
|
|
223
|
+
commands: getGGBCoreCommands(identifiers),
|
|
224
|
+
hideGrid: true,
|
|
225
|
+
hideAxes: true,
|
|
226
|
+
customToolBar: toolBarConstructor({
|
|
227
|
+
segment: true,
|
|
228
|
+
}),
|
|
229
|
+
forbidShiftDragZoom: true,
|
|
230
|
+
});
|
|
231
|
+
return studentGGB.getOptions({
|
|
232
|
+
coords: studentGGB.getCoordsForPoints(points),
|
|
233
|
+
});
|
|
234
|
+
};
|
|
235
|
+
const isGGBAnswerValid = (ans, { ggbAnswer, ...identifiers }) => {
|
|
236
|
+
const studentCommands = ans;
|
|
237
|
+
function getStudentPointsDictFromStudentCommands(commands) {
|
|
238
|
+
const regexPoint = new RegExp(`(?<name>\\w+)\\s?=\\s?\\((?<strX>-?\\d+(\\.\\d+)?),\\s?(?<strY>-?\\d+(\\.\\d+)?)\\)`);
|
|
239
|
+
const pointsDict = commands.reduce((acc, command) => {
|
|
240
|
+
const match = command.match(regexPoint);
|
|
241
|
+
if (match && match.groups) {
|
|
242
|
+
const { name, strX, strY } = match.groups;
|
|
243
|
+
const [x, y] = [strX, strY].map((strZ) => parseFloat(strZ));
|
|
244
|
+
const point = new Point(name, x, y);
|
|
245
|
+
acc[name] = point;
|
|
246
|
+
}
|
|
247
|
+
return acc;
|
|
248
|
+
}, {});
|
|
249
|
+
console.log("pointsDict", pointsDict);
|
|
250
|
+
return pointsDict;
|
|
251
|
+
}
|
|
252
|
+
function getStudentSegmentsDictFromStudentCommands(commands) {
|
|
253
|
+
const studentPointsDict = getStudentPointsDictFromStudentCommands(commands);
|
|
254
|
+
const regexSegment = new RegExp(`(?<name>\\w+)\\s?=\\s?Segment\\[(?<namePointA>\\w+),\\s?(?<namePointB>\\w+)\\]`);
|
|
255
|
+
const segmentsDict = studentCommands.reduce((acc, command) => {
|
|
256
|
+
const match = command.match(regexSegment);
|
|
257
|
+
if (match && match.groups) {
|
|
258
|
+
const { name, namePointA, namePointB } = match.groups;
|
|
259
|
+
const segment = new Segment(studentPointsDict[namePointA], studentPointsDict[namePointB]);
|
|
260
|
+
acc[name] = segment;
|
|
261
|
+
}
|
|
262
|
+
return acc;
|
|
263
|
+
}, {});
|
|
264
|
+
console.log("segmentsDict", segmentsDict);
|
|
265
|
+
return segmentsDict;
|
|
266
|
+
}
|
|
267
|
+
const isSegmentValid = () => {
|
|
268
|
+
const studentSegmentDict = getStudentSegmentsDictFromStudentCommands(studentCommands);
|
|
269
|
+
if (Object.keys(studentSegmentDict).length !== 1) {
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
const segmentStudent = Object.values(studentSegmentDict)[0];
|
|
273
|
+
const segmentDst = getSegmentDst(identifiers);
|
|
274
|
+
return ((segmentStudent.pointA.distanceTo(segmentDst.pointA) < 0.1 &&
|
|
275
|
+
segmentStudent.pointB.distanceTo(segmentDst.pointB) < 0.1) ||
|
|
276
|
+
(segmentStudent.pointB.distanceTo(segmentDst.pointA) < 0.1 &&
|
|
277
|
+
segmentStudent.pointA.distanceTo(segmentDst.pointB) < 0.1));
|
|
278
|
+
};
|
|
279
|
+
return isSegmentValid();
|
|
280
|
+
};
|
|
281
|
+
const getPinSegmentFromRotationQuestion = () => {
|
|
282
|
+
const namesPool = shuffle("ABCDEFGHIJKLMNPQRST".split(""));
|
|
283
|
+
const snowflakeDict = createSnowflakeDict(namesPool, randint(-30, 30));
|
|
284
|
+
const pointsDict = Object.fromEntries(snowflakeDict.points.map((point) => [point.name, point.toIdentifiers()]));
|
|
285
|
+
const segments = snowflakeDict.segments.map(([pointA, pointB]) => `${pointA.name}${pointB.name}`);
|
|
286
|
+
function createRandomTransformationIds(points) {
|
|
287
|
+
return createRandomRotateTransformationIds(points);
|
|
288
|
+
}
|
|
289
|
+
const angleInDegreesPool = [
|
|
290
|
+
...new Set([...Array(4).keys()]
|
|
291
|
+
.map((i) => (i + 1) * 60)
|
|
292
|
+
.flatMap((angleInDegrees) => [angleInDegrees, -angleInDegrees])),
|
|
293
|
+
];
|
|
294
|
+
function createRandomRotateTransformationIds(points) {
|
|
295
|
+
const [point1] = [random(points)].map((point) => point.toIdentifiers());
|
|
296
|
+
return {
|
|
297
|
+
type: "rotation",
|
|
298
|
+
point1,
|
|
299
|
+
angleInDegrees: random(angleInDegreesPool).toTree().toIdentifiers(),
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
function applyTransformation(transformationIds, pointSrc) {
|
|
303
|
+
switch (transformationIds.type) {
|
|
304
|
+
case "rotation":
|
|
305
|
+
{
|
|
306
|
+
const pointCenter = PointConstructor.fromIdentifiers(transformationIds.point1);
|
|
307
|
+
const angleInDegrees = NodeConstructor.fromIdentifiers(transformationIds.angleInDegrees);
|
|
308
|
+
return rotatePoint(pointSrc, multiply(PiNode, frac(angleInDegrees, 180)).evaluate(), pointCenter, "N");
|
|
309
|
+
}
|
|
310
|
+
break;
|
|
311
|
+
default:
|
|
312
|
+
throw new Error("Unsupported transformation type: " + transformationIds.type);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
function findCorrespondingSnowflakePoint(point) {
|
|
316
|
+
return snowflakeDict.points.find((pointSnowflake) => {
|
|
317
|
+
const distance = point.distanceTo(pointSnowflake);
|
|
318
|
+
return distance < 0.0001;
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
let transformationIdsCandidate;
|
|
322
|
+
let pointsSrc;
|
|
323
|
+
let pointsDst;
|
|
324
|
+
let counter = -1;
|
|
325
|
+
let isValidTransformationIds = false;
|
|
326
|
+
while (!isValidTransformationIds && counter < 100) {
|
|
327
|
+
counter++;
|
|
328
|
+
transformationIdsCandidate = createRandomTransformationIds(snowflakeDict.points);
|
|
329
|
+
pointsSrc = randomMany(snowflakeDict.points, 2);
|
|
330
|
+
const pointsDstFromTransformation = pointsSrc.map((pointSrc) => applyTransformation(transformationIdsCandidate, pointSrc));
|
|
331
|
+
const pointsDstWrtExistingPoints = pointsDstFromTransformation
|
|
332
|
+
.map(findCorrespondingSnowflakePoint)
|
|
333
|
+
.filter((p) => p !== undefined);
|
|
334
|
+
if (pointsDstWrtExistingPoints.length === pointsSrc.length) {
|
|
335
|
+
pointsDst = pointsDstWrtExistingPoints;
|
|
336
|
+
isValidTransformationIds = true;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
if (!isValidTransformationIds) {
|
|
340
|
+
const defaultTransformationIds = {
|
|
341
|
+
type: "rotation",
|
|
342
|
+
point1: snowflakeDict.points[0].toIdentifiers(),
|
|
343
|
+
angleInDegrees: (120).toTree().toIdentifiers(),
|
|
344
|
+
};
|
|
345
|
+
transformationIdsCandidate = defaultTransformationIds;
|
|
346
|
+
pointsSrc = [snowflakeDict.points[2], snowflakeDict.points[3]];
|
|
347
|
+
pointsDst = [snowflakeDict.points[4], snowflakeDict.points[5]];
|
|
348
|
+
}
|
|
349
|
+
const [nameObjSrc, nameObjDst] = [pointsSrc, pointsDst].map((points) => points.map((point) => point.name).join(""));
|
|
350
|
+
const identifiers = {
|
|
351
|
+
pointsDict,
|
|
352
|
+
segments,
|
|
353
|
+
transformationIds: transformationIdsCandidate,
|
|
354
|
+
nameObjSrc,
|
|
355
|
+
nameObjDst,
|
|
356
|
+
};
|
|
357
|
+
return getQuestionFromIdentifiers(identifiers);
|
|
358
|
+
};
|
|
359
|
+
const getQuestionFromIdentifiers = (identifiers) => {
|
|
360
|
+
const question = {
|
|
361
|
+
ggbAnswer: getGGBAnswer(identifiers),
|
|
362
|
+
instruction: getInstruction(identifiers),
|
|
363
|
+
keys: [],
|
|
364
|
+
answerFormat: "tex",
|
|
365
|
+
identifiers,
|
|
366
|
+
studentGgbOptions: getStudentGGBOptions(identifiers),
|
|
367
|
+
hint: getHint(identifiers),
|
|
368
|
+
correction: getCorrection(identifiers),
|
|
369
|
+
correctionGgbOptions: getCorrectionGGBOptions(identifiers),
|
|
370
|
+
};
|
|
371
|
+
return question;
|
|
372
|
+
};
|
|
373
|
+
export const pinSegmentFromRotation = {
|
|
374
|
+
id: "pinSegmentFromRotation",
|
|
375
|
+
connector: "=",
|
|
376
|
+
label: "Placer l'image d'un segment par une rotation",
|
|
377
|
+
isSingleStep: true,
|
|
378
|
+
generator: (nb, opts) => getDistinctQuestions(() => getPinSegmentFromRotationQuestion(opts), nb),
|
|
379
|
+
ggbTimer: 60,
|
|
380
|
+
isGGBAnswerValid,
|
|
381
|
+
subject: "Mathématiques",
|
|
382
|
+
answerType: "GGB",
|
|
383
|
+
getQuestionFromIdentifiers,
|
|
384
|
+
getHint,
|
|
385
|
+
getCorrection,
|
|
386
|
+
hasHintAndCorrection: true,
|
|
387
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Exercise } from "../../../../exercises/exercise.js";
|
|
2
|
+
import { PointIdentifiers } from "../../../../math/geometry/point.js";
|
|
3
|
+
import { NodeIdentifiers } from "../../../../tree/nodes/nodeConstructor.js";
|
|
4
|
+
type TransformationIdentifiers = {
|
|
5
|
+
type: string;
|
|
6
|
+
point1: PointIdentifiers;
|
|
7
|
+
angleInDegrees: NodeIdentifiers;
|
|
8
|
+
};
|
|
9
|
+
type Identifiers = {
|
|
10
|
+
pointsDict: Record<string, PointIdentifiers>;
|
|
11
|
+
segments: string[];
|
|
12
|
+
transformationIds: TransformationIdentifiers;
|
|
13
|
+
namePointSrc: string;
|
|
14
|
+
namePointDst: string;
|
|
15
|
+
};
|
|
16
|
+
export declare const recognizeAngleFromRotation: Exercise<Identifiers>;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=recognizeAngleFromRotation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recognizeAngleFromRotation.d.ts","sourceRoot":"","sources":["../../../../../src/exercises/math/geometry/euclidian/recognizeAngleFromRotation.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EAUT,MAAM,6BAA6B,CAAC;AAKrC,OAAO,EAGL,gBAAgB,EACjB,MAAM,8BAA8B,CAAC;AAMtC,OAAO,EAEL,eAAe,EAChB,MAAM,qCAAqC,CAAC;AAuI7C,KAAK,yBAAyB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,gBAAgB,CAAC;IACzB,cAAc,EAAE,eAAe,CAAC;CACjC,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC7C,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,iBAAiB,EAAE,yBAAyB,CAAC;IAC7C,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AA8SF,eAAO,MAAM,0BAA0B,EAAE,QAAQ,CAAC,WAAW,CAgB5D,CAAC"}
|