math-exercises 2.0.18 → 2.0.20

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.
@@ -48,7 +48,7 @@ exports.firstDegreeEquation = {
48
48
  connector: "=",
49
49
  label: "Résoudre une équation du premier degré du type $\\frac{a}{x} = b$",
50
50
  levels: ["2nde", "1reESM", "1reSpé"],
51
- sections: ["Équations"],
51
+ sections: ["Équations", "Fonction inverse", "Fonctions de référence"],
52
52
  isSingleStep: false,
53
53
  generator: (nb) => (0, getDistinctQuestions_1.getDistinctQuestions)(getFirstDegreeEquation, nb),
54
54
  getPropositions,
@@ -56,7 +56,7 @@ const isAnswerValid = (ans, { answer }) => {
56
56
  exports.applyPercent = {
57
57
  id: "applyPercent",
58
58
  connector: "=",
59
- label: "Appliquer un pourcentage d'augmentation ou de diminution.",
59
+ label: "Appliquer un pourcentage d'augmentation ou de diminution",
60
60
  levels: [
61
61
  "4ème",
62
62
  "3ème",
@@ -52,7 +52,7 @@ const getPropositions = (n, { answer }) => {
52
52
  return (0, shuffle_1.shuffle)(propositions);
53
53
  };
54
54
  const isAnswerValid = (ans, { mainValue, isCos }) => {
55
- const remarkableValue = remarkableValues_1.remarkableTrigoValues.find((point) => point.angle.evaluate({}) === mainValue);
55
+ const remarkableValue = remarkableValues_1.remarkableTrigoValues.find((point) => Math.abs(point.angle.evaluate({}) - mainValue) < 0.0001);
56
56
  const answer = isCos ? remarkableValue.cos : remarkableValue.sin;
57
57
  const texs = answer.toAllValidTexs({
58
58
  allowFractionToDecimal: true,
package/lib/server.js CHANGED
@@ -35,24 +35,22 @@ const express_1 = __importDefault(require("express"));
35
35
  const body_parser_1 = __importDefault(require("body-parser"));
36
36
  const dotenv_1 = __importDefault(require("dotenv"));
37
37
  const cors_1 = __importDefault(require("cors"));
38
- const addNode_1 = require("./tree/nodes/operators/addNode");
39
- const numberNode_1 = require("./tree/nodes/numbers/numberNode");
40
- const powerNode_1 = require("./tree/nodes/operators/powerNode");
41
- const sqrtNode_1 = require("./tree/nodes/functions/sqrtNode");
42
- const multiplyNode_1 = require("./tree/nodes/operators/multiplyNode");
43
38
  const jsonParser = body_parser_1.default.json();
44
39
  const allExercises = [...exercises];
45
40
  const runServer = () => {
46
41
  dotenv_1.default.config();
47
42
  const app = (0, express_1.default)();
48
43
  app.use((0, cors_1.default)());
49
- console.log(exercises.length + " exercices");
50
- const firstTerm = new multiplyNode_1.MultiplyNode(new numberNode_1.NumberNode(3), new sqrtNode_1.SqrtNode(new numberNode_1.NumberNode(3)));
51
- const secondTerm = new numberNode_1.NumberNode(5);
52
- const answer = new addNode_1.AddNode(new powerNode_1.SquareNode(firstTerm), new addNode_1.AddNode(new powerNode_1.SquareNode(secondTerm), new multiplyNode_1.MultiplyNode(new numberNode_1.NumberNode(2), new multiplyNode_1.MultiplyNode(firstTerm, secondTerm))))
53
- .simplify()
54
- .toTex();
55
- console.log(answer);
44
+ // const string = "\\frac{9}{12}";
45
+ // const a = string.match(/^[0-9]+,?[0-9]*/);
46
+ // const before = Date.now();
47
+ // const parsed = parseLatex(string);
48
+ // console.log("res", parsed);
49
+ // console.log(parsed?.toTex());
50
+ // console.log(parsed?.simplify().toTex());
51
+ // console.log(parsed?.evaluate({ x: 1 }));
52
+ // console.log("time", Date.now() - before);
53
+ // tokenize(string);
56
54
  app.get("/", (req, res) => {
57
55
  res.json(allExercises);
58
56
  });
@@ -19,7 +19,7 @@ export declare class OppositeNode implements FunctionNode {
19
19
  */
20
20
  toAllValidTexs(opts?: NodeOptions): string[];
21
21
  evaluate(vars: Record<string, number>): number;
22
- simplify(opts?: SimplifyOptions): OppositeNode;
22
+ simplify(opts?: SimplifyOptions): AlgebraicNode;
23
23
  equals(node: AlgebraicNode): boolean;
24
24
  }
25
25
  //# sourceMappingURL=oppositeNode.d.ts.map
@@ -6,6 +6,7 @@ const node_1 = require("../node");
6
6
  const operatorNode_1 = require("../operators/operatorNode");
7
7
  const functionNode_1 = require("./functionNode");
8
8
  const numberNode_1 = require("../numbers/numberNode");
9
+ const multiplyNode_1 = require("../operators/multiplyNode");
9
10
  const fractionNode_1 = require("../operators/fractionNode");
10
11
  function isOppositeNode(a) {
11
12
  return (0, functionNode_1.isFunctionNode)(a) && a.id === functionNode_1.FunctionsIds.opposite;
@@ -70,7 +71,7 @@ class OppositeNode {
70
71
  return -this.child.evaluate(vars);
71
72
  }
72
73
  simplify(opts) {
73
- return new OppositeNode(this.child.simplify(opts));
74
+ return new multiplyNode_1.MultiplyNode(new numberNode_1.NumberNode(-1), this.child).simplify(opts);
74
75
  }
75
76
  equals(node) {
76
77
  return isOppositeNode(node) && node.child.equals(this.child);
@@ -1 +1 @@
1
- {"version":3,"file":"powerNode.d.ts","sourceRoot":"","sources":["../../../../src/tree/nodes/operators/powerNode.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAkB,MAAM,gBAAgB,CAAC;AAG3E,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAOlE,wBAAgB,WAAW,CAAC,CAAC,EAAE,IAAI,GAAG,CAAC,IAAI,SAAS,CAEnD;AAED,qBAAa,SAAU,YAAW,YAAY;IAC5C,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,EAAE,EAAE,WAAW,CAAC;IAChB,SAAS,EAAE,aAAa,CAAC;IACzB,UAAU,EAAE,aAAa,CAAC;IAC1B,IAAI,EAAE,QAAQ,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;gBAEjB,SAAS,EAAE,aAAa,EACxB,UAAU,EAAE,aAAa,EACzB,IAAI,CAAC,EAAE,WAAW;IAUpB,YAAY,IAAI,MAAM;IAItB,iBAAiB;IAqBjB,cAAc,IAAI,MAAM,EAAE;IAI1B,KAAK,IAAI,MAAM;IAuBf,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IA+FrC,QAAQ,CAAC,IAAI,CAAC,EAAE,eAAe,GAAG,aAAa;IAO/C,MAAM,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO;CAOrC;AAED,qBAAa,UAAW,SAAQ,SAAS;gBAC3B,KAAK,EAAE,aAAa,EAAE,IAAI,CAAC,EAAE,WAAW;CAGrD"}
1
+ {"version":3,"file":"powerNode.d.ts","sourceRoot":"","sources":["../../../../src/tree/nodes/operators/powerNode.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAkB,MAAM,gBAAgB,CAAC;AAG3E,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAOlE,wBAAgB,WAAW,CAAC,CAAC,EAAE,IAAI,GAAG,CAAC,IAAI,SAAS,CAEnD;AAED,qBAAa,SAAU,YAAW,YAAY;IAC5C,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,EAAE,EAAE,WAAW,CAAC;IAChB,SAAS,EAAE,aAAa,CAAC;IACzB,UAAU,EAAE,aAAa,CAAC;IAC1B,IAAI,EAAE,QAAQ,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;gBAEjB,SAAS,EAAE,aAAa,EACxB,UAAU,EAAE,aAAa,EACzB,IAAI,CAAC,EAAE,WAAW;IAUpB,YAAY,IAAI,MAAM;IAItB,iBAAiB;IAqBjB,cAAc,IAAI,MAAM,EAAE;IAI1B,KAAK,IAAI,MAAM;IAuBf,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IA+FrC,QAAQ,CAAC,IAAI,CAAC,EAAE,eAAe,GAAG,aAAa;IAY/C,MAAM,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO;CAOrC;AAED,qBAAa,UAAW,SAAQ,SAAS;gBAC3B,KAAK,EAAE,aAAa,EAAE,IAAI,CAAC,EAAE,WAAW;CAGrD"}
@@ -157,11 +157,14 @@ class PowerNode {
157
157
  // // puissances négatives ?
158
158
  // }
159
159
  simplify(opts) {
160
+ const leftSimplified = this.leftChild.simplify(opts);
161
+ const rightSimplified = this.rightChild.simplify(opts);
162
+ const copy = new PowerNode(leftSimplified, rightSimplified, this.opts);
160
163
  //! temporaire
161
- if ((0, numberNode_1.isNumberNode)(this.rightChild) && this.rightChild.value === 2) {
162
- return new multiplyNode_1.MultiplyNode(this.leftChild, this.leftChild).simplify(opts);
164
+ if ((0, numberNode_1.isNumberNode)(copy.rightChild) && copy.rightChild.value === 2) {
165
+ return new multiplyNode_1.MultiplyNode(copy.leftChild, copy.leftChild).simplify(opts);
163
166
  }
164
- return this;
167
+ return copy;
165
168
  }
166
169
  equals(node) {
167
170
  return (isPowerNode(node) &&
@@ -43,7 +43,7 @@ class SubstractNode {
43
43
  [operatorNode_1.OperatorIds.add, operatorNode_1.OperatorIds.substract].includes(this.rightChild.id)) ||
44
44
  rightTex[0] === "-";
45
45
  if (needBrackets)
46
- rightTex = `(${rightTex})`;
46
+ rightTex = `\\left(${rightTex}\\right)`;
47
47
  return `${leftTex}-${rightTex}`;
48
48
  }
49
49
  evaluate(vars) {
@@ -0,0 +1,4 @@
1
+ import { AlgebraicNode } from "../nodes/algebraicNode";
2
+ export declare const tokenize: (latex: string) => string[];
3
+ export declare const parseLatex: (latex: string) => AlgebraicNode;
4
+ //# sourceMappingURL=latexParser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"latexParser.d.ts","sourceRoot":"","sources":["../../../src/tree/parsers/latexParser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AA0CvD,eAAO,MAAM,QAAQ,UAAW,MAAM,aA4BrC,CAAC;AAEF,eAAO,MAAM,UAAU,UAAW,MAAM,kBAavC,CAAC"}
@@ -0,0 +1,287 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseLatex = exports.tokenize = void 0;
4
+ const oppositeNode_1 = require("../nodes/functions/oppositeNode");
5
+ const sqrtNode_1 = require("../nodes/functions/sqrtNode");
6
+ const numberNode_1 = require("../nodes/numbers/numberNode");
7
+ const addNode_1 = require("../nodes/operators/addNode");
8
+ const fractionNode_1 = require("../nodes/operators/fractionNode");
9
+ const multiplyNode_1 = require("../nodes/operators/multiplyNode");
10
+ const powerNode_1 = require("../nodes/operators/powerNode");
11
+ const substractNode_1 = require("../nodes/operators/substractNode");
12
+ const variableNode_1 = require("../nodes/variables/variableNode");
13
+ //cmd that needs a child, like \exp{3}
14
+ const functions = [
15
+ "\\exp",
16
+ "\\sqrt",
17
+ "\\log",
18
+ "\\ln",
19
+ "\\cos",
20
+ "\\sin",
21
+ "\\frac",
22
+ ];
23
+ const operators = ["+", "-", "\\div", "\\times", "^"];
24
+ const isDyck = (tokens) => {
25
+ const brackets = tokens.filter((el) => el === "(" || el === ")");
26
+ while (brackets.length) {
27
+ const rightIndex = brackets.findIndex((el) => el == ")");
28
+ if (rightIndex === -1 || rightIndex === 0)
29
+ return false;
30
+ let leftIndex = -1;
31
+ for (let i = rightIndex - 1; i > -1; i--) {
32
+ if (brackets[i] === "(") {
33
+ leftIndex = i;
34
+ }
35
+ break;
36
+ }
37
+ if (leftIndex === -1)
38
+ return false;
39
+ brackets.splice(rightIndex, 1);
40
+ brackets.splice(leftIndex, 1);
41
+ }
42
+ return true;
43
+ };
44
+ const tokenize = (latex) => {
45
+ const tokens = [];
46
+ for (let i = 0; i < latex.length; i++) {
47
+ const char = latex[i];
48
+ if (char === " ")
49
+ continue;
50
+ const match = char.match(/[\+\-\(\)\^a-zA-Z_=\{\}]/);
51
+ if (match) {
52
+ tokens.push(char);
53
+ continue;
54
+ }
55
+ const substring = latex.substring(i);
56
+ const nbMatch = substring.match(/^[0-9]+,?[0-9]*/); //x nombres éventuellement séparés par une virgule
57
+ if (nbMatch) {
58
+ tokens.push(nbMatch[0].replace(",", "."));
59
+ i += nbMatch[0].length - 1;
60
+ continue;
61
+ }
62
+ const cmdMatch = substring.match(/^\\[a-z]+/i);
63
+ if (cmdMatch) {
64
+ tokens.push(cmdMatch[0]);
65
+ i += cmdMatch[0].length - 1;
66
+ continue;
67
+ }
68
+ }
69
+ return tokens;
70
+ };
71
+ exports.tokenize = tokenize;
72
+ const parseLatex = (latex) => {
73
+ const formattedLatex = latex
74
+ .replaceAll("\\left", "")
75
+ .replaceAll("\\right", "");
76
+ const tokens = (0, exports.tokenize)(formattedLatex);
77
+ if (!isDyck(tokens))
78
+ throw Error("Problème de parenthèses.");
79
+ try {
80
+ const parsed = buildTree(tokens);
81
+ return parsed;
82
+ }
83
+ catch (err) {
84
+ throw err;
85
+ }
86
+ };
87
+ exports.parseLatex = parseLatex;
88
+ const buildTree = (tokens) => {
89
+ let currentDepth = 0;
90
+ let maxDepth = 0;
91
+ const depthedTokens = [];
92
+ for (const token of tokens) {
93
+ if (token === "(" || token === "{")
94
+ currentDepth++;
95
+ depthedTokens.push({
96
+ token,
97
+ depth: currentDepth,
98
+ });
99
+ if (currentDepth > maxDepth)
100
+ maxDepth = currentDepth;
101
+ if (token === ")" || token === "}")
102
+ currentDepth--;
103
+ }
104
+ console.log("depthed: ", depthedTokens);
105
+ while (true) {
106
+ if (maxDepth === 0) {
107
+ const tree = buildTreeForSameDepthTokens(depthedTokens.map((el) => el.token));
108
+ return tree;
109
+ }
110
+ for (let i = 0; i < depthedTokens.length; i++) {
111
+ const token = depthedTokens[i];
112
+ if (token.depth < maxDepth)
113
+ continue;
114
+ //le token est forcément ici ( ou {
115
+ //et on est sur qu'il n'y a aucun autre nestage à l'intérieur
116
+ const endIndex = depthedTokens.findIndex((el, index) => index > i && (el.token === ")" || el.token === "}"));
117
+ const tree = buildTreeForSameDepthTokens(depthedTokens.slice(i + 1, endIndex).map((el) => el.token));
118
+ depthedTokens.splice(i, endIndex - i + 1, {
119
+ token: tree,
120
+ depth: token.depth - 1,
121
+ });
122
+ console.log(`depthed after iter ${i}`, depthedTokens);
123
+ }
124
+ maxDepth--;
125
+ }
126
+ };
127
+ const buildTreeForSameDepthTokens = (tokens) => {
128
+ console.log("start: ", tokens);
129
+ let tempTokens = [];
130
+ for (let i = 0; i < tokens.length; i++) {
131
+ const token = tokens[i];
132
+ if (typeof token !== "string") {
133
+ tempTokens[i] = token;
134
+ continue;
135
+ }
136
+ if (token[0].match(/[0-9]/)) {
137
+ tempTokens[i] = new numberNode_1.NumberNode(Number(token));
138
+ }
139
+ else if (token[0].match(/[a-z]/i))
140
+ tempTokens[i] = new variableNode_1.VariableNode(token);
141
+ //! les fonctions qui attendent un child ne sont pas encore parsées
142
+ else if (functions.includes(token)) {
143
+ tempTokens[i] = token;
144
+ }
145
+ //!idem pour les opérators
146
+ else if (operators.includes(token))
147
+ tempTokens[i] = token;
148
+ else
149
+ throw Error(`token not implemented: ${token}`);
150
+ }
151
+ console.log("after parses : ", tempTokens);
152
+ //1 build les fct
153
+ for (let i = 0; i < tempTokens.length; i++) {
154
+ if (typeof tempTokens[i] !== "string")
155
+ continue;
156
+ const token = tempTokens[i];
157
+ if (functions.includes(token)) {
158
+ if (typeof tempTokens[i + 1] === "string")
159
+ throw Error(`Function child has not been parsed at index ${i}`);
160
+ switch (token) {
161
+ case "\\sqrt":
162
+ tempTokens[i] = new sqrtNode_1.SqrtNode(tempTokens[i + 1]);
163
+ tempTokens.splice(i + 1, 1);
164
+ break;
165
+ case "\\frac":
166
+ tempTokens[i] = new fractionNode_1.FractionNode(tempTokens[i + 1], tempTokens[i + 2]);
167
+ tempTokens.splice(i + 1, 2);
168
+ }
169
+ }
170
+ if (token === "^") {
171
+ if (!tempTokens[i - 1] ||
172
+ typeof tempTokens[i - 1] === "string" ||
173
+ !tempTokens[i + 1] ||
174
+ typeof tempTokens[i + 1] === "string")
175
+ throw Error("Error parsing power node");
176
+ else {
177
+ tempTokens[i - 1] = new powerNode_1.PowerNode(tempTokens[i - 1], tempTokens[i + 1]);
178
+ tempTokens.splice(i, 2);
179
+ }
180
+ }
181
+ }
182
+ //2 build les opposites
183
+ for (let i = 0; i < tempTokens.length; i++) {
184
+ const token = tempTokens[i];
185
+ if (token === "-") {
186
+ if (i === 0 ||
187
+ tempTokens[i - 1] === "\\times" ||
188
+ tempTokens[i - 1] === "+" ||
189
+ tempTokens[i - 1] === "-") {
190
+ //faire la liste des - conéscutifs
191
+ let j = i + 1;
192
+ while (tempTokens[j] === "-" && j < tempTokens.length) {
193
+ j++;
194
+ }
195
+ if (j === tempTokens.length)
196
+ throw Error("Nothing after minus");
197
+ const nextToken = tempTokens[j];
198
+ //! à ce stade, le nextToken est soit un node, soit : + ou \\times
199
+ //!on fait ici le choix d'interdire -+x
200
+ if (typeof nextToken === "string") {
201
+ throw Error("Opposé pas clair");
202
+ }
203
+ const oppositeCount = j - i;
204
+ let node = nextToken;
205
+ for (let k = 0; k < oppositeCount; k++) {
206
+ node = new oppositeNode_1.OppositeNode(node);
207
+ }
208
+ tempTokens[i] = node;
209
+ tempTokens.splice(i + 1, oppositeCount);
210
+ }
211
+ }
212
+ }
213
+ console.log("after fcts: ", tempTokens);
214
+ //3 build les *
215
+ let currentProduct;
216
+ let currentProductStartIndex;
217
+ for (let i = 0; i < tempTokens.length; i++) {
218
+ const token = tempTokens[i];
219
+ if (token === "\\times")
220
+ continue;
221
+ //la seule chose qui arrete un produit est + ou -
222
+ //y a t il d'autres cas ?
223
+ //? rappel ici on est sur une expression de niveau uniforme (sans parentheses ni childs)
224
+ if (token === "+" || token === "-") {
225
+ if (currentProduct &&
226
+ (0, multiplyNode_1.isMultiplyNode)(currentProduct) &&
227
+ currentProductStartIndex !== undefined) {
228
+ tempTokens[currentProductStartIndex] = currentProduct;
229
+ tempTokens.splice(currentProductStartIndex + 1, i - currentProductStartIndex - 1);
230
+ i = currentProductStartIndex + 1;
231
+ }
232
+ currentProduct = undefined;
233
+ currentProductStartIndex = undefined;
234
+ continue;
235
+ }
236
+ else {
237
+ if (currentProduct) {
238
+ currentProduct = new multiplyNode_1.MultiplyNode(currentProduct, token);
239
+ }
240
+ else {
241
+ currentProduct = token;
242
+ currentProductStartIndex = i;
243
+ }
244
+ }
245
+ }
246
+ if (currentProduct &&
247
+ (0, multiplyNode_1.isMultiplyNode)(currentProduct) &&
248
+ currentProductStartIndex !== undefined) {
249
+ tempTokens[currentProductStartIndex] = currentProduct;
250
+ tempTokens.splice(currentProductStartIndex + 1, tempTokens.length - 1 - currentProductStartIndex);
251
+ }
252
+ //4 build les +
253
+ let currentAdd;
254
+ console.log("beforeAdd", tempTokens);
255
+ for (let i = 0; i < tempTokens.length; i++) {
256
+ const token = tempTokens[i];
257
+ if (!currentAdd) {
258
+ if (typeof token === "string") {
259
+ if (token === "+" || token === "-") {
260
+ throw Error("Addition with no first term");
261
+ }
262
+ else
263
+ throw Error(`unexpected non parsed token ${token}`);
264
+ }
265
+ else {
266
+ currentAdd = token;
267
+ }
268
+ }
269
+ else {
270
+ if (typeof token !== "string" || (token !== "+" && token !== "-")) {
271
+ throw Error(`unexpected consecutive nodes without addition : ${token}`);
272
+ }
273
+ const next = tempTokens[i + 1];
274
+ if (typeof next === "string") {
275
+ throw Error(`unexpected non parsed token ${next}`);
276
+ }
277
+ else {
278
+ if (token === "+")
279
+ currentAdd = new addNode_1.AddNode(currentAdd, next);
280
+ else
281
+ currentAdd = new substractNode_1.SubstractNode(currentAdd, next);
282
+ i++;
283
+ }
284
+ }
285
+ }
286
+ return currentAdd;
287
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "math-exercises",
3
- "version": "2.0.18",
3
+ "version": "2.0.20",
4
4
  "description": "Math exercises generator for middle school and high school",
5
5
  "main": "lib/index.js",
6
6
  "files": [