From 1c3bf28755a54a445c70f718e3c988ffdfaf1ce1 Mon Sep 17 00:00:00 2001 From: Camarillas Date: Sun, 19 Mar 2023 20:14:10 +0300 Subject: [PATCH 1/4] Update mathOperators.ts --- src/lesson2/mathOperators.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lesson2/mathOperators.ts b/src/lesson2/mathOperators.ts index af8eb770..d3427395 100644 --- a/src/lesson2/mathOperators.ts +++ b/src/lesson2/mathOperators.ts @@ -25,6 +25,7 @@ export const mathOperators: { [key: string]: ScalarOperationType } = { "/": div, "+": add, "-": minus, + "^": minus, }; export const mathPriorities: number[] = [1, 2]; From a5f0d2252ac82c6618b9b5421fdc2984dec6d733 Mon Sep 17 00:00:00 2001 From: Camarillas Date: Sun, 19 Mar 2023 20:41:36 +0300 Subject: [PATCH 2/4] Addad Pow Pow --- src/lesson2/mathOperators.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/lesson2/mathOperators.ts b/src/lesson2/mathOperators.ts index d3427395..cc432035 100644 --- a/src/lesson2/mathOperators.ts +++ b/src/lesson2/mathOperators.ts @@ -20,12 +20,17 @@ export const minus: ScalarOperationType = ( second: number ): number => first - second; +export const pow: ScalarOperationType = ( + first: number, + second: number +): number => Math.pow(first, second); + export const mathOperators: { [key: string]: ScalarOperationType } = { "*": mul, "/": div, "+": add, "-": minus, - "^": minus, + "^": pow, }; export const mathPriorities: number[] = [1, 2]; @@ -34,6 +39,7 @@ const [FIRST, SECOND] = mathPriorities; export const mathOperatorsPriorities: { [key: string]: number } = { "*": FIRST, + "^": FIRST, "/": FIRST, "+": SECOND, "-": SECOND, From f3bc3cd39e553699a5c526355b5d19e40ad16f36 Mon Sep 17 00:00:00 2001 From: Camarillas Date: Sun, 19 Mar 2023 21:56:10 +0300 Subject: [PATCH 3/4] check Operator function --- src/lesson2/helpers.ts | 7 +++++++ src/lesson2/parser.ts | 6 ++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/lesson2/helpers.ts b/src/lesson2/helpers.ts index b5a4b6ae..7cbab2a4 100644 --- a/src/lesson2/helpers.ts +++ b/src/lesson2/helpers.ts @@ -1 +1,8 @@ +import { + mathOperators, +} from "./mathOperators"; + export const isNumber = (item: string): boolean => !isNaN(Number(item)); + + +export const isOperator = (item: string): boolean => item in mathOperators \ No newline at end of file diff --git a/src/lesson2/parser.ts b/src/lesson2/parser.ts index 118ff662..4c50ed5c 100644 --- a/src/lesson2/parser.ts +++ b/src/lesson2/parser.ts @@ -1,4 +1,5 @@ -import { isNumber } from "./helpers"; +import { isNumber, +isOperator } from "./helpers"; import { mathOperators } from "./mathOperators"; export type ParsedLineType = (number | string)[]; @@ -13,7 +14,8 @@ export const parser = (line: string): ParsedLineType | null => { const isValidOperatorPush = isNumber(prevItem) && !isNumber(item) && - mathOperators.hasOwnProperty(item); + mathOperators.hasOwnProperty(item) && + isOperator(item); if (isValidNumberPush) { result.push(Number(item)); From 9323b6bc8911d5d85ee9245db1b8024abb984f75 Mon Sep 17 00:00:00 2001 From: Camarillas Date: Mon, 20 Mar 2023 22:09:08 +0300 Subject: [PATCH 4/4] =?UTF-8?q?=D0=A4=D0=B0=D0=BA=D1=82=D0=BE=D1=80=D0=B8?= =?UTF-8?q?=D0=B0=D0=BB,=20=D0=B2=D0=BE=D0=B7=D0=B2=D0=B5=D0=B4=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=B2=20=D1=81=D1=82=D0=B5=D0=BF=D0=B5?= =?UTF-8?q?=D0=BD=D1=8C,=20=D1=83=D1=87=D0=B5=D1=82=20=D0=BA=D0=B0=D0=B2?= =?UTF-8?q?=D1=8B=D1=87=D0=B5=D0=BA,=20=D1=83=D0=BC=D0=BD=D0=BE=D0=B6?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lesson2/engine.ts | 27 +++++++++++- src/lesson2/helpers.ts | 14 ++++-- src/lesson2/mathOperators.test.ts | 34 ++++++++++++++- src/lesson2/mathOperators.ts | 22 ++++++++-- src/lesson2/parseBrackets.test.ts | 27 ++++++++++++ src/lesson2/parseBrackets.ts | 35 +++++++++++++++ src/lesson2/parser.test.ts | 16 +++++++ src/lesson2/parser.ts | 26 ++++++++--- src/lesson2/runner.test.ts | 72 +++++++++++++++++++++++++++++++ src/lesson2/runner.ts | 11 ++++- 10 files changed, 265 insertions(+), 19 deletions(-) create mode 100644 src/lesson2/parseBrackets.test.ts create mode 100644 src/lesson2/parseBrackets.ts diff --git a/src/lesson2/engine.ts b/src/lesson2/engine.ts index 78aee1d7..edb67304 100644 --- a/src/lesson2/engine.ts +++ b/src/lesson2/engine.ts @@ -4,9 +4,27 @@ import { mathOperators, mathPriorities, mathOperatorsPriorities, + UnionOperationType, + unionOperators } from "./mathOperators"; -const [FIRST, SECOND] = mathPriorities; +const [ZERO, FIRST, SECOND] = mathPriorities; + +export const zeroPrioritiesCalc = (stack: ParsedLineType): ParsedLineType => + stack.reduce((result, item) => { + const prevItem = result[result.length - 1]; + + if (!isNumber(String(item)) && mathOperatorsPriorities[item] === ZERO) { + if (!unionOperators[item]) { + throw new TypeError("Unexpected stack!"); + } + const action = unionOperators[item] as UnionOperationType; + result = [...result.slice(0, -1), action(Number(prevItem))]; + } else { + result.push(item); + } + return result; + }, []); export const firstPrioritiesCalc = (stack: ParsedLineType): ParsedLineType => stack.reduce((result, nextItem) => { @@ -27,6 +45,8 @@ export const firstPrioritiesCalc = (stack: ParsedLineType): ParsedLineType => return result; }, []); + + export const secondPrioritiesCalc = (stack: ParsedLineType): number => stack.reduce((result, nextItem, key) => { const item = stack[key - 1]; @@ -35,8 +55,11 @@ export const secondPrioritiesCalc = (stack: ParsedLineType): number => throw new TypeError("Unexpected stack!"); } - if (!isNumber(String(item)) && mathOperatorsPriorities[item] === SECOND) { + if (!isNumber(String(item)) && + mathOperatorsPriorities[item] === SECOND && + item !== undefined) { result = mathOperators[item](Number(result), Number(nextItem)); } return result; }, Number(stack[0])); + diff --git a/src/lesson2/helpers.ts b/src/lesson2/helpers.ts index 7cbab2a4..7e52e94a 100644 --- a/src/lesson2/helpers.ts +++ b/src/lesson2/helpers.ts @@ -1,8 +1,14 @@ -import { - mathOperators, -} from "./mathOperators"; +import { mathOperators, +unionOperators } from "./mathOperators"; + +import { zeroPrioritiesCalc, + firstPrioritiesCalc, + secondPrioritiesCalc } from "./engine"; + +import { parser } from "./parser"; export const isNumber = (item: string): boolean => !isNaN(Number(item)); +export const isOperator = (item: string): boolean => item in mathOperators; -export const isOperator = (item: string): boolean => item in mathOperators \ No newline at end of file +export const isUnionOperator = (item: string): boolean => item in unionOperators; \ No newline at end of file diff --git a/src/lesson2/mathOperators.test.ts b/src/lesson2/mathOperators.test.ts index aad07e8d..4638de73 100644 --- a/src/lesson2/mathOperators.test.ts +++ b/src/lesson2/mathOperators.test.ts @@ -1,4 +1,4 @@ -import { mul, div, add, minus } from "./mathOperators"; +import { mul, div, add, minus, factorial, pow, sqr } from "./mathOperators"; describe("mathOperators test cases", () => { it("mul 1 * 2 to equal 2", () => { @@ -21,7 +21,39 @@ describe("mathOperators test cases", () => { expect(add(4, 2)).toBe(6); }); + it("add 10 + 12 to equal 22", () => { + expect(add(10, 12)).toBe(22); + }); + it("minus 4 - 2 to equal 2", () => { expect(minus(4, 2)).toBe(2); }); + + it("minus 34 - 20 to equal 14", () => { + expect(minus(34, 20)).toBe(14); + }); + + it("factorial 5 to equal 120", () => { + expect(factorial(5)).toBe(120); + }); + + it("factorial 3 to equal 6", () => { + expect(factorial(3)).toBe(6); + }); + + it("power 3 * 4 to equal 81", () => { + expect(pow(3, 4)).toBe(81); + }); + + it("power 5 * 6 to equal 15625", () => { + expect(pow(5, 6)).toBe(15625); + }); + + it("sqr 6 to equal 36", () => { + expect(sqr(6)).toBe(36); + }); + + it("sqr 10 to equal 100", () => { + expect(sqr(10)).toBe(100); + }); }); diff --git a/src/lesson2/mathOperators.ts b/src/lesson2/mathOperators.ts index cc432035..923e01c7 100644 --- a/src/lesson2/mathOperators.ts +++ b/src/lesson2/mathOperators.ts @@ -1,4 +1,7 @@ export type ScalarOperationType = (first: number, second: number) => number; +export type UnionOperationType = (first: number) => number; + +export type MathOperationType = UnionOperationType | ScalarOperationType; export const mul: ScalarOperationType = ( first: number, @@ -25,7 +28,18 @@ export const pow: ScalarOperationType = ( second: number ): number => Math.pow(first, second); -export const mathOperators: { [key: string]: ScalarOperationType } = { +export const factorial: UnionOperationType = (first: number): number => { + return first ? first * factorial(first - 1) : 1; +}; + +export const sqr: UnionOperationType = (first: number): number => pow(first, 2); + +export const unionOperators: { [key: string]: MathOperationType } = { + "!": factorial, + "**": sqr, +}; + +export const mathOperators: { [key: string]: MathOperationType } = { "*": mul, "/": div, "+": add, @@ -33,11 +47,13 @@ export const mathOperators: { [key: string]: ScalarOperationType } = { "^": pow, }; -export const mathPriorities: number[] = [1, 2]; +export const mathPriorities: number[] = [0, 1, 2]; -const [FIRST, SECOND] = mathPriorities; +const [ZERO, FIRST, SECOND] = mathPriorities; export const mathOperatorsPriorities: { [key: string]: number } = { + "!": ZERO, + "**": ZERO, "*": FIRST, "^": FIRST, "/": FIRST, diff --git a/src/lesson2/parseBrackets.test.ts b/src/lesson2/parseBrackets.test.ts new file mode 100644 index 00000000..1c0226ed --- /dev/null +++ b/src/lesson2/parseBrackets.test.ts @@ -0,0 +1,27 @@ +import { parseBrackets } from "./parseBrackets"; + +describe("parseBrackets correct cases", () => { + it("(1 + 32) * 2", () => { + expect(parseBrackets("(1 + 32) * 2")).toEqual("33 * 2"); + }); + + it("66 / (6 + 2 * 20)", () => { + expect(parseBrackets("66 / (6 + 2 * 20)")).toEqual("66 / 46"); + }); + + it("1 + 32 - 2 + 2", () => { + expect(parseBrackets("(1 + 32) - (2 + 2)")).toEqual("33 - 4"); + }); + + it("1 + (4 * (2 + 2))", () => { + expect(parseBrackets("1 + (4 * (2 + 2))")).toEqual("1 + 16"); + }); +}); + +describe("parseBrackets invalid cases", () => { + it("2 + ((1 + 33 - 2)", () => { + expect(() => parseBrackets("2 + ((1 + 33 - 2)")).toThrow( + RangeError("Invalid string length") + ); + }); +}); \ No newline at end of file diff --git a/src/lesson2/parseBrackets.ts b/src/lesson2/parseBrackets.ts new file mode 100644 index 00000000..1a7ec87e --- /dev/null +++ b/src/lesson2/parseBrackets.ts @@ -0,0 +1,35 @@ +import { parser } from "./parser"; +import { zeroPrioritiesCalc, firstPrioritiesCalc, secondPrioritiesCalc } from "./engine"; + +export const parseBrackets = (line: string): string => { + +var k = 1; + +do { +var openBracket = line.lastIndexOf("("); + if (openBracket < 0) { + k = 0; + } + else { + var closeBracket = line.indexOf(")",openBracket); + var inside = line.slice(openBracket+1,closeBracket); + var parsed = parser(inside) + + if(parsed === null) { + throw new TypeError("Unexpected string"); + } + + var zeroPriorities = zeroPrioritiesCalc(parsed) + var firstPriorities = firstPrioritiesCalc(zeroPriorities) + var secondPriorities = secondPrioritiesCalc(firstPriorities) + + var changed = secondPriorities + + line = line.substr(0, openBracket) + changed.toString() + line.substr(closeBracket + 1); + + } +} while (k==1) + +return line; + +} \ No newline at end of file diff --git a/src/lesson2/parser.test.ts b/src/lesson2/parser.test.ts index 5593e312..d898f0a6 100644 --- a/src/lesson2/parser.test.ts +++ b/src/lesson2/parser.test.ts @@ -12,6 +12,14 @@ describe("Parser correct cases", () => { it("1 + 32 - 2 + 2", () => { expect(parser("1 + 32 - 2 + 2")).toEqual([1, "+", 32, "-", 2, "+", 2]); }); + + it("1 + 32 ! - 2 + 2", () => { + expect(parser("1 + 32 ! - 2 + 2")).toEqual([1, "+", 32, "!", "-", 2, "+", 2]); + }); + + it("1 + 32 - 2 + 2 **", () => { + expect(parser("1 + 32 - 2 + 2 **")).toEqual([1, "+", 32, "-", 2, "+", 2, "**"]); + }); }); describe("Parser invalid cases", () => { @@ -24,4 +32,12 @@ describe("Parser invalid cases", () => { it("1 ! 33 - 2", () => { expect(() => parser("1 ! 33 - 2")).toThrow(TypeError("Unexpected string")); }); + + it("1 ! ++ 33 - 2", () => { + expect(() => parser("1 ! ++ 33 - 2")).toThrow(TypeError("Unexpected string")); + }); + + it("1 ! 33 - 2 /", () => { + expect(() => parser("1 ! 33 - 2 /")).toThrow(TypeError("Unexpected string")); + }); }); diff --git a/src/lesson2/parser.ts b/src/lesson2/parser.ts index 4c50ed5c..aff18bc7 100644 --- a/src/lesson2/parser.ts +++ b/src/lesson2/parser.ts @@ -1,29 +1,41 @@ -import { isNumber, -isOperator } from "./helpers"; -import { mathOperators } from "./mathOperators"; +import { isNumber, isOperator, isUnionOperator } from "./helpers"; +import { mathOperators, +unionOperators } from "./mathOperators"; + +import { parseBrackets } from "./parseBrackets"; export type ParsedLineType = (number | string)[]; export const parser = (line: string): ParsedLineType | null => { - const stack = line.split(" "); + const parsedBrackets = parseBrackets(line) + const stack = parsedBrackets.split(" "); return stack.reduce((result, item, key) => { const prevItem = stack[key - 1]; - const isValidNumberPush = !isNumber(prevItem) && isNumber(item); + const isValidNumberPush = !isNumber(prevItem) && isNumber(item) && !unionOperators.hasOwnProperty(prevItem); const isValidOperatorPush = - isNumber(prevItem) && + (isNumber(prevItem) || isUnionOperator(prevItem)) && !isNumber(item) && mathOperators.hasOwnProperty(item) && isOperator(item); + const isValidUnionOperatorPush = + (isNumber(prevItem) || isUnionOperator(prevItem)) && + !isNumber(item) && + unionOperators.hasOwnProperty(item) && + isUnionOperator(item); + if (isValidNumberPush) { result.push(Number(item)); } else if (isValidOperatorPush) { result.push(item); + } else if(isValidUnionOperatorPush) { + result.push(item); } else { throw new TypeError("Unexpected string"); } + return result; }, []); -}; +}; \ No newline at end of file diff --git a/src/lesson2/runner.test.ts b/src/lesson2/runner.test.ts index 1318dce3..e78d41f6 100644 --- a/src/lesson2/runner.test.ts +++ b/src/lesson2/runner.test.ts @@ -12,6 +12,54 @@ describe("Runner simple cases", () => { it("2 + 32", () => { expect(runner("2 + 32")).toEqual(34); }); + + it("5 + 32", () => { + expect(runner("5 + 32")).toEqual(37); + }); + + it("2 - 32", () => { + expect(runner("2 - 32")).toEqual(-30); + }); + + it("25 - 5", () => { + expect(runner("25 - 5")).toEqual(20); + }); + + it("2 / 2", () => { + expect(runner("2 / 2")).toEqual(1); + }); + + it("12 / 3", () => { + expect(runner("12 / 3")).toEqual(4); + }); + + it("2 ^ 2", () => { + expect(runner("2 ^ 2")).toEqual(4); + }); + + it("5 ^ 2", () => { + expect(runner("5 ^ 2")).toEqual(25); + }); + + it("5 ! + 4", () => { + expect(runner("5 ! + 4")).toEqual(124); + }); + + it("3 ! + 4", () => { + expect(runner("3 ! + 4")).toEqual(10); + }); + + it("5 ! * 2", () => { + expect(runner("5 ! * 2")).toEqual(240); + }); + + it("5 ! / 2", () => { + expect(runner("5 ! / 2")).toEqual(60); + }); + + it("5 ! / 4", () => { + expect(runner("5 ! / 4")).toEqual(30); + }); }); describe("Runner tripled/mixed cases", () => { @@ -26,6 +74,22 @@ describe("Runner tripled/mixed cases", () => { it("2 + 2 * 3", () => { expect(runner("2 + 2 * 3")).toEqual(8); }); + + it("2 + 2 / 2", () => { + expect(runner("2 + 2 / 2")).toEqual(3); + }); + + it("2 + 2 + 5 !", () => { + expect(runner("2 + 2 + 5 !")).toEqual(124); + }); + + it("2 ^ 2 / 4", () => { + expect(runner("2 ^ 2 / 4")).toEqual(1); + }); + + it("2 ** + 2", () => { + expect(runner("2 ** + 2")).toEqual(6); + }); }); describe("Runner long cases", () => { @@ -36,4 +100,12 @@ describe("Runner long cases", () => { it("20 - 10 * 10 / 5 - 3", () => { expect(runner("20 - 10 * 10 / 5 - 3")).toEqual(-3); }); + + it("10 - 5 ** + 10 / 5 - 3", () => { + expect(runner("10 - 5 ** + 10 / 5 - 3")).toEqual(-16); + }); + + it("5 ! - 10 * 10 / 5 - 3", () => { + expect(runner("5 ! - 10 * 10 / 5 - 3")).toEqual(97); + }); }); diff --git a/src/lesson2/runner.ts b/src/lesson2/runner.ts index 920249fd..7eb2f4ba 100644 --- a/src/lesson2/runner.ts +++ b/src/lesson2/runner.ts @@ -1,6 +1,6 @@ import { parser } from "./parser"; -import { firstPrioritiesCalc, secondPrioritiesCalc } from "./engine"; +import { zeroPrioritiesCalc, firstPrioritiesCalc, secondPrioritiesCalc } from "./engine"; export const runner = (line: string): number => { const stack = parser(line); @@ -9,11 +9,18 @@ export const runner = (line: string): number => { throw new TypeError("Unexpected string"); } - const firstPrioritiesRes = firstPrioritiesCalc(stack); + const zeroPrioritiesRes = zeroPrioritiesCalc(stack); + + if (zeroPrioritiesRes.length === 1) { + return Number(zeroPrioritiesRes[0]); + } + + const firstPrioritiesRes = firstPrioritiesCalc(zeroPrioritiesRes); if (firstPrioritiesRes.length === 1) { return Number(firstPrioritiesRes[0]); } + return secondPrioritiesCalc(firstPrioritiesRes); };