Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 96 additions & 27 deletions src/lesson2/engine.test.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,116 @@
import { firstPrioritiesCalc, secondPrioritiesCalc } from "./engine";
import {
bracketsProcessing,
firstPrioritiesCalc,
secondPrioritiesCalc,
thirdPrioritiesCalc,
fourthPrioritiesCalc,
} from "./engine";

describe("firstPrioritiesCalc simple cases", () => {
it("[1, * 32]", () => {
expect(firstPrioritiesCalc([1, "*", 32])).toEqual([32]);
});

it("[32, /, 32]", () => {
expect(firstPrioritiesCalc([32, "/", 32])).toEqual([1]);
describe("brackets processing simple cases", () => {
it("(5, +, 4, ), /, (, 5, -, 3, )", () => {
expect(
bracketsProcessing(["(", 5, "+", 4, ")", "/", "(", 5, "-", 3, ")"])
).toEqual([9, "/", 2]);
});
});

it("[32, + 32]", () => {
expect(firstPrioritiesCalc([32, "+", 32])).toEqual([32, "+", 32]);
describe("brackets processing simple cases", () => {
it("(5+5)", () => {
expect(bracketsProcessing(["(", 5, "+", 5, ")"])).toEqual([10]);
});
});

describe("firstPrioritiesCalc mixed with second priorities cases", () => {
it("[32, /, 32, +, 10, *, 10]", () => {
expect(firstPrioritiesCalc([32, "/", 32, "+", 10, "*", 10])).toEqual([
1,
"+",
100,
describe("brackets processing simple cases", () => {
it("sin ( 45 + 1 )", () => {
expect(bracketsProcessing(["sin", "(", 45, "+", 1, ")"])).toEqual([
"sin",
46,
]);
});
});

describe("secondPrioritiesCalc invalid cases", () => {
it("[32, / 32]", () => {
expect(() => secondPrioritiesCalc([32, "/", 32])).toThrow(
TypeError("Unexpected stack!")
);
describe("brackets processing simple cases", () => {
it("1 + (3 + 2 * (3 + 4))", () => {
expect(
bracketsProcessing([
1,
"+",
"(",
3,
"+",
2,
"*",
"(",
3,
"+",
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("[32, + 32]", () => {
expect(secondPrioritiesCalc([32, "+", 32])).toEqual(64);
it("5, +, 4, /, 1, -, 3, **", () => {
expect(secondPrioritiesCalc([5, "+", 4, "/", 1, "-", 3, "**"])).toEqual([
5,
"+",
4,
"/",
1,
"-",
9,
]);
});
it("3, **", () => {
expect(secondPrioritiesCalc([3, "**", "+", 4, "^", 3])).toEqual([
9,
"+",
4,
"^",
3,
]);
});
});

it("[32, - 32]", () => {
expect(secondPrioritiesCalc([32, "-", 32])).toEqual(0);
describe("thirdPrioritiesCalc simple cases", () => {
it("2, '*', 4, '/', 1", () => {
expect(thirdPrioritiesCalc([2, "*", 4, "/", 1])).toEqual([8]);
});
it("2, '*', 4, '/', 1, -, 2, ^, 4", () => {
expect(
thirdPrioritiesCalc([2, "*", 4, "/", 1, "-", 2, "^", 4, "+", 1])
).toEqual([8, "-", 16, "+", 1]);
});
it("2, '*', 4, '/', 1 - 2", () => {
expect(thirdPrioritiesCalc([2, "*", 4, "/", 1, "-", 2])).toEqual([
8,
"-",
2,
]);
});
});

it("[32, - 32, +, 10]", () => {
expect(secondPrioritiesCalc([32, "-", 32, "+", 10])).toEqual(10);
describe("fourthPrioritiesCalc simple cases", () => {
it("2, '+', 4, '-', 1", () => {
expect(fourthPrioritiesCalc([2, "+", 4, "-", 1])).toEqual(5);
});
it("2, '-', 4, '-', 10", () => {
expect(fourthPrioritiesCalc([2, "-", 4, "-", 10.5])).toEqual(-12.5);
});
});
70 changes: 56 additions & 14 deletions src/lesson2/engine.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,84 @@
import { ParsedLineType } from "./parser";
import { isNumber } from "./helpers";
import { calc } from "./runner";
import {
mathOperators,
mathPriorities,
mathOperatorsPriorities,
functionMathOperators,
trigonometryMathOperators,
} from "./mathOperators";

const [FIRST, SECOND] = mathPriorities;
const [FIRST, SECOND, THIRD, FOURTH] = mathPriorities;

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 firstPrioritiesCalc = (stack: ParsedLineType): ParsedLineType =>
stack.reduce<ParsedLineType>((result, nextItem) => {
const prevItem = result[result.length - 2];
const item = result[result.length - 1];

if (!isNumber(String(item)) && mathOperatorsPriorities[item] === FIRST) {
if (!mathOperators[item]) {
throw new TypeError("Unexpected stack!");
}
result = [
...result.slice(0, -2),
mathOperators[item](Number(prevItem), Number(nextItem)),
...result.slice(0, -1),
trigonometryMathOperators[item](Number(nextItem)),
];
} else {
result.push(nextItem);
}
return result;
}, []);

export const secondPrioritiesCalc = (stack: ParsedLineType): number =>
stack.reduce<number>((result, nextItem, key) => {
const item = stack[key - 1];
export const secondPrioritiesCalc = (stack: ParsedLineType): ParsedLineType =>
stack.reduce<ParsedLineType>((result, item) => {
const prevItem = result[result.length - 1];

if (mathOperatorsPriorities[item] === FIRST) {
throw new TypeError("Unexpected stack!");
if (!isNumber(String(item)) && mathOperatorsPriorities[item] === SECOND) {
result = [
...result.slice(0, -1),
functionMathOperators[item](Number(prevItem)),
];
} else {
result.push(item);
}
return result;
}, []);
export const thirdPrioritiesCalc = (stack: ParsedLineType): ParsedLineType =>
stack.reduce<ParsedLineType>((result, nextItem) => {
const prevItem = result[result.length - 2];
const item = result[result.length - 1];

if (!isNumber(String(item)) && mathOperatorsPriorities[item] === SECOND) {
result = mathOperators[item](Number(result), Number(nextItem));
if (!isNumber(String(item)) && mathOperatorsPriorities[item] === THIRD) {
result = [
...result.slice(0, -2),
mathOperators[item](Number(prevItem), Number(nextItem)),
];
} else {
result.push(nextItem);
}
return result;
}, []);
export const fourthPrioritiesCalc = (stack: ParsedLineType): number =>
stack.reduce<number>((result, nextItem, key) => {
const item = stack[key - 1];
if (!isNumber(String(item)) && mathOperatorsPriorities[item] === FOURTH) {
result = mathOperators[item](Number(result), Number(nextItem));
}
return Number(result.toFixed(2));
}, Number(stack[0]));
3 changes: 2 additions & 1 deletion src/lesson2/helpers.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export const isNumber = (item: string): boolean => !isNaN(Number(item));
export const isNumber = (item: string): boolean =>
!isNaN(Number(item)) && item !== "";
2 changes: 1 addition & 1 deletion src/lesson2/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const rl = createInterface({
const question = (): Promise<null> =>
new Promise((resolve) => {
rl.question("> ", (answer: string) => {
const result = runner(answer);
const result = runner(answer.trim());

if (result) {
console.log(`Result: ${result}`);
Expand Down
47 changes: 45 additions & 2 deletions src/lesson2/mathOperators.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
import { mul, div, add, minus } 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", () => {
expect(mul(1, 2)).toBe(2);
expect(mul(1, 3)).toBe(3);
});

it("mul 2 * 2 to equal 4", () => {
Expand All @@ -24,4 +35,36 @@ 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);
});

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);
});
});
58 changes: 51 additions & 7 deletions src/lesson2/mathOperators.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export type ScalarOperationType = (first: number, second: number) => number;
export type FunctionOperationType = (first: number, second?: number) => number;

export const mul: ScalarOperationType = (
first: number,
Expand All @@ -20,20 +21,63 @@ export const minus: ScalarOperationType = (
second: number
): number => first - second;

export const mathOperators: { [key: string]: ScalarOperationType } = {
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 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,
"+": add,
"-": minus,
"^": pow,
};

export const functionMathOperators: { [key: string]: FunctionOperationType } = {
"**": square,
"!": 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];
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,
"**": SECOND,
"!": SECOND,
sin: FIRST,
cos: FIRST,
tan: FIRST,
};
Loading