Skip to content

Instantly share code, notes, and snippets.

@anhdiepmmk
Last active August 20, 2022 03:16
Show Gist options
  • Save anhdiepmmk/de032bdc34cc9f5b354a0d86c6bc466f to your computer and use it in GitHub Desktop.
Save anhdiepmmk/de032bdc34cc9f5b354a0d86c6bc466f to your computer and use it in GitHub Desktop.
simple calculator
function combine(a, b, operator) {
if (operator === 'x') {
return a * b;
}
if (operator === '/') {
return a / b;
}
if (operator === '+') {
return a + b;
}
if (operator === '-') {
return a - b;
}
throw new Error(`Invalid operator: ${operator}`);
}
function removeNullElements(elements) {
while (elements.includes(null)) {
const index = elements.findIndex((element) => element === null);
elements.splice(index, 1);
}
}
function compact(originalElements, operator) {
const elements = originalElements;
while (elements.includes(operator)) {
const index = elements.findIndex((element) => element === operator);
const leftIndex = index - 1;
const rightIndex = index + 1;
const leftValue = parseFloat(elements[leftIndex]);
const rightValue = parseFloat(elements[rightIndex]);
// update operator to new value
elements[index] = combine(leftValue, rightValue, operator);
// mark to delete
elements[leftIndex] = null;
elements[rightIndex] = null;
removeNullElements(elements);
}
}
function calculate(elements) {
compact(elements, 'x');
compact(elements, '/');
compact(elements, '+');
compact(elements, '-');
if (elements.length > 1) {
throw new Error(
`there are some invalid elements ${JSON.stringify(elements)}`,
);
}
return elements[0];
}
function convertElements2String(elements) {
return elements.join(' ');
}
const caculatorService = require('./calculator');
describe('calculate', () => {
test('given invalid elements then throw an error', () => {
expect(() => caculatorService.calculate([1, 2, 1])).toThrowError(
new Error(`there are some invalid elements ${JSON.stringify([1, 2, 1])}`),
);
});
describe('simple', () => {
test('should return 2', () => {
expect(caculatorService.calculate([1, '+', 1])).toBe(2);
});
test('should return 0', () => {
expect(caculatorService.calculate([1, '-', 1])).toBe(0);
});
test('should return 4', () => {
expect(caculatorService.calculate([2, 'x', 2])).toBe(4);
});
test('should return 0.5', () => {
expect(caculatorService.calculate([1, '/', 2])).toBe(0.5);
});
});
describe('priority', () => {
test('should return 21', () => {
expect(caculatorService.calculate([3, '+', 3, 'x', 6])).toBe(21);
});
test('should return 31', () => {
expect(caculatorService.calculate([3, '+', 4, 'x', 7])).toBe(31);
});
test('should return 26', () => {
expect(caculatorService.calculate([6, '+', 4, 'x', 5])).toBe(26);
});
test('should return 10', () => {
expect(caculatorService.calculate([5, 'x', 6, '/', 3])).toBe(10);
});
});
});
describe('combine', () => {
test('should return a value', () => {
expect(caculatorService.combine(1, 2, '+')).toBe(3);
expect(caculatorService.combine(2, 2, '-')).toBe(0);
expect(caculatorService.combine(3, 2, 'x')).toBe(6);
expect(caculatorService.combine(1, 2, '/')).toBe(0.5);
});
test('given invalid operator then throw an error', () => {
expect(() => caculatorService.combine(1, 2, '*')).toThrowError(
new Error('Invalid operator: *'),
);
});
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
#result {
border: 1px solid rebeccapurple;
height: 2rem;
border-radius: 1px;
}
</style>
</head>
<body>
<div>
<div id="result"></div>
<div>
<button class="numbers">1</button>
<button class="numbers">2</button>
<button class="numbers">3</button>
<button class="numbers">4</button>
<button class="numbers">5</button>
</div>
<div>
<button class="numbers">6</button>
<button class="numbers">7</button>
<button class="numbers">8</button>
<button class="numbers">9</button>
<button class="numbers">0</button>
</div>
<div>
<button class="operators">+</button>
<button class="operators">-</button>
<button class="operators">x</button>
<button class="operators">/</button>
<button id="backspace">backspace</button>
<button id="clear">clear</button>
<button id="enter">=</button>
</div>
</div>
<script type="text/javascript" src="calculator.js"></script>
<script type="text/javascript" src="main.js"></script>
</body>
</html>
module.exports = {
testEnvironment: "jsdom",
};
const OPERATORS = ['+', '-', 'x', '/'];
const btnNumbers = document.getElementsByClassName('numbers');
const btnOperators = document.getElementsByClassName('operators');
const divResult = document.getElementById('result');
// ['3', '+', '4.1']
const inputs = [];
for (const btnNumber of btnNumbers) {
btnNumber.addEventListener('click', (event) => {
const lastElement = inputs.at(-1);
if (lastElement === undefined || OPERATORS.includes(lastElement)) {
// insert new element
inputs.push(event.target.textContent);
} else {
// merge with last element
inputs[inputs.length - 1] =
`${lastElement}${event.target.textContent}`
}
divResult.innerText = convertElements2String(inputs);
});
}
for (const btnOperator of btnOperators) {
btnOperator.addEventListener('click', (event) => {
const lastElement = inputs.at(-1);
if (lastElement !== undefined && !OPERATORS.includes(lastElement)) {
inputs.push(event.target.textContent);
divResult.innerText = convertElements2String(inputs);
}
});
}
document.getElementById('enter').addEventListener('click', (event) => {
const lastElement = inputs.at(-1);
if (lastElement !== undefined && !OPERATORS.includes(lastElement)) {
const result = calculate(inputs);
// remove all elements
inputs.length = 0;
divResult.innerText = result;
}
});
document.getElementById('backspace').addEventListener('click', () => {
const lastElement = inputs.at(-1);
if (lastElement !== undefined) {
if (OPERATORS.includes(lastElement)) {
inputs.pop();
} else {
// remove last charater
const updatedLastElement = lastElement.slice(0, -1);
if (updatedLastElement === '') {
inputs.pop();
} else {
inputs[inputs.length - 1] = updatedLastElement;
}
}
divResult.innerText = convertElements2String(inputs);
}
});
document.getElementById('clear').addEventListener('click', () => {
// remove all elements
inputs.length = 0;
divResult.innerText = convertElements2String(inputs);
});
document.getElementById('point').addEventListener('click', () => {
const lastElement = inputs.at(-1);
if (lastElement !== undefined && !OPERATORS.includes(lastElement) && !`${lastElement}`.includes('.')) {
// append point (.)
inputs[inputs.length - 1] =
`${lastElement}.`;
divResult.innerText = convertElements2String(inputs);
}
});
describe("do some thing", () => {
it("should abc", () => {
document.body.innerHTML = "<div>hello world</div>";
expect(document.body.innerHTML).toBe("<div>hello world</div>");
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment