From c82d17a34568765b87ed538b0205608afe357b00 Mon Sep 17 00:00:00 2001 From: "d.golovko" Date: Sat, 4 Mar 2023 04:10:41 +0300 Subject: [PATCH 1/7] =?UTF-8?q?=D1=81=D0=BA=D0=BE=D0=B1=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 7 +-- src/lesson2/engine.test.ts | 46 +++++++++++------ src/lesson2/engine.ts | 24 +++++++-- src/lesson2/helpers.ts | 3 ++ src/lesson2/index.ts | 2 +- src/lesson2/mathOperators.test.ts | 17 ++++++- src/lesson2/mathOperators.ts | 41 +++++++++++++--- src/lesson2/parser.test.ts | 62 ++++++++++++++++++++++- src/lesson2/parser.ts | 82 +++++++++++++++++++++++++++++-- src/lesson2/runner.test.ts | 4 ++ src/lesson2/runner.ts | 9 +++- 11 files changed, 257 insertions(+), 40 deletions(-) diff --git a/package.json b/package.json index e9c23573..0d9ac4cb 100644 --- a/package.json +++ b/package.json @@ -10,12 +10,7 @@ "test": "npx jest", "check": "npm test && npm run lint" }, - "husky": { - "hooks": { - "pre-commit": "npm run check", - "pre-push": "npm run check" - } - }, + "repository": { "type": "git", "url": "git+https://github.com/nickovchinnikov/react-js-tutorial.git" diff --git a/src/lesson2/engine.test.ts b/src/lesson2/engine.test.ts index eae1cc00..f8fa3287 100644 --- a/src/lesson2/engine.test.ts +++ b/src/lesson2/engine.test.ts @@ -1,22 +1,40 @@ -import { firstPrioritiesCalc, secondPrioritiesCalc } from "./engine"; +import { firstPrioritiesCalc, secondPrioritiesCalc, thirdPrioritiesCalc } from "./engine"; +/*describe("firstPrioritiesCalc simple cases", () => { + it("[2, **]", () => { + expect(firstPrioritiesCalc([2, "**"])).toEqual([4]); + }); -describe("firstPrioritiesCalc simple cases", () => { - it("[1, * 32]", () => { - expect(firstPrioritiesCalc([1, "*", 32])).toEqual([32]); + it("[2, **, +, 1]", () => { + expect(firstPrioritiesCalc([2, '**', '+', 1])).toEqual([4, '+', 1]) + }); + +}); +describe("firstPrioritiesCalc mixed with second priorities cases", () => { + it("[2, **, +, 10, *, 2]", () => { + expect(thirdPrioritiesCalc([2, "**", "+", 10, "*", 2])).toEqual([ + 4, + "+", + 20, + ]); + }); +});*/ +describe("secondPrioritiesCalc simple cases", () => { + it("[1, *, 32]", () => { + expect(secondPrioritiesCalc([1, "*", 32])).toEqual([32]); }); it("[32, /, 32]", () => { - expect(firstPrioritiesCalc([32, "/", 32])).toEqual([1]); + expect(secondPrioritiesCalc([32, "/", 32])).toEqual([1]); }); it("[32, + 32]", () => { - expect(firstPrioritiesCalc([32, "+", 32])).toEqual([32, "+", 32]); + expect(secondPrioritiesCalc([32, "+", 32])).toEqual([32, "+", 32]); }); }); -describe("firstPrioritiesCalc mixed with second priorities cases", () => { +describe("secondPrioritiesCalc mixed with second priorities cases", () => { it("[32, /, 32, +, 10, *, 10]", () => { - expect(firstPrioritiesCalc([32, "/", 32, "+", 10, "*", 10])).toEqual([ + expect(thirdPrioritiesCalc([32, "/", 32, "+", 10, "*", 10])).toEqual([ 1, "+", 100, @@ -24,24 +42,24 @@ describe("firstPrioritiesCalc mixed with second priorities cases", () => { }); }); -describe("secondPrioritiesCalc invalid cases", () => { +describe("thirdPrioritiesCalc invalid cases", () => { it("[32, / 32]", () => { - expect(() => secondPrioritiesCalc([32, "/", 32])).toThrow( + expect(() => thirdPrioritiesCalc([32, "/", 32])).toThrow( TypeError("Unexpected stack!") ); }); }); -describe("secondPrioritiesCalc simple cases", () => { +describe("thirdPrioritiesCalc simple cases", () => { it("[32, + 32]", () => { - expect(secondPrioritiesCalc([32, "+", 32])).toEqual(64); + expect(thirdPrioritiesCalc([32, "+", 32])).toEqual(64); }); it("[32, - 32]", () => { - expect(secondPrioritiesCalc([32, "-", 32])).toEqual(0); + expect(thirdPrioritiesCalc([32, "-", 32])).toEqual(0); }); it("[32, - 32, +, 10]", () => { - expect(secondPrioritiesCalc([32, "-", 32, "+", 10])).toEqual(10); + expect(thirdPrioritiesCalc([32, "-", 32, "+", 10])).toEqual(10); }); }); diff --git a/src/lesson2/engine.ts b/src/lesson2/engine.ts index 78aee1d7..5f37e495 100644 --- a/src/lesson2/engine.ts +++ b/src/lesson2/engine.ts @@ -4,16 +4,32 @@ import { mathOperators, mathPriorities, mathOperatorsPriorities, + functionMathOperators } from "./mathOperators"; -const [FIRST, SECOND] = mathPriorities; +const [FIRST, SECOND, THIRD, FOURTH] = mathPriorities; export const firstPrioritiesCalc = (stack: ParsedLineType): ParsedLineType => + stack.reduce((result, item, key) => { + if (!isNumber(String(item)) && mathOperatorsPriorities[item] === FIRST) { + if (!mathOperators[item]) { + throw new TypeError("Unexpected stack!"); + } + result = [ + ...result.slice(0, - 1), + functionMathOperators[item](Number(stack[key - 1]))] + } else { + result.push(item) + } + return result; + }, []) + +export const secondPrioritiesCalc = (stack: ParsedLineType): ParsedLineType => stack.reduce((result, nextItem) => { const prevItem = result[result.length - 2]; const item = result[result.length - 1]; - if (!isNumber(String(item)) && mathOperatorsPriorities[item] === FIRST) { + if (!isNumber(String(item)) && mathOperatorsPriorities[item] === THIRD) { if (!mathOperators[item]) { throw new TypeError("Unexpected stack!"); } @@ -27,7 +43,7 @@ export const firstPrioritiesCalc = (stack: ParsedLineType): ParsedLineType => return result; }, []); -export const secondPrioritiesCalc = (stack: ParsedLineType): number => +export const thirdPrioritiesCalc = (stack: ParsedLineType): number => stack.reduce((result, nextItem, key) => { const item = stack[key - 1]; @@ -39,4 +55,4 @@ export const secondPrioritiesCalc = (stack: ParsedLineType): number => result = mathOperators[item](Number(result), Number(nextItem)); } return result; - }, Number(stack[0])); + }, Number(stack[0])); \ No newline at end of file diff --git a/src/lesson2/helpers.ts b/src/lesson2/helpers.ts index b5a4b6ae..1e153704 100644 --- a/src/lesson2/helpers.ts +++ b/src/lesson2/helpers.ts @@ -1 +1,4 @@ export const isNumber = (item: string): boolean => !isNaN(Number(item)); +export const hasBrackets = (item: string): boolean => { + return item.includes( '(' ) || item.includes( ')' ) +} diff --git a/src/lesson2/index.ts b/src/lesson2/index.ts index 1766cf85..41c8a671 100644 --- a/src/lesson2/index.ts +++ b/src/lesson2/index.ts @@ -10,7 +10,7 @@ const rl = createInterface({ const question = (): Promise => new Promise((resolve) => { rl.question("> ", (answer: string) => { - const result = runner(answer); + const result = runner(answer.trim()); if (result) { console.log(`Result: ${result}`); diff --git a/src/lesson2/mathOperators.test.ts b/src/lesson2/mathOperators.test.ts index aad07e8d..3926da5c 100644 --- a/src/lesson2/mathOperators.test.ts +++ b/src/lesson2/mathOperators.test.ts @@ -1,8 +1,8 @@ -import { mul, div, add, minus } from "./mathOperators"; +import {mul, div, add, minus, pow, square} from "./mathOperators"; describe("mathOperators test cases", () => { it("mul 1 * 2 to equal 2", () => { - expect(mul(1, 2)).toBe(2); + expect(mul(1, 3)).toBe(2); }); it("mul 2 * 2 to equal 4", () => { @@ -24,4 +24,17 @@ describe("mathOperators test cases", () => { it("minus 4 - 2 to equal 2", () => { expect(minus(4, 2)).toBe(2); }); + + it("pow 2 in 3 equal 8", () => { + expect(pow(2,3)).toBe(8) + }) + + it("square 4 equal 16", () => { + expect(square(4)).toBe(16) + }) + + it("square 2 equal 4", () => { + expect(square(2)).toBe(4) + }) + }); diff --git a/src/lesson2/mathOperators.ts b/src/lesson2/mathOperators.ts index af8eb770..f11f39bc 100644 --- a/src/lesson2/mathOperators.ts +++ b/src/lesson2/mathOperators.ts @@ -1,4 +1,5 @@ export type ScalarOperationType = (first: number, second: number) => number; +export type FunctionOperationType = (value: number) => number export const mul: ScalarOperationType = ( first: number, @@ -20,20 +21,46 @@ export const minus: ScalarOperationType = ( second: number ): number => first - second; -export const mathOperators: { [key: string]: ScalarOperationType } = { +export const pow: ScalarOperationType = ( + first: number, + second: number +):number => Math.pow(first, second); + +export const square: FunctionOperationType = (value: number): number => pow(value, 2); +export const factorial: FunctionOperationType = (value: number): number => pow(value, 2); +export const scalarMathOperators: { [key: string]: ScalarOperationType } = { "*": mul, "/": div, "+": add, "-": minus, + "^": pow, +}; + +export const functionMathOperators: { [key: string]: FunctionOperationType } = { + "**": square, + "!" : factorial }; -export const mathPriorities: number[] = [1, 2]; +export const mathOperators: { + [key: string]: FunctionOperationType | ScalarOperationType +} = + { + ...scalarMathOperators, + ...functionMathOperators + }; + +export const mathPriorities: number[] = [1, 2, 3, 4]; -const [FIRST, SECOND] = mathPriorities; +const [FIRST, SECOND, THIRD, FOURTH] = mathPriorities; export const mathOperatorsPriorities: { [key: string]: number } = { - "*": FIRST, - "/": FIRST, - "+": SECOND, - "-": SECOND, + "*": THIRD, + "/": THIRD, + "+": FOURTH, + "-": FOURTH, + "^": THIRD, + "**": FIRST, + "!": FIRST, + "sin": SECOND, + "cos": SECOND }; diff --git a/src/lesson2/parser.test.ts b/src/lesson2/parser.test.ts index 5593e312..a4501506 100644 --- a/src/lesson2/parser.test.ts +++ b/src/lesson2/parser.test.ts @@ -12,6 +12,42 @@ describe("Parser correct cases", () => { it("1 + 32 - 2 + 2", () => { expect(parser("1 + 32 - 2 + 2")).toEqual([1, "+", 32, "-", 2, "+", 2]); }); + + /*it("2 ** + 2 / 3", () => { + expect(parser("2 ** + 2 / 3")).toEqual([2, "**", '+', 2, "/", 3]); + });*/ + + // brackets + it("(5.2 + 3.2)", () => { + expect(parser("(5.2 + 3.2)")).toEqual(["(", 5.2, "+", 3.2, ")"]) + }) + it("8 + (6 * 3)", () => { + expect(parser("8 + (6 * 3)")).toEqual([8, "+", "(", 6, "*", 3, ")"]) + }) + + it("7 + (8 + 9 * 2) * 3 - ((1)) / (5 * (5 + 2))", () => { + expect(parser("7 + (8 + 9 * 2) * 3 - ((1)) / (5 * (5 + 2))")).toEqual([7, "+", "(", 8, "+", 9, "*", 2, ")", "*", 3, "-", 1, "/", "(", 5, "*", "(", 5, "+", 2, ")", ")"]) + }) + it("5 + (3)", () => { + expect(parser("5 + (3)")).toEqual([5, "+", 3]) + }) + + it("5 + (((3)))", () => { + expect(parser("5 + (3)")).toEqual([5, "+", 3]) + }) + + it("5 + ()3)", () => { + expect(() => parser("5 + ()3)")).toThrow(TypeError("Unexpected string")) + }) + it("5 + ()3", () => { + expect(() => parser("5 + ()3")).toThrow(TypeError("Unexpected string")) + }) + it("5 + )3(", () => { + expect(() => parser("5 + )3(")).toThrow(TypeError("Unexpected string")) + }) + it("(5 + 3))", () => { + expect(() => parser("(5 + 3))")).toThrow(TypeError("Unexpected string")) + }) }); describe("Parser invalid cases", () => { @@ -21,7 +57,31 @@ describe("Parser invalid cases", () => { ); }); - it("1 ! 33 - 2", () => { + it("1 ! 33 -", () => { + expect(() => parser("1 ! 33 -")).toThrow(TypeError("Unexpected string")); + }); + + it("** ** **", () => { expect(() => parser("1 ! 33 - 2")).toThrow(TypeError("Unexpected string")); }); + it("** 2", () => { + expect(() => parser("1 ! 33 - 2")).toThrow(TypeError("Unexpected string")); + }); + + // brackets + it("7 + ((8 * 9) - 3", () => { + expect(() => parser("7 + ((8 * 9) - 3")).toThrow(TypeError("Unexpected string")); + }) + + it("7 + (8 * 9)) - 3", () => { + expect(() => parser("7 + (8 * 9)) - 3")).toThrow(TypeError("Unexpected string")); + }) + + it("7 + (8 * 9)) - 3", () => { + expect(() => parser("7 + (8 * 9)) - 3")).toThrow(TypeError("Unexpected string")); + }) + + it("7 + 2 () + 1", () => { + expect(() => parser("7 + 2 () + 1")).toThrow(TypeError("Unexpected string")); + }) }); diff --git a/src/lesson2/parser.ts b/src/lesson2/parser.ts index 118ff662..0c2df3be 100644 --- a/src/lesson2/parser.ts +++ b/src/lesson2/parser.ts @@ -1,13 +1,81 @@ import { isNumber } from "./helpers"; -import { mathOperators } from "./mathOperators"; +import { mathOperators } from "./mathOperators"; export type ParsedLineType = (number | string)[]; export const parser = (line: string): ParsedLineType | null => { + let _countOpenBrackets = 0; + let _countCloseBrackets = 0; + for (let i = 0; i < line.length; i++) { + if (line[i] === ')') { + _countCloseBrackets++; + } + if (line[i] === '(') { + _countOpenBrackets++; + } + } + if (_countOpenBrackets !== _countCloseBrackets) { + console.log("Число открытых и закрытых скобок не совпадает"); + throw new TypeError("Unexpected string"); + } const stack = line.split(" "); - - return stack.reduce((result, item, key) => { + const res = stack.reduce((result, item, key) => { const prevItem = stack[key - 1]; + let itemHasCloseBrackets = false; + let countOpenBrackets = 0; + let countCloseBrackets = 0; + + if (item.includes('(') || item.includes(')')) { + let openBracketsIsOpen = false; + let numberInsideBrackets = false; + let itemLength = item.length; + let oldItem = item; + for (let i = 0; i < itemLength; i++) { + let curSymbol = oldItem[i]; + if (curSymbol === '(') { + openBracketsIsOpen = true; + countOpenBrackets++; + item = item.replace('(', ''); + + } + if (curSymbol === ')' ) { + if (i == 0) { + console.log("Закрытая скобка впереди"); + throw new TypeError("Unexpected string"); + } + if (countOpenBrackets !== 0 && !numberInsideBrackets) { + console.log("Число НЕ внутри скобок"); + throw new TypeError("Unexpected string"); + } + countCloseBrackets++; + item = item.replace(')', ''); + openBracketsIsOpen = false; + itemHasCloseBrackets = true; + } + if (isNumber(curSymbol)) { + numberInsideBrackets = true; + } + } + if ( + (countOpenBrackets > 0 && countCloseBrackets > 0) + && countOpenBrackets !== countCloseBrackets) { + console.log("Число открытых и закрытых скобок не совпадает"); + throw new TypeError("Unexpected string"); + } + if (countOpenBrackets === countCloseBrackets){ + countOpenBrackets = 0; + itemHasCloseBrackets = false; + } + + if (countOpenBrackets > 0) { + result.push('('); + } + + if (isNumber(item)) { + stack[key] = item; + } + + } const isValidNumberPush = !isNumber(prevItem) && isNumber(item); const isValidOperatorPush = @@ -17,6 +85,11 @@ export const parser = (line: string): ParsedLineType | null => { if (isValidNumberPush) { result.push(Number(item)); + if (itemHasCloseBrackets) { + for (let i = 0; i < countCloseBrackets; i++) { + result.push(')'); + } + } } else if (isValidOperatorPush) { result.push(item); } else { @@ -24,4 +97,7 @@ export const parser = (line: string): ParsedLineType | null => { } return result; }, []); + + console.log(res); + return res; }; diff --git a/src/lesson2/runner.test.ts b/src/lesson2/runner.test.ts index 1318dce3..3cb94aae 100644 --- a/src/lesson2/runner.test.ts +++ b/src/lesson2/runner.test.ts @@ -12,6 +12,10 @@ describe("Runner simple cases", () => { it("2 + 32", () => { expect(runner("2 + 32")).toEqual(34); }); + + it("2**", () => { + expect(runner("2 **")).toEqual(4); + }); }); describe("Runner tripled/mixed cases", () => { diff --git a/src/lesson2/runner.ts b/src/lesson2/runner.ts index 920249fd..6f454baa 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 { firstPrioritiesCalc, secondPrioritiesCalc, thirdPrioritiesCalc } from "./engine"; export const runner = (line: string): number => { const stack = parser(line); @@ -15,5 +15,10 @@ export const runner = (line: string): number => { return Number(firstPrioritiesRes[0]); } - return secondPrioritiesCalc(firstPrioritiesRes); + const secondPrioritiesRes = secondPrioritiesCalc(firstPrioritiesRes); + + if (secondPrioritiesRes.length === 1) { + return Number(secondPrioritiesRes[0]); + } + return thirdPrioritiesCalc(firstPrioritiesRes); }; From 12278105434c1b5e59fd00d06def71cbc05ca243 Mon Sep 17 00:00:00 2001 From: "d.golovko" Date: Sat, 11 Mar 2023 20:44:11 +0300 Subject: [PATCH 2/7] =?UTF-8?q?=D1=81=D0=BA=D0=BE=D0=B1=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 7 +- src/lesson2/engine.test.ts | 117 +++++++++++++++--------- src/lesson2/engine.ts | 54 ++++++++---- src/lesson2/helpers.ts | 4 +- src/lesson2/mathOperators.test.ts | 17 ++-- src/lesson2/mathOperators.ts | 37 ++++---- src/lesson2/parser.test.ts | 142 ++++++++++++++++++++++-------- src/lesson2/parser.ts | 78 +++++++++------- src/lesson2/runner.test.ts | 18 ++++ src/lesson2/runner.ts | 40 ++++++--- 10 files changed, 344 insertions(+), 170 deletions(-) diff --git a/package.json b/package.json index 0d9ac4cb..e9c23573 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,12 @@ "test": "npx jest", "check": "npm test && npm run lint" }, - + "husky": { + "hooks": { + "pre-commit": "npm run check", + "pre-push": "npm run check" + } + }, "repository": { "type": "git", "url": "git+https://github.com/nickovchinnikov/react-js-tutorial.git" diff --git a/src/lesson2/engine.test.ts b/src/lesson2/engine.test.ts index f8fa3287..f0c5e094 100644 --- a/src/lesson2/engine.test.ts +++ b/src/lesson2/engine.test.ts @@ -1,65 +1,102 @@ -import { firstPrioritiesCalc, secondPrioritiesCalc, thirdPrioritiesCalc } from "./engine"; -/*describe("firstPrioritiesCalc simple cases", () => { - it("[2, **]", () => { - expect(firstPrioritiesCalc([2, "**"])).toEqual([4]); - }); +import { + fourthPrioritiesCalc, + secondPrioritiesCalc, + thirdPrioritiesCalc, + bracketsProcessing, +} from "./engine"; - it("[2, **, +, 1]", () => { - expect(firstPrioritiesCalc([2, '**', '+', 1])).toEqual([4, '+', 1]) +describe("brackets processing simple cases", () => { + it("(5, +, 4, ), /, (, 5, -, 3, )", () => { + expect( + bracketsProcessing(["(", 5, "+", 4, ")", "/", "(", 5, "-", 3, ")"]) + ).toEqual([9, "/", 2]); }); - }); -describe("firstPrioritiesCalc mixed with second priorities cases", () => { - it("[2, **, +, 10, *, 2]", () => { - expect(thirdPrioritiesCalc([2, "**", "+", 10, "*", 2])).toEqual([ - 4, - "+", - 20, - ]); - }); -});*/ -describe("secondPrioritiesCalc simple cases", () => { - it("[1, *, 32]", () => { - expect(secondPrioritiesCalc([1, "*", 32])).toEqual([32]); - }); - it("[32, /, 32]", () => { - expect(secondPrioritiesCalc([32, "/", 32])).toEqual([1]); +describe("brackets processing simple cases", () => { + it("(5+5)", () => { + expect(bracketsProcessing(["(", 5, "+", 5, ")"])).toEqual([10]); }); +}); - it("[32, + 32]", () => { - expect(secondPrioritiesCalc([32, "+", 32])).toEqual([32, "+", 32]); +describe("brackets processing simple cases", () => { + it("1 + (3 + 2 * (3 + 4))", () => { + expect( + bracketsProcessing([ + 1, + "+", + "(", + 3, + "+", + 2, + "*", + "(", + 3, + "+", + 4, + ")", + ")", + ]) + ).toEqual([1, "+", 17]); }); }); -describe("secondPrioritiesCalc mixed with second priorities cases", () => { - it("[32, /, 32, +, 10, *, 10]", () => { - expect(thirdPrioritiesCalc([32, "/", 32, "+", 10, "*", 10])).toEqual([ +describe("secondPrioritiesCalc simple cases", () => { + it("5, +, 4, /, 1, -, 3, **", () => { + expect(secondPrioritiesCalc([5, "+", 4, "/", 1, "-", 3, "**"])).toEqual([ + 5, + "+", + 4, + "/", 1, + "-", + 9, + ]); + }); +}); +describe("secondPrioritiesCalc simple cases", () => { + it("3, **", () => { + expect(secondPrioritiesCalc([3, "**", "+", 4, "^", 3])).toEqual([ + 9, "+", - 100, + 4, + "^", + 3, ]); }); }); -describe("thirdPrioritiesCalc invalid cases", () => { - it("[32, / 32]", () => { - expect(() => thirdPrioritiesCalc([32, "/", 32])).toThrow( - TypeError("Unexpected stack!") - ); +describe("thirdPrioritiesCalc simple cases", () => { + it("2, '*', 4, '/', 1", () => { + expect(thirdPrioritiesCalc([2, "*", 4, "/", 1])).toEqual([8]); }); }); describe("thirdPrioritiesCalc simple cases", () => { - it("[32, + 32]", () => { - expect(thirdPrioritiesCalc([32, "+", 32])).toEqual(64); + it("2, '*', 4, '/', 1, -, 2, ^, 4", () => { + expect( + thirdPrioritiesCalc([2, "*", 4, "/", 1, "-", 2, "^", 4, "+", 1]) + ).toEqual([8, "-", 16, "+", 1]); }); +}); +describe("thirdPrioritiesCalc simple cases", () => { + it("2, '*', 4, '/', 1 - 2", () => { + expect(thirdPrioritiesCalc([2, "*", 4, "/", 1, "-", 2])).toEqual([ + 8, + "-", + 2, + ]); + }); +}); - it("[32, - 32]", () => { - expect(thirdPrioritiesCalc([32, "-", 32])).toEqual(0); +describe("fourthPrioritiesCalc simple cases", () => { + it("2, '+', 4, '-', 1", () => { + expect(fourthPrioritiesCalc([2, "+", 4, "-", 1])).toEqual(5); }); +}); - it("[32, - 32, +, 10]", () => { - expect(thirdPrioritiesCalc([32, "-", 32, "+", 10])).toEqual(10); +describe("fourthPrioritiesCalc simple cases", () => { + it("2, '-', 4, '-', 10", () => { + expect(fourthPrioritiesCalc([2, "-", 4, "-", 10.5])).toEqual(-12.5); }); }); diff --git a/src/lesson2/engine.ts b/src/lesson2/engine.ts index 5f37e495..18372dc2 100644 --- a/src/lesson2/engine.ts +++ b/src/lesson2/engine.ts @@ -1,30 +1,52 @@ import { ParsedLineType } from "./parser"; import { isNumber } from "./helpers"; +import { calc } from "./runner"; import { mathOperators, mathPriorities, mathOperatorsPriorities, - functionMathOperators + functionMathOperators, } from "./mathOperators"; const [FIRST, SECOND, THIRD, FOURTH] = mathPriorities; -export const firstPrioritiesCalc = (stack: ParsedLineType): ParsedLineType => - stack.reduce((result, item, key) => { - if (!isNumber(String(item)) && mathOperatorsPriorities[item] === FIRST) { +export const bracketsProcessing = (stack: ParsedLineType): ParsedLineType => { + let indexOpenBrackets: number; + stack.forEach((item, index) => { + if (item === "(") { + indexOpenBrackets = index; + } + if (item === ")") { + stack.splice( + indexOpenBrackets, + index - indexOpenBrackets + 1, + calc(stack.slice(indexOpenBrackets + 1, index)) + ); + bracketsProcessing(stack); + } + }); + + return stack; +}; + +export const secondPrioritiesCalc = (stack: ParsedLineType): ParsedLineType => + stack.reduce((result, item) => { + const prevItem = result[result.length - 1]; + + if (!isNumber(String(item)) && mathOperatorsPriorities[item] === SECOND) { if (!mathOperators[item]) { throw new TypeError("Unexpected stack!"); } result = [ - ...result.slice(0, - 1), - functionMathOperators[item](Number(stack[key - 1]))] + ...result.slice(0, -1), + functionMathOperators[item](Number(prevItem)), + ]; } else { - result.push(item) + result.push(item); } return result; - }, []) - -export const secondPrioritiesCalc = (stack: ParsedLineType): ParsedLineType => + }, []); +export const thirdPrioritiesCalc = (stack: ParsedLineType): ParsedLineType => stack.reduce((result, nextItem) => { const prevItem = result[result.length - 2]; const item = result[result.length - 1]; @@ -42,17 +64,11 @@ export const secondPrioritiesCalc = (stack: ParsedLineType): ParsedLineType => } return result; }, []); - -export const thirdPrioritiesCalc = (stack: ParsedLineType): number => +export const fourthPrioritiesCalc = (stack: ParsedLineType): number => stack.reduce((result, nextItem, key) => { const item = stack[key - 1]; - - if (mathOperatorsPriorities[item] === FIRST) { - throw new TypeError("Unexpected stack!"); - } - - if (!isNumber(String(item)) && mathOperatorsPriorities[item] === SECOND) { + if (!isNumber(String(item)) && mathOperatorsPriorities[item] === FOURTH) { result = mathOperators[item](Number(result), Number(nextItem)); } return result; - }, Number(stack[0])); \ No newline at end of file + }, Number(stack[0])); diff --git a/src/lesson2/helpers.ts b/src/lesson2/helpers.ts index 1e153704..1cd8dde3 100644 --- a/src/lesson2/helpers.ts +++ b/src/lesson2/helpers.ts @@ -1,4 +1,4 @@ export const isNumber = (item: string): boolean => !isNaN(Number(item)); export const hasBrackets = (item: string): boolean => { - return item.includes( '(' ) || item.includes( ')' ) -} + return item.includes("(") || item.includes(")"); +}; diff --git a/src/lesson2/mathOperators.test.ts b/src/lesson2/mathOperators.test.ts index 3926da5c..61cf996b 100644 --- a/src/lesson2/mathOperators.test.ts +++ b/src/lesson2/mathOperators.test.ts @@ -1,8 +1,8 @@ -import {mul, div, add, minus, pow, square} from "./mathOperators"; +import { mul, div, add, minus, pow, square } from "./mathOperators"; describe("mathOperators test cases", () => { it("mul 1 * 2 to equal 2", () => { - expect(mul(1, 3)).toBe(2); + expect(mul(1, 3)).toBe(3); }); it("mul 2 * 2 to equal 4", () => { @@ -26,15 +26,14 @@ describe("mathOperators test cases", () => { }); it("pow 2 in 3 equal 8", () => { - expect(pow(2,3)).toBe(8) - }) + expect(pow(2, 3)).toBe(8); + }); it("square 4 equal 16", () => { - expect(square(4)).toBe(16) - }) + expect(square(4)).toBe(16); + }); it("square 2 equal 4", () => { - expect(square(2)).toBe(4) - }) - + expect(square(2)).toBe(4); + }); }); diff --git a/src/lesson2/mathOperators.ts b/src/lesson2/mathOperators.ts index f11f39bc..30fe3684 100644 --- a/src/lesson2/mathOperators.ts +++ b/src/lesson2/mathOperators.ts @@ -1,5 +1,5 @@ export type ScalarOperationType = (first: number, second: number) => number; -export type FunctionOperationType = (value: number) => number +export type FunctionOperationType = (first: number, second?: number) => number; export const mul: ScalarOperationType = ( first: number, @@ -21,13 +21,15 @@ export const minus: ScalarOperationType = ( second: number ): number => first - second; -export const pow: ScalarOperationType = ( - first: number, - second: number -):number => Math.pow(first, second); +export const pow: FunctionOperationType = ( + first: number, + second?: number +): number => Math.pow(first, Number(second)); -export const square: FunctionOperationType = (value: number): number => pow(value, 2); -export const factorial: FunctionOperationType = (value: number): number => pow(value, 2); +export const square: FunctionOperationType = (value: number): number => + pow(value, 2); +export const factorial: FunctionOperationType = (value: number): number => + pow(value, 2); export const scalarMathOperators: { [key: string]: ScalarOperationType } = { "*": mul, "/": div, @@ -38,16 +40,15 @@ export const scalarMathOperators: { [key: string]: ScalarOperationType } = { export const functionMathOperators: { [key: string]: FunctionOperationType } = { "**": square, - "!" : factorial + "!": factorial, }; export const mathOperators: { - [key: string]: FunctionOperationType | ScalarOperationType -} = - { - ...scalarMathOperators, - ...functionMathOperators - }; + [key: string]: FunctionOperationType | ScalarOperationType; +} = { + ...scalarMathOperators, + ...functionMathOperators, +}; export const mathPriorities: number[] = [1, 2, 3, 4]; @@ -59,8 +60,8 @@ export const mathOperatorsPriorities: { [key: string]: number } = { "+": FOURTH, "-": FOURTH, "^": THIRD, - "**": FIRST, - "!": FIRST, - "sin": SECOND, - "cos": SECOND + "**": SECOND, + "!": SECOND, + sin: FIRST, + cos: FIRST, }; diff --git a/src/lesson2/parser.test.ts b/src/lesson2/parser.test.ts index a4501506..6d414e10 100644 --- a/src/lesson2/parser.test.ts +++ b/src/lesson2/parser.test.ts @@ -13,41 +13,82 @@ describe("Parser correct cases", () => { expect(parser("1 + 32 - 2 + 2")).toEqual([1, "+", 32, "-", 2, "+", 2]); }); - /*it("2 ** + 2 / 3", () => { - expect(parser("2 ** + 2 / 3")).toEqual([2, "**", '+', 2, "/", 3]); - });*/ + it("2 ** + 2 / 3", () => { + expect(parser("2 ** + 2 / 3")).toEqual([2, "**", "+", 2, "/", 3]); + }); // brackets it("(5.2 + 3.2)", () => { - expect(parser("(5.2 + 3.2)")).toEqual(["(", 5.2, "+", 3.2, ")"]) - }) + expect(parser("(5.2 + 3.2)")).toEqual(["(", 5.2, "+", 3.2, ")"]); + }); it("8 + (6 * 3)", () => { - expect(parser("8 + (6 * 3)")).toEqual([8, "+", "(", 6, "*", 3, ")"]) - }) + expect(parser("8 + (6 * 3)")).toEqual([8, "+", "(", 6, "*", 3, ")"]); + }); it("7 + (8 + 9 * 2) * 3 - ((1)) / (5 * (5 + 2))", () => { - expect(parser("7 + (8 + 9 * 2) * 3 - ((1)) / (5 * (5 + 2))")).toEqual([7, "+", "(", 8, "+", 9, "*", 2, ")", "*", 3, "-", 1, "/", "(", 5, "*", "(", 5, "+", 2, ")", ")"]) - }) + expect(parser("7 + (8 + 9 * 2) * 3 - ((1)) / (5 * (5 + 2))")).toEqual([ + 7, + "+", + "(", + 8, + "+", + 9, + "*", + 2, + ")", + "*", + 3, + "-", + "(", + "(", + 1, + ")", + ")", + "/", + "(", + 5, + "*", + "(", + 5, + "+", + 2, + ")", + ")", + ]); + }); it("5 + (3)", () => { - expect(parser("5 + (3)")).toEqual([5, "+", 3]) - }) + expect(parser("5 + (3)")).toEqual([5, "+", "(", 3, ")"]); + }); + + it("5 + ((3))", () => { + expect(parser("5 + ((3))")).toEqual([5, "+", "(", "(", 3, ")", ")"]); + }); it("5 + (((3)))", () => { - expect(parser("5 + (3)")).toEqual([5, "+", 3]) - }) + expect(parser("5 + (3 * 2)")).toEqual([5, "+", "(", 3, "*", 2, ")"]); + }); - it("5 + ()3)", () => { - expect(() => parser("5 + ()3)")).toThrow(TypeError("Unexpected string")) - }) - it("5 + ()3", () => { - expect(() => parser("5 + ()3")).toThrow(TypeError("Unexpected string")) - }) - it("5 + )3(", () => { - expect(() => parser("5 + )3(")).toThrow(TypeError("Unexpected string")) - }) - it("(5 + 3))", () => { - expect(() => parser("(5 + 3))")).toThrow(TypeError("Unexpected string")) - }) + it("5 + ((3 + 6) * 2) / 2", () => { + expect(parser("5 + ((3 + 6) * 2) / 2")).toEqual([ + 5, + "+", + "(", + "(", + 3, + "+", + 6, + ")", + "*", + 2, + ")", + "/", + 2, + ]); + }); + + it("(-5.2 + 3)", () => { + expect(parser("(-5.2 + 3)")).toEqual(["(", -5.2, "+", 3, ")"]); + }); }); describe("Parser invalid cases", () => { @@ -62,26 +103,57 @@ describe("Parser invalid cases", () => { }); it("** ** **", () => { - expect(() => parser("1 ! 33 - 2")).toThrow(TypeError("Unexpected string")); + expect(() => parser("** ** **")).toThrow(TypeError("Unexpected string")); }); it("** 2", () => { - expect(() => parser("1 ! 33 - 2")).toThrow(TypeError("Unexpected string")); + expect(() => parser("** 2")).toThrow(TypeError("Unexpected string")); }); // brackets it("7 + ((8 * 9) - 3", () => { - expect(() => parser("7 + ((8 * 9) - 3")).toThrow(TypeError("Unexpected string")); - }) + expect(() => parser("7 + ((8 * 9) - 3")).toThrow( + TypeError("Unexpected string") + ); + }); it("7 + (8 * 9)) - 3", () => { - expect(() => parser("7 + (8 * 9)) - 3")).toThrow(TypeError("Unexpected string")); - }) + expect(() => parser("7 + (8 * 9)) - 3")).toThrow( + TypeError("Unexpected string") + ); + }); it("7 + (8 * 9)) - 3", () => { - expect(() => parser("7 + (8 * 9)) - 3")).toThrow(TypeError("Unexpected string")); - }) + expect(() => parser("7 + (8 * 9)) - 3")).toThrow( + TypeError("Unexpected string") + ); + }); it("7 + 2 () + 1", () => { - expect(() => parser("7 + 2 () + 1")).toThrow(TypeError("Unexpected string")); - }) + expect(() => parser("7 + 2 () + 1")).toThrow( + TypeError("Unexpected string") + ); + }); + + it("5 + ()3)", () => { + expect(() => parser("5 + ()3)")).toThrow(TypeError("Unexpected string")); + }); + it("5 + ()3", () => { + expect(() => parser("5 + ()3")).toThrow(TypeError("Unexpected string")); + }); + it("5 + )3(", () => { + expect(() => parser("5 + )3(")).toThrow(TypeError("Unexpected string")); + }); + it("(5 + 3))", () => { + expect(() => parser("(5 + 3))")).toThrow(TypeError("Unexpected string")); + }); + + it("(5.2w + 3)", () => { + expect(() => parser("(5.2w + 3)")).toThrow(TypeError("Unexpected string")); + }); + + it("1 + (1+) - 33", () => { + expect(() => parser("1 + (1 + ы) - 33")).toThrow( + TypeError("Unexpected string") + ); + }); }); diff --git a/src/lesson2/parser.ts b/src/lesson2/parser.ts index 0c2df3be..423d9c20 100644 --- a/src/lesson2/parser.ts +++ b/src/lesson2/parser.ts @@ -1,5 +1,9 @@ import { isNumber } from "./helpers"; -import { mathOperators } from "./mathOperators"; +import { + functionMathOperators, + mathOperators, + scalarMathOperators, +} from "./mathOperators"; export type ParsedLineType = (number | string)[]; @@ -7,49 +11,50 @@ export const parser = (line: string): ParsedLineType | null => { let _countOpenBrackets = 0; let _countCloseBrackets = 0; for (let i = 0; i < line.length; i++) { - if (line[i] === ')') { + if (line[i] === ")") { _countCloseBrackets++; } - if (line[i] === '(') { + if (line[i] === "(") { _countOpenBrackets++; } } if (_countOpenBrackets !== _countCloseBrackets) { - console.log("Число открытых и закрытых скобок не совпадает"); throw new TypeError("Unexpected string"); } const stack = line.split(" "); - const res = stack.reduce((result, item, key) => { + return stack.reduce((result, item, key) => { + if (key === 0 && mathOperators.hasOwnProperty(item)) { + throw new TypeError("Unexpected string"); + } + + if (key === stack.length - 1 && scalarMathOperators.hasOwnProperty(item)) { + throw new TypeError("Unexpected string"); + } const prevItem = stack[key - 1]; let itemHasCloseBrackets = false; let countOpenBrackets = 0; let countCloseBrackets = 0; - if (item.includes('(') || item.includes(')')) { - let openBracketsIsOpen = false; + if (item.includes("(") || item.includes(")")) { let numberInsideBrackets = false; - let itemLength = item.length; - let oldItem = item; + const itemLength = item.length; + const oldItem = item; + for (let i = 0; i < itemLength; i++) { - let curSymbol = oldItem[i]; - if (curSymbol === '(') { - openBracketsIsOpen = true; + const curSymbol = oldItem[i]; + if (curSymbol === "(") { countOpenBrackets++; - item = item.replace('(', ''); - + item = item.replace("(", ""); } - if (curSymbol === ')' ) { + if (curSymbol === ")") { if (i == 0) { - console.log("Закрытая скобка впереди"); throw new TypeError("Unexpected string"); } if (countOpenBrackets !== 0 && !numberInsideBrackets) { - console.log("Число НЕ внутри скобок"); throw new TypeError("Unexpected string"); } countCloseBrackets++; - item = item.replace(')', ''); - openBracketsIsOpen = false; + item = item.replace(")", ""); itemHasCloseBrackets = true; } if (isNumber(curSymbol)) { @@ -57,37 +62,45 @@ export const parser = (line: string): ParsedLineType | null => { } } if ( - (countOpenBrackets > 0 && countCloseBrackets > 0) - && countOpenBrackets !== countCloseBrackets) { - console.log("Число открытых и закрытых скобок не совпадает"); + countOpenBrackets > 0 && + countCloseBrackets > 0 && + countOpenBrackets !== countCloseBrackets + ) { throw new TypeError("Unexpected string"); } - if (countOpenBrackets === countCloseBrackets){ - countOpenBrackets = 0; - itemHasCloseBrackets = false; - } if (countOpenBrackets > 0) { - result.push('('); + for (let i = 0; i < countOpenBrackets; i++) { + result.push("("); + } } if (isNumber(item)) { stack[key] = item; } - } const isValidNumberPush = !isNumber(prevItem) && isNumber(item); - const isValidOperatorPush = + const isValidFunctionalOperatorPush = isNumber(prevItem) && !isNumber(item) && - mathOperators.hasOwnProperty(item); + functionMathOperators.hasOwnProperty(item); + + const isValidScalarOperatorPush = + (isNumber(prevItem) && + !isNumber(item) && + scalarMathOperators.hasOwnProperty(item)) || + (functionMathOperators.hasOwnProperty(prevItem) && + scalarMathOperators.hasOwnProperty(item)); + + const isValidOperatorPush = + isValidScalarOperatorPush || isValidFunctionalOperatorPush; if (isValidNumberPush) { result.push(Number(item)); if (itemHasCloseBrackets) { for (let i = 0; i < countCloseBrackets; i++) { - result.push(')'); + result.push(")"); } } } else if (isValidOperatorPush) { @@ -97,7 +110,4 @@ export const parser = (line: string): ParsedLineType | null => { } return result; }, []); - - console.log(res); - return res; }; diff --git a/src/lesson2/runner.test.ts b/src/lesson2/runner.test.ts index 3cb94aae..7f2e1424 100644 --- a/src/lesson2/runner.test.ts +++ b/src/lesson2/runner.test.ts @@ -41,3 +41,21 @@ describe("Runner long cases", () => { expect(runner("20 - 10 * 10 / 5 - 3")).toEqual(-3); }); }); + +describe("Runner with brackets cases", () => { + it("(2 + 2) * 2", () => { + expect(runner("(2 + 2) * 2")).toEqual(8); + }); +}); + +describe("Runner with brackets cases", () => { + it("((2 + 2)) ** * 2", () => { + expect(runner("(2 + 2) ** * 2")).toEqual(32); + }); +}); + +describe("Runner with brackets cases", () => { + it("8 * 4 + 3 * (4 + 8 - (2 ^ 3 + 1))", () => { + expect(runner("8 * 4 + 3 * (4 + 8 - (2 ^ 3 + 1))")).toEqual(41); + }); +}); diff --git a/src/lesson2/runner.ts b/src/lesson2/runner.ts index 6f454baa..92d0acd3 100644 --- a/src/lesson2/runner.ts +++ b/src/lesson2/runner.ts @@ -1,24 +1,40 @@ -import { parser } from "./parser"; - -import { firstPrioritiesCalc, secondPrioritiesCalc, thirdPrioritiesCalc } from "./engine"; - -export const runner = (line: string): number => { - const stack = parser(line); +import { parser, ParsedLineType } from "./parser"; +import { + fourthPrioritiesCalc, + secondPrioritiesCalc, + thirdPrioritiesCalc, + bracketsProcessing, +} from "./engine"; +export const calc = (stack: ParsedLineType | null): number => { if (stack === null) { throw new TypeError("Unexpected string"); } - const firstPrioritiesRes = firstPrioritiesCalc(stack); + const bracketsProcessingRes = bracketsProcessing(stack); - if (firstPrioritiesRes.length === 1) { - return Number(firstPrioritiesRes[0]); - } + /* const firstPrioritiesRes = firstPrioritiesCalc(stack); + + if (firstPrioritiesRes.length === 1) { + return Number(firstPrioritiesRes[0]); + }*/ - const secondPrioritiesRes = secondPrioritiesCalc(firstPrioritiesRes); + const secondPrioritiesRes = secondPrioritiesCalc(bracketsProcessingRes); if (secondPrioritiesRes.length === 1) { return Number(secondPrioritiesRes[0]); } - return thirdPrioritiesCalc(firstPrioritiesRes); + + const thirdPrioritiesRes = thirdPrioritiesCalc(secondPrioritiesRes); + + if (thirdPrioritiesRes.length === 1) { + return Number(thirdPrioritiesRes[0]); + } + + return fourthPrioritiesCalc(thirdPrioritiesRes); +}; +export const runner = (line: string): number => { + const stack = parser(line); + + return calc(stack); }; From 919eeda87639bb96cc4863a21048c62df70e31e2 Mon Sep 17 00:00:00 2001 From: "d.golovko" Date: Mon, 13 Mar 2023 22:39:25 +0300 Subject: [PATCH 3/7] =?UTF-8?q?=D1=81=D0=BA=D0=BE=D0=B1=D0=BA=D0=B8=20?= =?UTF-8?q?=D1=81=20=D0=BF=D1=80=D0=BE=D0=B1=D0=B5=D0=BB=D0=B0=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lesson2/helpers.ts | 2 +- src/lesson2/parser.ts | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/lesson2/helpers.ts b/src/lesson2/helpers.ts index 1cd8dde3..853927bc 100644 --- a/src/lesson2/helpers.ts +++ b/src/lesson2/helpers.ts @@ -1,4 +1,4 @@ -export const isNumber = (item: string): boolean => !isNaN(Number(item)); +export const isNumber = (item: string): boolean => !isNaN(Number(item)) && item !== ''; export const hasBrackets = (item: string): boolean => { return item.includes("(") || item.includes(")"); }; diff --git a/src/lesson2/parser.ts b/src/lesson2/parser.ts index 423d9c20..b3cc1b03 100644 --- a/src/lesson2/parser.ts +++ b/src/lesson2/parser.ts @@ -35,7 +35,7 @@ export const parser = (line: string): ParsedLineType | null => { let countOpenBrackets = 0; let countCloseBrackets = 0; - if (item.includes("(") || item.includes(")")) { + if (item.length > 1 && (item.includes("(") || item.includes(")"))) { let numberInsideBrackets = false; const itemLength = item.length; const oldItem = item; @@ -96,6 +96,8 @@ export const parser = (line: string): ParsedLineType | null => { const isValidOperatorPush = isValidScalarOperatorPush || isValidFunctionalOperatorPush; + const isValidBrackets = item.length === 1 && (item === '(' || item === ')') + if (isValidNumberPush) { result.push(Number(item)); if (itemHasCloseBrackets) { @@ -105,6 +107,8 @@ export const parser = (line: string): ParsedLineType | null => { } } else if (isValidOperatorPush) { result.push(item); + } else if (isValidBrackets) { + result.push(item); } else { throw new TypeError("Unexpected string"); } From f7efab734b20c6ea23a4a7f5474728a6c342b724 Mon Sep 17 00:00:00 2001 From: "d.golovko" Date: Mon, 13 Mar 2023 22:39:53 +0300 Subject: [PATCH 4/7] =?UTF-8?q?=D1=81=D0=BA=D0=BE=D0=B1=D0=BA=D0=B8=20?= =?UTF-8?q?=D1=81=20=D0=BF=D1=80=D0=BE=D0=B1=D0=B5=D0=BB=D0=B0=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lesson2/helpers.ts | 3 ++- src/lesson2/parser.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lesson2/helpers.ts b/src/lesson2/helpers.ts index 853927bc..8355dbb2 100644 --- a/src/lesson2/helpers.ts +++ b/src/lesson2/helpers.ts @@ -1,4 +1,5 @@ -export const isNumber = (item: string): boolean => !isNaN(Number(item)) && item !== ''; +export const isNumber = (item: string): boolean => + !isNaN(Number(item)) && item !== ""; export const hasBrackets = (item: string): boolean => { return item.includes("(") || item.includes(")"); }; diff --git a/src/lesson2/parser.ts b/src/lesson2/parser.ts index b3cc1b03..ee0e685f 100644 --- a/src/lesson2/parser.ts +++ b/src/lesson2/parser.ts @@ -96,7 +96,7 @@ export const parser = (line: string): ParsedLineType | null => { const isValidOperatorPush = isValidScalarOperatorPush || isValidFunctionalOperatorPush; - const isValidBrackets = item.length === 1 && (item === '(' || item === ')') + const isValidBrackets = item.length === 1 && (item === "(" || item === ")"); if (isValidNumberPush) { result.push(Number(item)); From 2d744c852eb9367a0cbdd095084cc2953f06d442 Mon Sep 17 00:00:00 2001 From: "d.golovko" Date: Thu, 16 Mar 2023 00:30:18 +0300 Subject: [PATCH 5/7] =?UTF-8?q?=D1=84=D0=B8=D0=BD=D0=B0=D0=BB=D1=8C=D0=BD?= =?UTF-8?q?=D1=8B=D0=B5=20=D0=B4=D0=BE=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lesson2/engine.test.ts | 46 ++++++++++++++++++++----------- src/lesson2/engine.ts | 24 +++++++++++----- src/lesson2/helpers.ts | 5 +--- src/lesson2/mathOperators.test.ts | 33 +++++++++++++++++++++- src/lesson2/mathOperators.ts | 16 +++++++++++ src/lesson2/parser.test.ts | 17 ++++-------- src/lesson2/parser.ts | 37 +++++++++++++------------ src/lesson2/runner.test.ts | 15 ++++++++++ src/lesson2/runner.ts | 20 +++++++------- 9 files changed, 146 insertions(+), 67 deletions(-) diff --git a/src/lesson2/engine.test.ts b/src/lesson2/engine.test.ts index f0c5e094..fe06cdfc 100644 --- a/src/lesson2/engine.test.ts +++ b/src/lesson2/engine.test.ts @@ -1,8 +1,9 @@ import { - fourthPrioritiesCalc, + bracketsProcessing, + firstPrioritiesCalc, secondPrioritiesCalc, thirdPrioritiesCalc, - bracketsProcessing, + fourthPrioritiesCalc } from "./engine"; describe("brackets processing simple cases", () => { @@ -19,6 +20,15 @@ describe("brackets processing simple cases", () => { }); }); +describe("brackets processing simple cases", () => { + it("sin ( 45 + 1 )", () => { + expect(bracketsProcessing(["sin", "(", 45, "+", 1, ")"])).toEqual([ + "sin", + 46 + ]); + }); +}); + describe("brackets processing simple cases", () => { it("1 + (3 + 2 * (3 + 4))", () => { expect( @@ -35,12 +45,26 @@ describe("brackets processing simple cases", () => { "+", 4, ")", - ")", + ")" ]) ).toEqual([1, "+", 17]); }); }); +describe("firstPrioritiesCalc simple cases", () => { + it("sin 45", () => { + expect(firstPrioritiesCalc(["sin", 45])).toEqual([0.85]); + }); + it("cos 45", () => { + expect(firstPrioritiesCalc(["cos", 45])).toEqual([0.53]); + }); + it("tan 45", () => { + expect(firstPrioritiesCalc(["tan", 45])).toEqual([1.62]); + }); + it("sin 45 + 2", () => { + expect(firstPrioritiesCalc(["sin", 45, "+", 2])).toEqual([0.85, "+", 2]); + }); +}); describe("secondPrioritiesCalc simple cases", () => { it("5, +, 4, /, 1, -, 3, **", () => { expect(secondPrioritiesCalc([5, "+", 4, "/", 1, "-", 3, "**"])).toEqual([ @@ -50,18 +74,16 @@ describe("secondPrioritiesCalc simple cases", () => { "/", 1, "-", - 9, + 9 ]); }); -}); -describe("secondPrioritiesCalc simple cases", () => { it("3, **", () => { expect(secondPrioritiesCalc([3, "**", "+", 4, "^", 3])).toEqual([ 9, "+", 4, "^", - 3, + 3 ]); }); }); @@ -70,21 +92,16 @@ describe("thirdPrioritiesCalc simple cases", () => { it("2, '*', 4, '/', 1", () => { expect(thirdPrioritiesCalc([2, "*", 4, "/", 1])).toEqual([8]); }); -}); - -describe("thirdPrioritiesCalc simple cases", () => { it("2, '*', 4, '/', 1, -, 2, ^, 4", () => { expect( thirdPrioritiesCalc([2, "*", 4, "/", 1, "-", 2, "^", 4, "+", 1]) ).toEqual([8, "-", 16, "+", 1]); }); -}); -describe("thirdPrioritiesCalc simple cases", () => { it("2, '*', 4, '/', 1 - 2", () => { expect(thirdPrioritiesCalc([2, "*", 4, "/", 1, "-", 2])).toEqual([ 8, "-", - 2, + 2 ]); }); }); @@ -93,9 +110,6 @@ describe("fourthPrioritiesCalc simple cases", () => { it("2, '+', 4, '-', 1", () => { expect(fourthPrioritiesCalc([2, "+", 4, "-", 1])).toEqual(5); }); -}); - -describe("fourthPrioritiesCalc simple cases", () => { it("2, '-', 4, '-', 10", () => { expect(fourthPrioritiesCalc([2, "-", 4, "-", 10.5])).toEqual(-12.5); }); diff --git a/src/lesson2/engine.ts b/src/lesson2/engine.ts index 18372dc2..6616415c 100644 --- a/src/lesson2/engine.ts +++ b/src/lesson2/engine.ts @@ -6,6 +6,7 @@ import { mathPriorities, mathOperatorsPriorities, functionMathOperators, + trigonometryMathOperators, } from "./mathOperators"; const [FIRST, SECOND, THIRD, FOURTH] = mathPriorities; @@ -29,14 +30,26 @@ export const bracketsProcessing = (stack: ParsedLineType): ParsedLineType => { return stack; }; +export const firstPrioritiesCalc = (stack: ParsedLineType): ParsedLineType => + stack.reduce((result, nextItem) => { + const item = result[result.length - 1]; + + if (!isNumber(String(item)) && mathOperatorsPriorities[item] === FIRST) { + result = [ + ...result.slice(0, -1), + trigonometryMathOperators[item](Number(nextItem)), + ]; + } else { + result.push(nextItem); + } + return result; + }, []); + export const secondPrioritiesCalc = (stack: ParsedLineType): ParsedLineType => stack.reduce((result, item) => { const prevItem = result[result.length - 1]; if (!isNumber(String(item)) && mathOperatorsPriorities[item] === SECOND) { - if (!mathOperators[item]) { - throw new TypeError("Unexpected stack!"); - } result = [ ...result.slice(0, -1), functionMathOperators[item](Number(prevItem)), @@ -52,9 +65,6 @@ export const thirdPrioritiesCalc = (stack: ParsedLineType): ParsedLineType => const item = result[result.length - 1]; if (!isNumber(String(item)) && mathOperatorsPriorities[item] === THIRD) { - if (!mathOperators[item]) { - throw new TypeError("Unexpected stack!"); - } result = [ ...result.slice(0, -2), mathOperators[item](Number(prevItem), Number(nextItem)), @@ -70,5 +80,5 @@ export const fourthPrioritiesCalc = (stack: ParsedLineType): number => if (!isNumber(String(item)) && mathOperatorsPriorities[item] === FOURTH) { result = mathOperators[item](Number(result), Number(nextItem)); } - return result; + return Number(result.toFixed(2)); }, Number(stack[0])); diff --git a/src/lesson2/helpers.ts b/src/lesson2/helpers.ts index 8355dbb2..16387b57 100644 --- a/src/lesson2/helpers.ts +++ b/src/lesson2/helpers.ts @@ -1,5 +1,2 @@ export const isNumber = (item: string): boolean => - !isNaN(Number(item)) && item !== ""; -export const hasBrackets = (item: string): boolean => { - return item.includes("(") || item.includes(")"); -}; + !isNaN(Number(item)) && item !== ""; \ No newline at end of file diff --git a/src/lesson2/mathOperators.test.ts b/src/lesson2/mathOperators.test.ts index 61cf996b..bfe949c4 100644 --- a/src/lesson2/mathOperators.test.ts +++ b/src/lesson2/mathOperators.test.ts @@ -1,4 +1,15 @@ -import { mul, div, add, minus, pow, square } from "./mathOperators"; +import { + mul, + div, + add, + minus, + pow, + square, + factorial, + sin, + cos, + tan, +} from "./mathOperators"; describe("mathOperators test cases", () => { it("mul 1 * 2 to equal 2", () => { @@ -36,4 +47,24 @@ describe("mathOperators test cases", () => { it("square 2 equal 4", () => { expect(square(2)).toBe(4); }); + + it("factorial 5 equal 25", () => { + expect(factorial(5)).toBe(25); + }); + + it("sin 45 equal 0.82", () => { + expect(sin(45)).toBe(0.85); + }); + + it("sin 45 equal 0.82", () => { + expect(sin(45)).toBe(0.85); + }); + + it("cos 45 equal 0.53", () => { + expect(cos(45)).toBe(0.53); + }); + + it("tan 45 equal 0.53", () => { + expect(tan(45)).toBe(1.62); + }); }); diff --git a/src/lesson2/mathOperators.ts b/src/lesson2/mathOperators.ts index 30fe3684..ef12c05f 100644 --- a/src/lesson2/mathOperators.ts +++ b/src/lesson2/mathOperators.ts @@ -30,6 +30,12 @@ export const square: FunctionOperationType = (value: number): number => pow(value, 2); export const factorial: FunctionOperationType = (value: number): number => pow(value, 2); +export const sin: FunctionOperationType = (value: number): number => + Number(Math.sin(value).toFixed(2)); +export const cos: FunctionOperationType = (value: number): number => + Number(Math.cos(value).toFixed(2)); +export const tan: FunctionOperationType = (value: number): number => + Number(Math.tan(value).toFixed(2)); export const scalarMathOperators: { [key: string]: ScalarOperationType } = { "*": mul, "/": div, @@ -43,11 +49,20 @@ export const functionMathOperators: { [key: string]: FunctionOperationType } = { "!": factorial, }; +export const trigonometryMathOperators: { + [key: string]: FunctionOperationType; +} = { + sin: sin, + cos: cos, + tan: tan, +}; + export const mathOperators: { [key: string]: FunctionOperationType | ScalarOperationType; } = { ...scalarMathOperators, ...functionMathOperators, + ...trigonometryMathOperators, }; export const mathPriorities: number[] = [1, 2, 3, 4]; @@ -64,4 +79,5 @@ export const mathOperatorsPriorities: { [key: string]: number } = { "!": SECOND, sin: FIRST, cos: FIRST, + tan: FIRST, }; diff --git a/src/lesson2/parser.test.ts b/src/lesson2/parser.test.ts index 6d414e10..66dd6b22 100644 --- a/src/lesson2/parser.test.ts +++ b/src/lesson2/parser.test.ts @@ -53,7 +53,7 @@ describe("Parser correct cases", () => { "+", 2, ")", - ")", + ")" ]); }); it("5 + (3)", () => { @@ -82,7 +82,7 @@ describe("Parser correct cases", () => { 2, ")", "/", - 2, + 2 ]); }); @@ -97,43 +97,35 @@ describe("Parser invalid cases", () => { TypeError("Unexpected string") ); }); - it("1 ! 33 -", () => { expect(() => parser("1 ! 33 -")).toThrow(TypeError("Unexpected string")); }); - it("** ** **", () => { expect(() => parser("** ** **")).toThrow(TypeError("Unexpected string")); }); it("** 2", () => { expect(() => parser("** 2")).toThrow(TypeError("Unexpected string")); }); - - // brackets it("7 + ((8 * 9) - 3", () => { expect(() => parser("7 + ((8 * 9) - 3")).toThrow( TypeError("Unexpected string") ); }); - it("7 + (8 * 9)) - 3", () => { expect(() => parser("7 + (8 * 9)) - 3")).toThrow( TypeError("Unexpected string") ); }); - it("7 + (8 * 9)) - 3", () => { expect(() => parser("7 + (8 * 9)) - 3")).toThrow( TypeError("Unexpected string") ); }); - it("7 + 2 () + 1", () => { expect(() => parser("7 + 2 () + 1")).toThrow( TypeError("Unexpected string") ); }); - it("5 + ()3)", () => { expect(() => parser("5 + ()3)")).toThrow(TypeError("Unexpected string")); }); @@ -146,14 +138,15 @@ describe("Parser invalid cases", () => { it("(5 + 3))", () => { expect(() => parser("(5 + 3))")).toThrow(TypeError("Unexpected string")); }); - it("(5.2w + 3)", () => { expect(() => parser("(5.2w + 3)")).toThrow(TypeError("Unexpected string")); }); - it("1 + (1+) - 33", () => { expect(() => parser("1 + (1 + ы) - 33")).toThrow( TypeError("Unexpected string") ); }); + it("5 + (3))", () => { + expect(() => parser("5 + (3))")).toThrow(TypeError("Unexpected string")); + }); }); diff --git a/src/lesson2/parser.ts b/src/lesson2/parser.ts index ee0e685f..1874ceab 100644 --- a/src/lesson2/parser.ts +++ b/src/lesson2/parser.ts @@ -1,13 +1,14 @@ import { isNumber } from "./helpers"; import { functionMathOperators, - mathOperators, scalarMathOperators, + trigonometryMathOperators, + mathOperators, } from "./mathOperators"; export type ParsedLineType = (number | string)[]; -export const parser = (line: string): ParsedLineType | null => { +export const parser = (line: string): ParsedLineType => { let _countOpenBrackets = 0; let _countCloseBrackets = 0; for (let i = 0; i < line.length; i++) { @@ -23,7 +24,11 @@ export const parser = (line: string): ParsedLineType | null => { } const stack = line.split(" "); return stack.reduce((result, item, key) => { - if (key === 0 && mathOperators.hasOwnProperty(item)) { + if ( + key === 0 && + mathOperators.hasOwnProperty(item) && + !trigonometryMathOperators.hasOwnProperty(item) + ) { throw new TypeError("Unexpected string"); } @@ -31,6 +36,7 @@ export const parser = (line: string): ParsedLineType | null => { throw new TypeError("Unexpected string"); } const prevItem = stack[key - 1]; + const nextItem = stack[key + 1]; let itemHasCloseBrackets = false; let countOpenBrackets = 0; let countCloseBrackets = 0; @@ -61,13 +67,6 @@ export const parser = (line: string): ParsedLineType | null => { numberInsideBrackets = true; } } - if ( - countOpenBrackets > 0 && - countCloseBrackets > 0 && - countOpenBrackets !== countCloseBrackets - ) { - throw new TypeError("Unexpected string"); - } if (countOpenBrackets > 0) { for (let i = 0; i < countOpenBrackets; i++) { @@ -82,19 +81,23 @@ export const parser = (line: string): ParsedLineType | null => { const isValidNumberPush = !isNumber(prevItem) && isNumber(item); const isValidFunctionalOperatorPush = - isNumber(prevItem) && - !isNumber(item) && - functionMathOperators.hasOwnProperty(item); + isNumber(prevItem) && functionMathOperators.hasOwnProperty(item); + + const isValidTrigonometryOperatorPush = + (isNumber(nextItem) && trigonometryMathOperators.hasOwnProperty(item)) || + ((String(nextItem).indexOf("(") !== -1 || + String(nextItem).indexOf(")") !== -1) && + trigonometryMathOperators.hasOwnProperty(item)); const isValidScalarOperatorPush = - (isNumber(prevItem) && - !isNumber(item) && - scalarMathOperators.hasOwnProperty(item)) || + (isNumber(prevItem) && scalarMathOperators.hasOwnProperty(item)) || (functionMathOperators.hasOwnProperty(prevItem) && scalarMathOperators.hasOwnProperty(item)); const isValidOperatorPush = - isValidScalarOperatorPush || isValidFunctionalOperatorPush; + isValidScalarOperatorPush || + isValidFunctionalOperatorPush || + isValidTrigonometryOperatorPush; const isValidBrackets = item.length === 1 && (item === "(" || item === ")"); diff --git a/src/lesson2/runner.test.ts b/src/lesson2/runner.test.ts index 7f2e1424..0ecc95a0 100644 --- a/src/lesson2/runner.test.ts +++ b/src/lesson2/runner.test.ts @@ -59,3 +59,18 @@ describe("Runner with brackets cases", () => { expect(runner("8 * 4 + 3 * (4 + 8 - (2 ^ 3 + 1))")).toEqual(41); }); }); + +describe("Runner with sin cases", () => { + it("sin ( 45 )", () => { + expect(runner("sin ( 45 )")).toEqual(0.85); + }); +}); + + +describe("Runner with null cases", () => { + it("null", () => { + expect(() => { + runner("") + }).toThrow("Unexpected string"); + }); +}); diff --git a/src/lesson2/runner.ts b/src/lesson2/runner.ts index 92d0acd3..f40e6e0f 100644 --- a/src/lesson2/runner.ts +++ b/src/lesson2/runner.ts @@ -1,25 +1,23 @@ import { parser, ParsedLineType } from "./parser"; import { - fourthPrioritiesCalc, + firstPrioritiesCalc, secondPrioritiesCalc, + fourthPrioritiesCalc, thirdPrioritiesCalc, bracketsProcessing, } from "./engine"; -export const calc = (stack: ParsedLineType | null): number => { - if (stack === null) { - throw new TypeError("Unexpected string"); - } +export const calc = (stack: ParsedLineType): number => { const bracketsProcessingRes = bracketsProcessing(stack); - /* const firstPrioritiesRes = firstPrioritiesCalc(stack); + const firstPrioritiesRes = firstPrioritiesCalc(bracketsProcessingRes); - if (firstPrioritiesRes.length === 1) { - return Number(firstPrioritiesRes[0]); - }*/ + if (firstPrioritiesRes.length === 1) { + return Number(firstPrioritiesRes[0]); + } - const secondPrioritiesRes = secondPrioritiesCalc(bracketsProcessingRes); + const secondPrioritiesRes = secondPrioritiesCalc(firstPrioritiesRes); if (secondPrioritiesRes.length === 1) { return Number(secondPrioritiesRes[0]); @@ -36,5 +34,7 @@ export const calc = (stack: ParsedLineType | null): number => { export const runner = (line: string): number => { const stack = parser(line); + console.log(stack); + return calc(stack); }; From 62204e9c02f35a9b284dfb569cbf32f2eadb9ea0 Mon Sep 17 00:00:00 2001 From: "d.golovko" Date: Thu, 16 Mar 2023 00:33:07 +0300 Subject: [PATCH 6/7] =?UTF-8?q?=D1=84=D0=B8=D0=BD=D0=B0=D0=BB=D1=8C=D0=BD?= =?UTF-8?q?=D1=8B=D0=B5=20=D0=B4=D0=BE=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lesson2/engine.test.ts | 12 ++++++------ src/lesson2/helpers.ts | 2 +- src/lesson2/parser.test.ts | 4 ++-- src/lesson2/runner.test.ts | 3 +-- src/lesson2/runner.ts | 1 - 5 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/lesson2/engine.test.ts b/src/lesson2/engine.test.ts index fe06cdfc..03d27184 100644 --- a/src/lesson2/engine.test.ts +++ b/src/lesson2/engine.test.ts @@ -3,7 +3,7 @@ import { firstPrioritiesCalc, secondPrioritiesCalc, thirdPrioritiesCalc, - fourthPrioritiesCalc + fourthPrioritiesCalc, } from "./engine"; describe("brackets processing simple cases", () => { @@ -24,7 +24,7 @@ describe("brackets processing simple cases", () => { it("sin ( 45 + 1 )", () => { expect(bracketsProcessing(["sin", "(", 45, "+", 1, ")"])).toEqual([ "sin", - 46 + 46, ]); }); }); @@ -45,7 +45,7 @@ describe("brackets processing simple cases", () => { "+", 4, ")", - ")" + ")", ]) ).toEqual([1, "+", 17]); }); @@ -74,7 +74,7 @@ describe("secondPrioritiesCalc simple cases", () => { "/", 1, "-", - 9 + 9, ]); }); it("3, **", () => { @@ -83,7 +83,7 @@ describe("secondPrioritiesCalc simple cases", () => { "+", 4, "^", - 3 + 3, ]); }); }); @@ -101,7 +101,7 @@ describe("thirdPrioritiesCalc simple cases", () => { expect(thirdPrioritiesCalc([2, "*", 4, "/", 1, "-", 2])).toEqual([ 8, "-", - 2 + 2, ]); }); }); diff --git a/src/lesson2/helpers.ts b/src/lesson2/helpers.ts index 16387b57..38a7cd2a 100644 --- a/src/lesson2/helpers.ts +++ b/src/lesson2/helpers.ts @@ -1,2 +1,2 @@ export const isNumber = (item: string): boolean => - !isNaN(Number(item)) && item !== ""; \ No newline at end of file + !isNaN(Number(item)) && item !== ""; diff --git a/src/lesson2/parser.test.ts b/src/lesson2/parser.test.ts index 66dd6b22..47a06d84 100644 --- a/src/lesson2/parser.test.ts +++ b/src/lesson2/parser.test.ts @@ -53,7 +53,7 @@ describe("Parser correct cases", () => { "+", 2, ")", - ")" + ")", ]); }); it("5 + (3)", () => { @@ -82,7 +82,7 @@ describe("Parser correct cases", () => { 2, ")", "/", - 2 + 2, ]); }); diff --git a/src/lesson2/runner.test.ts b/src/lesson2/runner.test.ts index 0ecc95a0..5bd8f7f8 100644 --- a/src/lesson2/runner.test.ts +++ b/src/lesson2/runner.test.ts @@ -66,11 +66,10 @@ describe("Runner with sin cases", () => { }); }); - describe("Runner with null cases", () => { it("null", () => { expect(() => { - runner("") + runner(""); }).toThrow("Unexpected string"); }); }); diff --git a/src/lesson2/runner.ts b/src/lesson2/runner.ts index f40e6e0f..407cc1b1 100644 --- a/src/lesson2/runner.ts +++ b/src/lesson2/runner.ts @@ -8,7 +8,6 @@ import { } from "./engine"; export const calc = (stack: ParsedLineType): number => { - const bracketsProcessingRes = bracketsProcessing(stack); const firstPrioritiesRes = firstPrioritiesCalc(bracketsProcessingRes); From 719927081b6d1379ebcd21af33d029a1f1484d3a Mon Sep 17 00:00:00 2001 From: "d.golovko" Date: Thu, 16 Mar 2023 00:36:14 +0300 Subject: [PATCH 7/7] =?UTF-8?q?=D1=83=D0=B4=D0=B0=D0=BB=D0=B8=D0=BB=20cons?= =?UTF-8?q?ole.log?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lesson2/runner.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lesson2/runner.ts b/src/lesson2/runner.ts index 407cc1b1..9b173805 100644 --- a/src/lesson2/runner.ts +++ b/src/lesson2/runner.ts @@ -33,7 +33,5 @@ export const calc = (stack: ParsedLineType): number => { export const runner = (line: string): number => { const stack = parser(line); - console.log(stack); - return calc(stack); };