mirror of
https://github.com/TheAlgorithms/JavaScript.git
synced 2025-07-05 08:16:50 +08:00
feat: Test running overhaul, switch to Prettier & reformat everything (#1407)
* chore: Switch to Node 20 + Vitest * chore: migrate to vitest mock functions * chore: code style (switch to prettier) * test: re-enable long-running test Seems the switch to Node 20 and Vitest has vastly improved the code's and / or the test's runtime! see #1193 * chore: code style * chore: fix failing tests * Updated Documentation in README.md * Update contribution guidelines to state usage of Prettier * fix: set prettier printWidth back to 80 * chore: apply updated code style automatically * fix: set prettier line endings to lf again * chore: apply updated code style automatically --------- Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com>
This commit is contained in:
7
.github/workflows/Ci.yml
vendored
7
.github/workflows/Ci.yml
vendored
@ -15,20 +15,15 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 20
|
||||
cache: npm
|
||||
|
||||
- name: 📦 Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: 🧪 Run all tests
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
run: npm run test
|
||||
|
||||
- name: 🧪 Run tests for changed files only
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
run: npm run test-changed
|
||||
|
||||
- name: 💄 Code style
|
||||
run: npm run style
|
||||
|
||||
|
@ -63,7 +63,7 @@ globby([
|
||||
"!**/test/**/*",
|
||||
'!**/*.test.js',
|
||||
'!**/*.manual-test.js',
|
||||
'!babel.config.js'
|
||||
'!vitest.config.ts'
|
||||
])
|
||||
// create markdown content
|
||||
.then(pathsToMarkdown)
|
5
.github/workflows/UpdateDirectory.yml
vendored
5
.github/workflows/UpdateDirectory.yml
vendored
@ -11,16 +11,17 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 20
|
||||
cache: npm
|
||||
|
||||
- name: 📦 Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: 🗄️ Create Directory from JS files
|
||||
run: node .github/workflows/UpdateDirectory.mjs
|
||||
run: node .github/workflows/UpdateDirectory.js
|
||||
|
||||
- name: Configure Github Action
|
||||
run: |
|
||||
|
@ -2,4 +2,4 @@
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npm run style
|
||||
npm run test-changed
|
||||
npm run test
|
||||
|
2
.prettierignore
Normal file
2
.prettierignore
Normal file
@ -0,0 +1,2 @@
|
||||
.github
|
||||
DIRECTORY.md
|
@ -22,14 +22,14 @@
|
||||
*/
|
||||
|
||||
class Combinations {
|
||||
constructor (n, k) {
|
||||
constructor(n, k) {
|
||||
this.n = n
|
||||
this.k = k
|
||||
this.current = [] // will be used for storing current combination
|
||||
this.combinations = []
|
||||
}
|
||||
|
||||
findCombinations (high = this.n, total = this.k, low = 1) {
|
||||
findCombinations(high = this.n, total = this.k, low = 1) {
|
||||
if (total === 0) {
|
||||
this.combinations.push([...this.current])
|
||||
return this.combinations
|
||||
|
@ -10,14 +10,14 @@
|
||||
*/
|
||||
|
||||
const swap = (arr, i, j) => {
|
||||
const newArray = [...arr];
|
||||
const newArray = [...arr]
|
||||
|
||||
[newArray[i], newArray[j]] = [newArray[j], newArray[i]] // Swapping elements ES6 way
|
||||
;[newArray[i], newArray[j]] = [newArray[j], newArray[i]] // Swapping elements ES6 way
|
||||
|
||||
return newArray
|
||||
}
|
||||
|
||||
const permutations = arr => {
|
||||
const permutations = (arr) => {
|
||||
const P = []
|
||||
const permute = (arr, low, high) => {
|
||||
if (low === high) {
|
||||
|
@ -1,12 +1,12 @@
|
||||
// Wikipedia: https://en.wikipedia.org/wiki/Knight%27s_tour
|
||||
|
||||
class OpenKnightTour {
|
||||
constructor (size) {
|
||||
constructor(size) {
|
||||
this.board = new Array(size).fill(0).map(() => new Array(size).fill(0))
|
||||
this.size = size
|
||||
}
|
||||
|
||||
getMoves ([i, j]) {
|
||||
getMoves([i, j]) {
|
||||
// helper function to get the valid moves of the knight from the current position
|
||||
const moves = [
|
||||
[i + 2, j - 1],
|
||||
@ -19,15 +19,17 @@ class OpenKnightTour {
|
||||
[i - 1, j + 2]
|
||||
]
|
||||
|
||||
return moves.filter(([y, x]) => y >= 0 && y < this.size && x >= 0 && x < this.size)
|
||||
return moves.filter(
|
||||
([y, x]) => y >= 0 && y < this.size && x >= 0 && x < this.size
|
||||
)
|
||||
}
|
||||
|
||||
isComplete () {
|
||||
isComplete() {
|
||||
// helper function to check if the board is complete
|
||||
return !this.board.map(row => row.includes(0)).includes(true)
|
||||
return !this.board.map((row) => row.includes(0)).includes(true)
|
||||
}
|
||||
|
||||
solve () {
|
||||
solve() {
|
||||
// function to find the solution for the given board
|
||||
for (let i = 0; i < this.size; i++) {
|
||||
for (let j = 0; j < this.size; j++) {
|
||||
@ -37,7 +39,7 @@ class OpenKnightTour {
|
||||
return false
|
||||
}
|
||||
|
||||
solveHelper ([i, j], curr) {
|
||||
solveHelper([i, j], curr) {
|
||||
// helper function for the main computation
|
||||
if (this.isComplete()) return true
|
||||
|
||||
@ -52,7 +54,7 @@ class OpenKnightTour {
|
||||
return false
|
||||
}
|
||||
|
||||
printBoard (output = value => console.log(value)) {
|
||||
printBoard(output = (value) => console.log(value)) {
|
||||
// utility function to display the board
|
||||
for (const row of this.board) {
|
||||
let string = ''
|
||||
|
@ -1,5 +1,5 @@
|
||||
class NQueens {
|
||||
constructor (size) {
|
||||
constructor(size) {
|
||||
if (size < 0) {
|
||||
throw RangeError('Invalid board size')
|
||||
}
|
||||
@ -8,7 +8,7 @@ class NQueens {
|
||||
this.solutionCount = 0
|
||||
}
|
||||
|
||||
isValid ([row, col]) {
|
||||
isValid([row, col]) {
|
||||
// function to check if the placement of the queen in the given location is valid
|
||||
|
||||
// checking the left of the current row
|
||||
@ -29,15 +29,15 @@ class NQueens {
|
||||
return true
|
||||
}
|
||||
|
||||
placeQueen (row, col) {
|
||||
placeQueen(row, col) {
|
||||
this.board[row][col] = 'Q'
|
||||
}
|
||||
|
||||
removeQueen (row, col) {
|
||||
removeQueen(row, col) {
|
||||
this.board[row][col] = '.'
|
||||
}
|
||||
|
||||
solve (col = 0) {
|
||||
solve(col = 0) {
|
||||
if (col >= this.size) {
|
||||
this.solutionCount++
|
||||
return true
|
||||
@ -54,7 +54,7 @@ class NQueens {
|
||||
return false
|
||||
}
|
||||
|
||||
printBoard (output = value => console.log(value)) {
|
||||
printBoard(output = (value) => console.log(value)) {
|
||||
if (!output._isMockFunction) {
|
||||
output('\n')
|
||||
}
|
||||
|
@ -21,19 +21,23 @@
|
||||
* @param grid The grid to check.
|
||||
* @throws TypeError When the given grid is invalid.
|
||||
*/
|
||||
function validateGrid (grid) {
|
||||
if (!Array.isArray(grid) || grid.length === 0) throw new TypeError('Grid must be a non-empty array')
|
||||
function validateGrid(grid) {
|
||||
if (!Array.isArray(grid) || grid.length === 0)
|
||||
throw new TypeError('Grid must be a non-empty array')
|
||||
|
||||
const allRowsHaveCorrectLength = grid.every(row => row.length === grid.length)
|
||||
const allRowsHaveCorrectLength = grid.every(
|
||||
(row) => row.length === grid.length
|
||||
)
|
||||
if (!allRowsHaveCorrectLength) throw new TypeError('Grid must be a square')
|
||||
|
||||
const allCellsHaveValidValues = grid.every(row => {
|
||||
return row.every(cell => cell === 0 || cell === 1)
|
||||
const allCellsHaveValidValues = grid.every((row) => {
|
||||
return row.every((cell) => cell === 0 || cell === 1)
|
||||
})
|
||||
if (!allCellsHaveValidValues) throw new TypeError('Grid must only contain 0s and 1s')
|
||||
if (!allCellsHaveValidValues)
|
||||
throw new TypeError('Grid must only contain 0s and 1s')
|
||||
}
|
||||
|
||||
function isSafe (grid, x, y) {
|
||||
function isSafe(grid, x, y) {
|
||||
const n = grid.length
|
||||
return x >= 0 && x < n && y >= 0 && y < n && grid[y][x] === 1
|
||||
}
|
||||
@ -48,7 +52,7 @@ function isSafe (grid, x, y) {
|
||||
* @param path The path we took to get from the source cell to the current location.
|
||||
* @returns {string|boolean} Either the path to the target cell or false.
|
||||
*/
|
||||
function getPathPart (grid, x, y, solution, path) {
|
||||
function getPathPart(grid, x, y, solution, path) {
|
||||
const n = grid.length
|
||||
|
||||
// are we there yet?
|
||||
@ -89,7 +93,7 @@ function getPathPart (grid, x, y, solution, path) {
|
||||
return false
|
||||
}
|
||||
|
||||
function getPath (grid) {
|
||||
function getPath(grid) {
|
||||
// grid dimensions
|
||||
const n = grid.length
|
||||
|
||||
@ -108,7 +112,7 @@ function getPath (grid) {
|
||||
* Creates an instance of the "rat in a maze" based on a given grid (maze).
|
||||
*/
|
||||
export class RatInAMaze {
|
||||
constructor (grid) {
|
||||
constructor(grid) {
|
||||
// first, let's do some error checking on the input
|
||||
validateGrid(grid)
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
class Sudoku {
|
||||
// Sudoku Class to hold the board and related functions
|
||||
constructor (board) {
|
||||
constructor(board) {
|
||||
this.board = board
|
||||
}
|
||||
|
||||
findEmptyCell () {
|
||||
findEmptyCell() {
|
||||
// Find a empty cell in the board (returns [-1, -1] if all cells are filled)
|
||||
for (let i = 0; i < 9; i++) {
|
||||
for (let j = 0; j < 9; j++) {
|
||||
@ -14,7 +14,7 @@ class Sudoku {
|
||||
return [-1, -1]
|
||||
}
|
||||
|
||||
check ([y, x], value) {
|
||||
check([y, x], value) {
|
||||
// checks if the value to be added in the board is an acceptable value for the cell
|
||||
|
||||
// checking through the row
|
||||
@ -29,8 +29,8 @@ class Sudoku {
|
||||
// checking through the 3x3 block of the cell
|
||||
const secRow = Math.floor(y / 3)
|
||||
const secCol = Math.floor(x / 3)
|
||||
for (let i = (secRow * 3); i < ((secRow * 3) + 3); i++) {
|
||||
for (let j = (secCol * 3); j < ((secCol * 3) + 3); j++) {
|
||||
for (let i = secRow * 3; i < secRow * 3 + 3; i++) {
|
||||
for (let j = secCol * 3; j < secCol * 3 + 3; j++) {
|
||||
if (y !== i && x !== j && this.board[i][j] === value) return false
|
||||
}
|
||||
}
|
||||
@ -38,7 +38,7 @@ class Sudoku {
|
||||
return true
|
||||
}
|
||||
|
||||
solve () {
|
||||
solve() {
|
||||
const [y, x] = this.findEmptyCell()
|
||||
|
||||
// checking if the board is complete
|
||||
@ -56,20 +56,23 @@ class Sudoku {
|
||||
return false
|
||||
}
|
||||
|
||||
getSection (row, [start, end]) {
|
||||
getSection(row, [start, end]) {
|
||||
return this.board[row].slice(start, end)
|
||||
}
|
||||
|
||||
printBoard (output = (...v) => console.log(...v)) {
|
||||
printBoard(output = (...v) => console.log(...v)) {
|
||||
// helper function to display board
|
||||
for (let i = 0; i < 9; i++) {
|
||||
if (i % 3 === 0 && i !== 0) {
|
||||
output('- - - - - - - - - - - -')
|
||||
}
|
||||
output(
|
||||
...this.getSection(i, [0, 3]), ' | ',
|
||||
...this.getSection(i, [3, 6]), ' | ',
|
||||
...this.getSection(i, [6, 9]))
|
||||
...this.getSection(i, [0, 3]),
|
||||
' | ',
|
||||
...this.getSection(i, [3, 6]),
|
||||
' | ',
|
||||
...this.getSection(i, [6, 9])
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,22 @@ import { Combinations } from '../AllCombinationsOfSizeK'
|
||||
describe('AllCombinationsOfSizeK', () => {
|
||||
it('should return 3x2 matrix solution for n = 3 and k = 2', () => {
|
||||
const test1 = new Combinations(3, 2)
|
||||
expect(test1.findCombinations()).toEqual([[1, 2], [1, 3], [2, 3]])
|
||||
expect(test1.findCombinations()).toEqual([
|
||||
[1, 2],
|
||||
[1, 3],
|
||||
[2, 3]
|
||||
])
|
||||
})
|
||||
|
||||
it('should return 6x2 matrix solution for n = 4 and k = 2', () => {
|
||||
const test2 = new Combinations(4, 2)
|
||||
expect(test2.findCombinations()).toEqual([[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]])
|
||||
expect(test2.findCombinations()).toEqual([
|
||||
[1, 2],
|
||||
[1, 3],
|
||||
[1, 4],
|
||||
[2, 3],
|
||||
[2, 4],
|
||||
[3, 4]
|
||||
])
|
||||
})
|
||||
})
|
||||
|
@ -1,5 +1,11 @@
|
||||
import { generateParentheses } from '../generateParentheses'
|
||||
|
||||
test('generate all valid parentheses of input 3', () => {
|
||||
expect(generateParentheses(3)).toStrictEqual(['((()))', '(()())', '(())()', '()(())', '()()()'])
|
||||
expect(generateParentheses(3)).toStrictEqual([
|
||||
'((()))',
|
||||
'(()())',
|
||||
'(())()',
|
||||
'()(())',
|
||||
'()()()'
|
||||
])
|
||||
})
|
||||
|
@ -14,6 +14,8 @@ describe('NQueens', () => {
|
||||
})
|
||||
|
||||
it('should throw RangeError for negative size board', () => {
|
||||
expect(() => { return new NQueens(-1) }).toThrow(RangeError)
|
||||
expect(() => {
|
||||
return new NQueens(-1)
|
||||
}).toThrow(RangeError)
|
||||
})
|
||||
})
|
||||
|
@ -7,14 +7,18 @@ describe('RatInAMaze', () => {
|
||||
for (const value of values) {
|
||||
// we deliberately want to check whether this constructor call fails or not
|
||||
// eslint-disable-next-line no-new
|
||||
expect(() => { new RatInAMaze(value) }).toThrow()
|
||||
expect(() => {
|
||||
new RatInAMaze(value)
|
||||
}).toThrow()
|
||||
}
|
||||
})
|
||||
|
||||
it('should fail for an empty array', () => {
|
||||
// we deliberately want to check whether this constructor call fails or not
|
||||
// eslint-disable-next-line no-new
|
||||
expect(() => { new RatInAMaze([]) }).toThrow()
|
||||
expect(() => {
|
||||
new RatInAMaze([])
|
||||
}).toThrow()
|
||||
})
|
||||
|
||||
it('should fail for a non-square array', () => {
|
||||
@ -25,7 +29,9 @@ describe('RatInAMaze', () => {
|
||||
|
||||
// we deliberately want to check whether this constructor call fails or not
|
||||
// eslint-disable-next-line no-new
|
||||
expect(() => { new RatInAMaze(array) }).toThrow()
|
||||
expect(() => {
|
||||
new RatInAMaze(array)
|
||||
}).toThrow()
|
||||
})
|
||||
|
||||
it('should fail for arrays containing invalid values', () => {
|
||||
@ -34,7 +40,9 @@ describe('RatInAMaze', () => {
|
||||
for (const value of values) {
|
||||
// we deliberately want to check whether this constructor call fails or not
|
||||
// eslint-disable-next-line no-new
|
||||
expect(() => { new RatInAMaze(value) }).toThrow()
|
||||
expect(() => {
|
||||
new RatInAMaze(value)
|
||||
}).toThrow()
|
||||
}
|
||||
})
|
||||
|
||||
@ -51,13 +59,20 @@ describe('RatInAMaze', () => {
|
||||
})
|
||||
|
||||
it('should work for a simple 3x3 maze', () => {
|
||||
const maze = new RatInAMaze([[1, 1, 0], [0, 1, 0], [0, 1, 1]])
|
||||
const maze = new RatInAMaze([
|
||||
[1, 1, 0],
|
||||
[0, 1, 0],
|
||||
[0, 1, 1]
|
||||
])
|
||||
expect(maze.solved).toBe(true)
|
||||
expect(maze.path).toBe('RDDR')
|
||||
})
|
||||
|
||||
it('should work for a simple 2x2 that can not be solved', () => {
|
||||
const maze = new RatInAMaze([[1, 0], [0, 1]])
|
||||
const maze = new RatInAMaze([
|
||||
[1, 0],
|
||||
[0, 1]
|
||||
])
|
||||
expect(maze.solved).toBe(false)
|
||||
expect(maze.path).toBe('')
|
||||
})
|
||||
|
@ -28,7 +28,9 @@ describe('Sudoku', () => {
|
||||
it('should create a valid board successfully', () => {
|
||||
// we deliberately want to check whether this constructor call fails or not
|
||||
// eslint-disable-next-line no-new
|
||||
expect(() => { new Sudoku(data) }).not.toThrow()
|
||||
expect(() => {
|
||||
new Sudoku(data)
|
||||
}).not.toThrow()
|
||||
})
|
||||
|
||||
it('should find an empty cell', () => {
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
*/
|
||||
|
||||
function BinaryCountSetBits (a) {
|
||||
function BinaryCountSetBits(a) {
|
||||
'use strict'
|
||||
|
||||
// check whether input is an integer, some non-integer number like, 21.1 have non-terminating binary expansions and hence their binary expansion will contain infinite ones, thus the handling of non-integers (including strings,objects etc. as it is meaningless) has been omitted
|
||||
|
@ -12,6 +12,6 @@
|
||||
* const result = isPowerOfFour(16); // Returns true (16 is 4^2)
|
||||
* const result2 = isPowerOfFour(5); // Returns false (5 is not a power of four)
|
||||
*/
|
||||
const isPowerOfFour = (n) => ((n > 0) && ((n & n - 1) === 0) && (n % 3 === 1))
|
||||
const isPowerOfFour = (n) => n > 0 && (n & (n - 1)) === 0 && n % 3 === 1
|
||||
|
||||
export { isPowerOfFour }
|
||||
|
@ -94,8 +94,8 @@ Be confident that your code works. When was the last time you committed a code c
|
||||
your app stopped working? Mine was last week. Writing tests for our Algorithms will help us ensure the implementations
|
||||
are airtight even after multiple fixes and code changes.
|
||||
|
||||
We use [Jest](https://jestjs.io/) to run unit tests on our algorithms. It provides a very readable and expressive way to
|
||||
structure your test code.
|
||||
We use [Vitest](https://vitest.dev/) to run unit tests on our algorithms. It provides a very readable and expressive
|
||||
way to structure your test code.
|
||||
|
||||
It is advised that the algorithm file (module) does not contain any "live" code but rather just exports the function(s)
|
||||
needed to execute the algorithm. Your test code can import those function(s), call them with the appropriate parameters
|
||||
@ -122,34 +122,23 @@ If you want to save some time and just run a specific test:
|
||||
npm test -- koch
|
||||
```
|
||||
|
||||
You can also start Jest in "watch" mode:
|
||||
You can also start Vitest in "watch" mode:
|
||||
|
||||
```bash
|
||||
npm test -- --watchAll
|
||||
```
|
||||
|
||||
We also prepared a helper script that runs tests only for changed files:
|
||||
|
||||
```bash
|
||||
npm run test-changed
|
||||
npm test-watch
|
||||
```
|
||||
|
||||
This will run all tests and watch source and test files for changes. When a change is made, the tests will run again.
|
||||
|
||||
#### Coding Style
|
||||
|
||||
To maximize the readability and correctness of our code, we require that new submissions follow the
|
||||
[JavaScript Standard Style](https://standardjs.com/).
|
||||
|
||||
Before committing, please run:
|
||||
For consistency and readability, we require that new submissions follow the [Prettier Style](https://prettier.io/).
|
||||
Before committing, please format your code automatically using Prettier by running the following command:
|
||||
|
||||
```bash
|
||||
npm run style
|
||||
```
|
||||
|
||||
In order to apply the coding style (where it can be done automatically). If an error is shown, please figure out what's
|
||||
wrong, fix it and run standard again.
|
||||
|
||||
A few (but not all) of the things to keep in mind:
|
||||
|
||||
- Use camelCase with the leading character as lowercase for identifier names (variables and functions).
|
||||
|
@ -1,5 +1,5 @@
|
||||
class CacheNode {
|
||||
constructor (key, value, frequency) {
|
||||
constructor(key, value, frequency) {
|
||||
this.key = key
|
||||
this.value = value
|
||||
this.frequency = frequency
|
||||
@ -10,15 +10,19 @@ class CacheNode {
|
||||
|
||||
// This frequency map class will act like javascript Map DS with more two custom method refresh & insert
|
||||
class FrequencyMap extends Map {
|
||||
static get [Symbol.species] () { return Map } // for using Symbol.species we can access Map constructor @see -> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/@@species
|
||||
get [Symbol.toStringTag] () { return '' }
|
||||
static get [Symbol.species]() {
|
||||
return Map
|
||||
} // for using Symbol.species we can access Map constructor @see -> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/@@species
|
||||
get [Symbol.toStringTag]() {
|
||||
return ''
|
||||
}
|
||||
|
||||
/**
|
||||
* @method refresh
|
||||
* @description - It's revive a CacheNode, increment of this nodes frequency and refresh the frequencyMap via new incremented nodes frequency
|
||||
* @param {CacheNode} node
|
||||
*/
|
||||
refresh (node) {
|
||||
* @method refresh
|
||||
* @description - It's revive a CacheNode, increment of this nodes frequency and refresh the frequencyMap via new incremented nodes frequency
|
||||
* @param {CacheNode} node
|
||||
*/
|
||||
refresh(node) {
|
||||
const { frequency } = node
|
||||
const freqSet = this.get(frequency)
|
||||
freqSet.delete(node)
|
||||
@ -33,7 +37,7 @@ class FrequencyMap extends Map {
|
||||
* @description - Add new CacheNode into HashSet by the frequency
|
||||
* @param {CacheNode} node
|
||||
*/
|
||||
insert (node) {
|
||||
insert(node) {
|
||||
const { frequency } = node
|
||||
|
||||
if (!this.has(frequency)) {
|
||||
@ -49,10 +53,10 @@ class LFUCache {
|
||||
#frequencyMap
|
||||
|
||||
/**
|
||||
* @param {number} capacity - The range of LFUCache
|
||||
* @returns {LFUCache} - sealed
|
||||
*/
|
||||
constructor (capacity) {
|
||||
* @param {number} capacity - The range of LFUCache
|
||||
* @returns {LFUCache} - sealed
|
||||
*/
|
||||
constructor(capacity) {
|
||||
this.#capacity = capacity
|
||||
this.#frequencyMap = new FrequencyMap()
|
||||
this.misses = 0
|
||||
@ -66,7 +70,7 @@ class LFUCache {
|
||||
* Get the capacity of the LFUCache
|
||||
* @returns {number}
|
||||
*/
|
||||
get capacity () {
|
||||
get capacity() {
|
||||
return this.#capacity
|
||||
}
|
||||
|
||||
@ -74,14 +78,14 @@ class LFUCache {
|
||||
* Get the current size of LFUCache
|
||||
* @returns {number}
|
||||
*/
|
||||
get size () {
|
||||
get size() {
|
||||
return this.cache.size
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the capacity of the LFUCache if you decrease the capacity its removed CacheNodes following the LFU - least frequency used
|
||||
*/
|
||||
set capacity (newCapacity) {
|
||||
* Set the capacity of the LFUCache if you decrease the capacity its removed CacheNodes following the LFU - least frequency used
|
||||
*/
|
||||
set capacity(newCapacity) {
|
||||
if (this.#capacity > newCapacity) {
|
||||
let diff = this.#capacity - newCapacity // get the decrement number of capacity
|
||||
|
||||
@ -95,7 +99,7 @@ class LFUCache {
|
||||
this.#capacity = newCapacity
|
||||
}
|
||||
|
||||
get info () {
|
||||
get info() {
|
||||
return Object.freeze({
|
||||
misses: this.misses,
|
||||
hits: this.hits,
|
||||
@ -105,7 +109,7 @@ class LFUCache {
|
||||
})
|
||||
}
|
||||
|
||||
get leastFrequency () {
|
||||
get leastFrequency() {
|
||||
const freqCacheIterator = this.#frequencyMap.keys()
|
||||
let leastFrequency = freqCacheIterator.next().value || null
|
||||
|
||||
@ -117,7 +121,7 @@ class LFUCache {
|
||||
return leastFrequency
|
||||
}
|
||||
|
||||
#removeCacheNode () {
|
||||
#removeCacheNode() {
|
||||
const leastFreqSet = this.#frequencyMap.get(this.leastFrequency)
|
||||
// Select the least recently used node from the least Frequency set
|
||||
const LFUNode = leastFreqSet.values().next().value
|
||||
@ -131,19 +135,19 @@ class LFUCache {
|
||||
* @param {any} key
|
||||
* @returns {boolean}
|
||||
*/
|
||||
has (key) {
|
||||
has(key) {
|
||||
key = String(key) // converted to string
|
||||
|
||||
return this.cache.has(key)
|
||||
}
|
||||
|
||||
/**
|
||||
* @method get
|
||||
* @description - This method return the value of key & refresh the frequencyMap by the oldNode
|
||||
* @param {string} key
|
||||
* @returns {any}
|
||||
*/
|
||||
get (key) {
|
||||
* @method get
|
||||
* @description - This method return the value of key & refresh the frequencyMap by the oldNode
|
||||
* @param {string} key
|
||||
* @returns {any}
|
||||
*/
|
||||
get(key) {
|
||||
key = String(key) // converted to string
|
||||
|
||||
if (this.cache.has(key)) {
|
||||
@ -160,14 +164,14 @@ class LFUCache {
|
||||
}
|
||||
|
||||
/**
|
||||
* @method set
|
||||
* @description - This method stored the value by key & add frequency if it doesn't exist
|
||||
* @param {string} key
|
||||
* @param {any} value
|
||||
* @param {number} frequency
|
||||
* @returns {LFUCache}
|
||||
*/
|
||||
set (key, value, frequency = 1) {
|
||||
* @method set
|
||||
* @description - This method stored the value by key & add frequency if it doesn't exist
|
||||
* @param {string} key
|
||||
* @param {any} value
|
||||
* @param {number} frequency
|
||||
* @returns {LFUCache}
|
||||
*/
|
||||
set(key, value, frequency = 1) {
|
||||
key = String(key) // converted to string
|
||||
|
||||
if (this.#capacity === 0) {
|
||||
@ -197,12 +201,12 @@ class LFUCache {
|
||||
}
|
||||
|
||||
/**
|
||||
* @method parse
|
||||
* @description - This method receive a valid LFUCache JSON & run JSON.prase() method and merge with existing LFUCache
|
||||
* @param {JSON} json
|
||||
* @returns {LFUCache} - merged
|
||||
*/
|
||||
parse (json) {
|
||||
* @method parse
|
||||
* @description - This method receive a valid LFUCache JSON & run JSON.prase() method and merge with existing LFUCache
|
||||
* @param {JSON} json
|
||||
* @returns {LFUCache} - merged
|
||||
*/
|
||||
parse(json) {
|
||||
const { misses, hits, cache } = JSON.parse(json)
|
||||
|
||||
this.misses += misses ?? 0
|
||||
@ -217,11 +221,11 @@ class LFUCache {
|
||||
}
|
||||
|
||||
/**
|
||||
* @method clear
|
||||
* @description - This method cleared the whole LFUCache
|
||||
* @returns {LFUCache}
|
||||
*/
|
||||
clear () {
|
||||
* @method clear
|
||||
* @description - This method cleared the whole LFUCache
|
||||
* @returns {LFUCache}
|
||||
*/
|
||||
clear() {
|
||||
this.cache.clear()
|
||||
this.#frequencyMap.clear()
|
||||
|
||||
@ -229,12 +233,12 @@ class LFUCache {
|
||||
}
|
||||
|
||||
/**
|
||||
* @method toString
|
||||
* @description - This method generate a JSON format of LFUCache & return it.
|
||||
* @param {number} indent
|
||||
* @returns {string} - JSON
|
||||
*/
|
||||
toString (indent) {
|
||||
* @method toString
|
||||
* @description - This method generate a JSON format of LFUCache & return it.
|
||||
* @param {number} indent
|
||||
* @returns {string} - JSON
|
||||
*/
|
||||
toString(indent) {
|
||||
const replacer = (_, value) => {
|
||||
if (value instanceof Set) {
|
||||
return [...value]
|
||||
|
@ -6,7 +6,7 @@ class LRUCache {
|
||||
* @param {number} capacity - the capacity of LRUCache
|
||||
* @returns {LRUCache} - sealed
|
||||
*/
|
||||
constructor (capacity) {
|
||||
constructor(capacity) {
|
||||
if (!Number.isInteger(capacity) || capacity < 0) {
|
||||
throw new TypeError('Invalid capacity')
|
||||
}
|
||||
@ -19,7 +19,7 @@ class LRUCache {
|
||||
return Object.seal(this)
|
||||
}
|
||||
|
||||
get info () {
|
||||
get info() {
|
||||
return Object.freeze({
|
||||
misses: this.misses,
|
||||
hits: this.hits,
|
||||
@ -28,15 +28,15 @@ class LRUCache {
|
||||
})
|
||||
}
|
||||
|
||||
get size () {
|
||||
get size() {
|
||||
return this.cache.size
|
||||
}
|
||||
|
||||
get capacity () {
|
||||
get capacity() {
|
||||
return this.#capacity
|
||||
}
|
||||
|
||||
set capacity (newCapacity) {
|
||||
set capacity(newCapacity) {
|
||||
if (newCapacity < 0) {
|
||||
throw new RangeError('Capacity should be greater than 0')
|
||||
}
|
||||
@ -53,9 +53,9 @@ class LRUCache {
|
||||
}
|
||||
|
||||
/**
|
||||
* delete oldest key existing in map by the help of iterator
|
||||
*/
|
||||
#removeLeastRecentlyUsed () {
|
||||
* delete oldest key existing in map by the help of iterator
|
||||
*/
|
||||
#removeLeastRecentlyUsed() {
|
||||
this.cache.delete(this.cache.keys().next().value)
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ class LRUCache {
|
||||
* @param {string} key
|
||||
* @returns {*}
|
||||
*/
|
||||
has (key) {
|
||||
has(key) {
|
||||
key = String(key)
|
||||
|
||||
return this.cache.has(key)
|
||||
@ -73,7 +73,7 @@ class LRUCache {
|
||||
* @param {string} key
|
||||
* @param {*} value
|
||||
*/
|
||||
set (key, value) {
|
||||
set(key, value) {
|
||||
key = String(key)
|
||||
// Sets the value for the input key and if the key exists it updates the existing key
|
||||
if (this.size === this.capacity) {
|
||||
@ -87,7 +87,7 @@ class LRUCache {
|
||||
* @param {string} key
|
||||
* @returns {*}
|
||||
*/
|
||||
get (key) {
|
||||
get(key) {
|
||||
key = String(key)
|
||||
// Returns the value for the input key. Returns null if key is not present in cache
|
||||
if (this.cache.has(key)) {
|
||||
@ -109,7 +109,7 @@ class LRUCache {
|
||||
* @param {JSON} json
|
||||
* @returns {LRUCache}
|
||||
*/
|
||||
parse (json) {
|
||||
parse(json) {
|
||||
const { misses, hits, cache } = JSON.parse(json)
|
||||
|
||||
this.misses += misses ?? 0
|
||||
@ -126,7 +126,7 @@ class LRUCache {
|
||||
* @param {number} indent
|
||||
* @returns {JSON} - string
|
||||
*/
|
||||
toString (indent) {
|
||||
toString(indent) {
|
||||
const replacer = (_, value) => {
|
||||
if (value instanceof Set) {
|
||||
return [...value]
|
||||
|
@ -15,11 +15,13 @@
|
||||
*/
|
||||
const memoize = (func, cache = new Map()) => {
|
||||
const jsonReplacer = (_, value) => {
|
||||
if (value instanceof Set) { // if the value is Set it's converted to Array cause JSON.stringify can't convert Set
|
||||
if (value instanceof Set) {
|
||||
// if the value is Set it's converted to Array cause JSON.stringify can't convert Set
|
||||
return [...value]
|
||||
}
|
||||
|
||||
if (value instanceof Map) { // if the value is Map it's converted to Object cause JSON.stringify can't convert Map
|
||||
if (value instanceof Map) {
|
||||
// if the value is Map it's converted to Object cause JSON.stringify can't convert Map
|
||||
return Object.fromEntries(value)
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,8 @@ describe('Testing LFUCache class', () => {
|
||||
leastFrequency: 2
|
||||
})
|
||||
|
||||
const json = '{"misses":3,"hits":6,"cache":{"2":{"key":"2","value":2,"frequency":4},"4":{"key":"4","value":4,"frequency":2}}}'
|
||||
const json =
|
||||
'{"misses":3,"hits":6,"cache":{"2":{"key":"2","value":2,"frequency":4},"4":{"key":"4","value":4,"frequency":2}}}'
|
||||
expect(cache.toString()).toBe(json)
|
||||
|
||||
const cacheInstance = cache.parse(json) // again merge the json
|
||||
@ -45,7 +46,8 @@ describe('Testing LFUCache class', () => {
|
||||
|
||||
cache.capacity = 1 // decrease the capacity
|
||||
|
||||
expect(cache.info).toEqual({ // after merging the info
|
||||
expect(cache.info).toEqual({
|
||||
// after merging the info
|
||||
misses: 6,
|
||||
hits: 12,
|
||||
capacity: 1,
|
||||
|
@ -43,11 +43,7 @@ describe('Testing Memoize', () => {
|
||||
|
||||
it('expects the union function to use the cache on the second call', () => {
|
||||
const memoUnion = memoize(union)
|
||||
const inputs = [
|
||||
new Set([1, 2, 3]),
|
||||
new Set([4, 3, 2]),
|
||||
new Set([5, 3, 6])
|
||||
]
|
||||
const inputs = [new Set([1, 2, 3]), new Set([4, 3, 2]), new Set([5, 3, 6])]
|
||||
|
||||
expect(memoUnion(...inputs)).toEqual(new Set([1, 2, 3, 4, 5, 6]))
|
||||
expect(memoUnion(...inputs)).toEqual(union(...inputs))
|
||||
|
@ -31,7 +31,5 @@ export const fibonacciCache = (n, cache = null) => {
|
||||
* @return {new Set}
|
||||
*/
|
||||
export const union = (...sets) => {
|
||||
return new Set(
|
||||
sets.reduce((flatArray, set) => [...flatArray, ...set], [])
|
||||
)
|
||||
return new Set(sets.reduce((flatArray, set) => [...flatArray, ...set], []))
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ The Game of Life is a cellular automaton devised by the British mathematician Jo
|
||||
/**
|
||||
* Generates the next generation for a given state of Conway's Game of Life.
|
||||
*/
|
||||
export function newGeneration (cells) {
|
||||
export function newGeneration(cells) {
|
||||
const nextGeneration = []
|
||||
for (let i = 0; i < cells.length; i++) {
|
||||
const nextGenerationRow = []
|
||||
@ -20,12 +20,14 @@ export function newGeneration (cells) {
|
||||
let neighbourCount = 0
|
||||
if (i > 0 && j > 0) neighbourCount += cells[i - 1][j - 1]
|
||||
if (i > 0) neighbourCount += cells[i - 1][j]
|
||||
if (i > 0 && j < cells[i].length - 1) neighbourCount += cells[i - 1][j + 1]
|
||||
if (i > 0 && j < cells[i].length - 1)
|
||||
neighbourCount += cells[i - 1][j + 1]
|
||||
if (j > 0) neighbourCount += cells[i][j - 1]
|
||||
if (j < cells[i].length - 1) neighbourCount += cells[i][j + 1]
|
||||
if (i < cells.length - 1 && j > 0) neighbourCount += cells[i + 1][j - 1]
|
||||
if (i < cells.length - 1) neighbourCount += cells[i + 1][j]
|
||||
if (i < cells.length - 1 && j < cells[i].length - 1) neighbourCount += cells[i + 1][j + 1]
|
||||
if (i < cells.length - 1 && j < cells[i].length - 1)
|
||||
neighbourCount += cells[i + 1][j + 1]
|
||||
|
||||
// Decide whether the cell is alive or dead
|
||||
const alive = cells[i][j] === 1
|
||||
|
@ -64,20 +64,26 @@
|
||||
* @param {number} rule The current rule of the Elementary Cellular Automata simulation. Must be an integer between 0 and 255 inclusive
|
||||
* @returns {(0 | 1)[]} The next generation according to the inputted rule
|
||||
*/
|
||||
export function getNextElementaryGeneration (generation, rule) {
|
||||
export function getNextElementaryGeneration(generation, rule) {
|
||||
const NUM_ELEMENTARY_NEIGHBORHOOD_STATES = 8
|
||||
const MIN_RULE = 0
|
||||
const MAX_RULE = 255
|
||||
|
||||
if (!Number.isInteger(rule)) {
|
||||
throw new Error(`Rule must be an integer between the values 0 and 255 (got ${rule})`)
|
||||
throw new Error(
|
||||
`Rule must be an integer between the values 0 and 255 (got ${rule})`
|
||||
)
|
||||
}
|
||||
if (rule < MIN_RULE || rule > MAX_RULE) {
|
||||
throw new RangeError(`Rule must be an integer between the values 0 and 255 (got ${rule})`)
|
||||
throw new RangeError(
|
||||
`Rule must be an integer between the values 0 and 255 (got ${rule})`
|
||||
)
|
||||
}
|
||||
|
||||
const binaryRule = rule.toString(2).padStart(NUM_ELEMENTARY_NEIGHBORHOOD_STATES, '0')
|
||||
const ruleData = binaryRule.split('').map(bit => Number.parseInt(bit)) // note that ruleData[0] represents "all alive" while ruleData[7] represents "all dead"
|
||||
const binaryRule = rule
|
||||
.toString(2)
|
||||
.padStart(NUM_ELEMENTARY_NEIGHBORHOOD_STATES, '0')
|
||||
const ruleData = binaryRule.split('').map((bit) => Number.parseInt(bit)) // note that ruleData[0] represents "all alive" while ruleData[7] represents "all dead"
|
||||
const output = new Array(generation.length)
|
||||
const LEFT_DEAD = 4 // 100 in binary
|
||||
const MIDDLE_DEAD = 2 // 010 in binary
|
||||
|
@ -2,7 +2,16 @@ import { newGeneration } from '../ConwaysGameOfLife'
|
||||
|
||||
describe('newGeneration', () => {
|
||||
it('should produce the next generation according to the rules', () => {
|
||||
expect(newGeneration([[0, 1, 0], [0, 1, 0], [0, 1, 0]]))
|
||||
.toEqual([[0, 0, 0], [1, 1, 1], [0, 0, 0]])
|
||||
expect(
|
||||
newGeneration([
|
||||
[0, 1, 0],
|
||||
[0, 1, 0],
|
||||
[0, 1, 0]
|
||||
])
|
||||
).toEqual([
|
||||
[0, 0, 0],
|
||||
[1, 1, 1],
|
||||
[0, 0, 0]
|
||||
])
|
||||
})
|
||||
})
|
||||
|
@ -3,91 +3,137 @@ import { getNextElementaryGeneration } from '../Elementary'
|
||||
describe('Elementary Cellular Automata', () => {
|
||||
describe('Rule Errors', () => {
|
||||
it('Correct', () => {
|
||||
expect(() => getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 128)).not.toThrow()
|
||||
expect(() =>
|
||||
getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 128)
|
||||
).not.toThrow()
|
||||
})
|
||||
|
||||
it('Less than 0', () => {
|
||||
expect(() => getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], -1)).toThrow()
|
||||
expect(() =>
|
||||
getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], -1)
|
||||
).toThrow()
|
||||
})
|
||||
|
||||
it('Greater than 255', () => {
|
||||
expect(() => getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 256)).toThrow()
|
||||
expect(() =>
|
||||
getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 256)
|
||||
).toThrow()
|
||||
})
|
||||
|
||||
it('Decimal', () => {
|
||||
expect(() => getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 100.4)).toThrow()
|
||||
expect(() =>
|
||||
getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 100.4)
|
||||
).toThrow()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Rule 54 Iterations', () => {
|
||||
it('Generation 1', () => {
|
||||
expect(getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 54)).toEqual([0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0])
|
||||
expect(
|
||||
getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 54)
|
||||
).toEqual([0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0])
|
||||
})
|
||||
it('Generation 2', () => {
|
||||
expect(getNextElementaryGeneration([0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], 54)).toEqual([0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0])
|
||||
expect(
|
||||
getNextElementaryGeneration([0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], 54)
|
||||
).toEqual([0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0])
|
||||
})
|
||||
it('Generation 3', () => {
|
||||
expect(getNextElementaryGeneration([0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0], 54)).toEqual([0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0])
|
||||
expect(
|
||||
getNextElementaryGeneration([0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0], 54)
|
||||
).toEqual([0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0])
|
||||
})
|
||||
it('Generation 4', () => {
|
||||
expect(getNextElementaryGeneration([0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0], 54)).toEqual([0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0])
|
||||
expect(
|
||||
getNextElementaryGeneration([0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0], 54)
|
||||
).toEqual([0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0])
|
||||
})
|
||||
})
|
||||
|
||||
describe('Rule 222 Iterations', () => {
|
||||
it('Generation 1', () => {
|
||||
expect(getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 222)).toEqual([0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0])
|
||||
expect(
|
||||
getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 222)
|
||||
).toEqual([0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0])
|
||||
})
|
||||
it('Generation 2', () => {
|
||||
expect(getNextElementaryGeneration([0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], 222)).toEqual([0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0])
|
||||
expect(
|
||||
getNextElementaryGeneration([0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], 222)
|
||||
).toEqual([0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0])
|
||||
})
|
||||
it('Generation 3', () => {
|
||||
expect(getNextElementaryGeneration([0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0], 222)).toEqual([0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0])
|
||||
expect(
|
||||
getNextElementaryGeneration([0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0], 222)
|
||||
).toEqual([0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0])
|
||||
})
|
||||
it('Generation 4', () => {
|
||||
expect(getNextElementaryGeneration([0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0], 222)).toEqual([0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0])
|
||||
expect(
|
||||
getNextElementaryGeneration([0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0], 222)
|
||||
).toEqual([0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0])
|
||||
})
|
||||
})
|
||||
|
||||
describe('Rule 60 Iterations', () => {
|
||||
it('Generation 1', () => {
|
||||
expect(getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 60)).toEqual([0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0])
|
||||
expect(
|
||||
getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 60)
|
||||
).toEqual([0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0])
|
||||
})
|
||||
it('Generation 2', () => {
|
||||
expect(getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0], 60)).toEqual([0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0])
|
||||
expect(
|
||||
getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0], 60)
|
||||
).toEqual([0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0])
|
||||
})
|
||||
it('Generation 3', () => {
|
||||
expect(getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], 60)).toEqual([0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0])
|
||||
expect(
|
||||
getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], 60)
|
||||
).toEqual([0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0])
|
||||
})
|
||||
it('Generation 4', () => {
|
||||
expect(getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0], 60)).toEqual([0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0])
|
||||
expect(
|
||||
getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0], 60)
|
||||
).toEqual([0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0])
|
||||
})
|
||||
})
|
||||
|
||||
describe('Rule 90 Iterations', () => {
|
||||
it('Generation 1', () => {
|
||||
expect(getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 90)).toEqual([0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0])
|
||||
expect(
|
||||
getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 90)
|
||||
).toEqual([0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0])
|
||||
})
|
||||
it('Generation 2', () => {
|
||||
expect(getNextElementaryGeneration([0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0], 90)).toEqual([0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0])
|
||||
expect(
|
||||
getNextElementaryGeneration([0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0], 90)
|
||||
).toEqual([0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0])
|
||||
})
|
||||
it('Generation 3', () => {
|
||||
expect(getNextElementaryGeneration([0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0], 90)).toEqual([0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0])
|
||||
expect(
|
||||
getNextElementaryGeneration([0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0], 90)
|
||||
).toEqual([0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0])
|
||||
})
|
||||
it('Generation 4', () => {
|
||||
expect(getNextElementaryGeneration([0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0], 90)).toEqual([0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0])
|
||||
expect(
|
||||
getNextElementaryGeneration([0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0], 90)
|
||||
).toEqual([0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0])
|
||||
})
|
||||
})
|
||||
|
||||
describe('Rule 30 Iterations', () => {
|
||||
it('Generation 1', () => {
|
||||
expect(getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 30)).toEqual([0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0])
|
||||
expect(
|
||||
getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 30)
|
||||
).toEqual([0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0])
|
||||
})
|
||||
it('Generation 2', () => {
|
||||
expect(getNextElementaryGeneration([0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], 30)).toEqual([0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0])
|
||||
expect(
|
||||
getNextElementaryGeneration([0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], 30)
|
||||
).toEqual([0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0])
|
||||
})
|
||||
it('Generation 3', () => {
|
||||
expect(getNextElementaryGeneration([0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0], 30)).toEqual([0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0])
|
||||
expect(
|
||||
getNextElementaryGeneration([0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0], 30)
|
||||
).toEqual([0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -13,7 +13,7 @@ const key = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
* @param {Number} m - Modulos value
|
||||
* @return {Number} Return n mod m
|
||||
*/
|
||||
function mod (n, m) {
|
||||
function mod(n, m) {
|
||||
return ((n % m) + m) % m
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ function mod (n, m) {
|
||||
* @param {Number} m - Modulos value
|
||||
* @return {Number} Return modular multiplicative inverse of coefficient a and modulos m
|
||||
*/
|
||||
function inverseMod (a, m) {
|
||||
function inverseMod(a, m) {
|
||||
for (let x = 1; x < m; x++) {
|
||||
if (mod(a * x, m) === 1) return x
|
||||
}
|
||||
@ -36,7 +36,7 @@ function inverseMod (a, m) {
|
||||
* @param {Number} b - B coefficient to be checked
|
||||
* @return {Boolean} Result of the checking
|
||||
*/
|
||||
function isCorrectFormat (str, a, b) {
|
||||
function isCorrectFormat(str, a, b) {
|
||||
if (typeof a !== 'number' || typeof b !== 'number') {
|
||||
throw new TypeError('Coefficient a, b should be number')
|
||||
}
|
||||
@ -57,8 +57,8 @@ function isCorrectFormat (str, a, b) {
|
||||
* @param {String} char - Character index to be found
|
||||
* @return {Boolean} Character index
|
||||
*/
|
||||
function findCharIndex (char) {
|
||||
return char.toUpperCase().charCodeAt(0) - ('A').charCodeAt(0)
|
||||
function findCharIndex(char) {
|
||||
return char.toUpperCase().charCodeAt(0) - 'A'.charCodeAt(0)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -69,7 +69,7 @@ function findCharIndex (char) {
|
||||
* @return {String} result - Encrypted string
|
||||
*/
|
||||
|
||||
function encrypt (str, a, b) {
|
||||
function encrypt(str, a, b) {
|
||||
let result = ''
|
||||
if (isCorrectFormat(str, a, b)) {
|
||||
for (let x = 0; x < str.length; x++) {
|
||||
@ -88,7 +88,7 @@ function encrypt (str, a, b) {
|
||||
* @param {Number} b - B coefficient
|
||||
* @return {String} result - Decrypted string
|
||||
*/
|
||||
function decrypt (str, a, b) {
|
||||
function decrypt(str, a, b) {
|
||||
let result = ''
|
||||
if (isCorrectFormat(str, a, b)) {
|
||||
str = str.split(' ')
|
||||
|
@ -2,7 +2,8 @@
|
||||
Find and retrieve the encryption key automatically
|
||||
Note: This is a draft version, please help to modify, Thanks!
|
||||
******************************************************/
|
||||
function keyFinder (str) { // str is used to get the input of encrypted string
|
||||
function keyFinder(str) {
|
||||
// str is used to get the input of encrypted string
|
||||
const wordBank = [
|
||||
'I ',
|
||||
'You ',
|
||||
@ -27,13 +28,15 @@ function keyFinder (str) { // str is used to get the input of encrypted string
|
||||
' may ',
|
||||
'May ',
|
||||
' be ',
|
||||
'Be ']
|
||||
'Be '
|
||||
]
|
||||
// let wordbankelementCounter = 0;
|
||||
// let key = 0; // return zero means the key can not be found
|
||||
const inStr = str.toString() // convert the input to String
|
||||
let outStr = '' // store the output value
|
||||
let outStrElement = '' // temporary store the word inside the outStr, it is used for comparison
|
||||
for (let k = 0; k < 26; k++) { // try the number of key shifted, the sum of character from a-z or A-Z is 26
|
||||
for (let k = 0; k < 26; k++) {
|
||||
// try the number of key shifted, the sum of character from a-z or A-Z is 26
|
||||
outStr = caesarCipherEncodeAndDecodeEngine(inStr, k) // use the encryption engine to decrypt the input string
|
||||
|
||||
// loop through the whole input string
|
||||
@ -57,7 +60,7 @@ function keyFinder (str) { // str is used to get the input of encrypted string
|
||||
}
|
||||
|
||||
/* this sub-function is used to assist the keyFinder to find the key */
|
||||
function caesarCipherEncodeAndDecodeEngine (inStr, numShifted) {
|
||||
function caesarCipherEncodeAndDecodeEngine(inStr, numShifted) {
|
||||
const shiftNum = numShifted
|
||||
let charCode = 0
|
||||
let outStr = ''
|
||||
@ -69,7 +72,7 @@ function caesarCipherEncodeAndDecodeEngine (inStr, numShifted) {
|
||||
shiftedCharCode = charCode + shiftNum
|
||||
result = charCode
|
||||
|
||||
if ((charCode >= 48 && charCode <= 57)) {
|
||||
if (charCode >= 48 && charCode <= 57) {
|
||||
if (shiftedCharCode < 48) {
|
||||
let diff = Math.abs(48 - 1 - shiftedCharCode) % 10
|
||||
|
||||
@ -95,11 +98,11 @@ function caesarCipherEncodeAndDecodeEngine (inStr, numShifted) {
|
||||
|
||||
result = shiftedCharCode
|
||||
}
|
||||
} else if ((charCode >= 65 && charCode <= 90)) {
|
||||
} else if (charCode >= 65 && charCode <= 90) {
|
||||
if (shiftedCharCode <= 64) {
|
||||
let diff = Math.abs(65 - 1 - shiftedCharCode) % 26
|
||||
|
||||
while ((diff % 26) >= 26) {
|
||||
while (diff % 26 >= 26) {
|
||||
diff = diff % 26
|
||||
}
|
||||
shiftedCharCode = 90 - diff
|
||||
@ -109,17 +112,17 @@ function caesarCipherEncodeAndDecodeEngine (inStr, numShifted) {
|
||||
} else if (shiftedCharCode > 90) {
|
||||
let diff = Math.abs(shiftedCharCode - 1 - 90) % 26
|
||||
|
||||
while ((diff % 26) >= 26) {
|
||||
while (diff % 26 >= 26) {
|
||||
diff = diff % 26
|
||||
}
|
||||
shiftedCharCode = 65 + diff
|
||||
result = shiftedCharCode
|
||||
}
|
||||
} else if ((charCode >= 97 && charCode <= 122)) {
|
||||
} else if (charCode >= 97 && charCode <= 122) {
|
||||
if (shiftedCharCode <= 96) {
|
||||
let diff = Math.abs(97 - 1 - shiftedCharCode) % 26
|
||||
|
||||
while ((diff % 26) >= 26) {
|
||||
while (diff % 26 >= 26) {
|
||||
diff = diff % 26
|
||||
}
|
||||
shiftedCharCode = 122 - diff
|
||||
@ -129,7 +132,7 @@ function caesarCipherEncodeAndDecodeEngine (inStr, numShifted) {
|
||||
} else if (shiftedCharCode > 122) {
|
||||
let diff = Math.abs(shiftedCharCode - 1 - 122) % 26
|
||||
|
||||
while ((diff % 26) >= 26) {
|
||||
while (diff % 26 >= 26) {
|
||||
diff = diff % 26
|
||||
}
|
||||
shiftedCharCode = 97 + diff
|
||||
|
@ -16,9 +16,36 @@
|
||||
* Non alphabetical characters (space, exclamation mark, ...) are kept as they are
|
||||
*/
|
||||
|
||||
const alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
|
||||
const alphabet = [
|
||||
'a',
|
||||
'b',
|
||||
'c',
|
||||
'd',
|
||||
'e',
|
||||
'f',
|
||||
'g',
|
||||
'h',
|
||||
'i',
|
||||
'j',
|
||||
'k',
|
||||
'l',
|
||||
'm',
|
||||
'n',
|
||||
'o',
|
||||
'p',
|
||||
'q',
|
||||
'r',
|
||||
's',
|
||||
't',
|
||||
'u',
|
||||
'v',
|
||||
'w',
|
||||
'x',
|
||||
'y',
|
||||
'z'
|
||||
]
|
||||
|
||||
function checkKeywordValidity (keyword) {
|
||||
function checkKeywordValidity(keyword) {
|
||||
keyword.split('').forEach((char, index) => {
|
||||
const rest = keyword.slice(0, index) + keyword.slice(index + 1)
|
||||
if (rest.indexOf(char) !== -1) {
|
||||
@ -28,7 +55,7 @@ function checkKeywordValidity (keyword) {
|
||||
return true
|
||||
}
|
||||
|
||||
function getEncryptedAlphabet (keyword) {
|
||||
function getEncryptedAlphabet(keyword) {
|
||||
const encryptedAlphabet = keyword.split('')
|
||||
alphabet.forEach((char) => {
|
||||
if (encryptedAlphabet.indexOf(char) === -1) {
|
||||
@ -38,17 +65,20 @@ function getEncryptedAlphabet (keyword) {
|
||||
return encryptedAlphabet
|
||||
}
|
||||
|
||||
function translate (sourceAlphabet, targetAlphabet, message) {
|
||||
function translate(sourceAlphabet, targetAlphabet, message) {
|
||||
return message.split('').reduce((encryptedMessage, char) => {
|
||||
const isUpperCase = char === char.toUpperCase()
|
||||
const encryptedCharIndex = sourceAlphabet.indexOf(char.toLowerCase())
|
||||
const encryptedChar = encryptedCharIndex !== -1 ? targetAlphabet[encryptedCharIndex] : char
|
||||
encryptedMessage += isUpperCase ? encryptedChar.toUpperCase() : encryptedChar
|
||||
const encryptedChar =
|
||||
encryptedCharIndex !== -1 ? targetAlphabet[encryptedCharIndex] : char
|
||||
encryptedMessage += isUpperCase
|
||||
? encryptedChar.toUpperCase()
|
||||
: encryptedChar
|
||||
return encryptedMessage
|
||||
}, '')
|
||||
}
|
||||
|
||||
function checkInputs (keyword, message) {
|
||||
function checkInputs(keyword, message) {
|
||||
if (!keyword || !message) {
|
||||
throw new Error('Both keyword and message must be specified')
|
||||
}
|
||||
@ -58,14 +88,22 @@ function checkInputs (keyword, message) {
|
||||
}
|
||||
}
|
||||
|
||||
function encrypt (keyword, message) {
|
||||
function encrypt(keyword, message) {
|
||||
checkInputs(keyword, message)
|
||||
return translate(alphabet, getEncryptedAlphabet(keyword.toLowerCase()), message)
|
||||
return translate(
|
||||
alphabet,
|
||||
getEncryptedAlphabet(keyword.toLowerCase()),
|
||||
message
|
||||
)
|
||||
}
|
||||
|
||||
function decrypt (keyword, message) {
|
||||
function decrypt(keyword, message) {
|
||||
checkInputs(keyword, message)
|
||||
return translate(getEncryptedAlphabet(keyword.toLowerCase()), alphabet, message)
|
||||
return translate(
|
||||
getEncryptedAlphabet(keyword.toLowerCase()),
|
||||
alphabet,
|
||||
message
|
||||
)
|
||||
}
|
||||
|
||||
export { encrypt, decrypt }
|
||||
|
@ -50,7 +50,7 @@ const morse = (msg, dot = '*', dash = '-') => {
|
||||
',': '--**--',
|
||||
'?': '**--**',
|
||||
'!': '-*-*--',
|
||||
'\'': '*----*',
|
||||
"'": '*----*',
|
||||
'"': '*-**-*',
|
||||
'(': '-*--*',
|
||||
')': '-*--*-',
|
||||
@ -68,16 +68,21 @@ const morse = (msg, dot = '*', dash = '-') => {
|
||||
|
||||
let newMsg = ''
|
||||
|
||||
msg.toString().split('').forEach((e) => {
|
||||
if (/[a-zA-Z]/.test(e)) {
|
||||
newMsg += key[e.toUpperCase()].replaceAll('*', dot).replaceAll('-', dash)
|
||||
} else if (Object.keys(key).includes(e)) {
|
||||
newMsg += key[e].replaceAll('*', dot).replaceAll('-', dash)
|
||||
} else {
|
||||
newMsg += e
|
||||
}
|
||||
newMsg += ' '
|
||||
})
|
||||
msg
|
||||
.toString()
|
||||
.split('')
|
||||
.forEach((e) => {
|
||||
if (/[a-zA-Z]/.test(e)) {
|
||||
newMsg += key[e.toUpperCase()]
|
||||
.replaceAll('*', dot)
|
||||
.replaceAll('-', dash)
|
||||
} else if (Object.keys(key).includes(e)) {
|
||||
newMsg += key[e].replaceAll('*', dot).replaceAll('-', dash)
|
||||
} else {
|
||||
newMsg += e
|
||||
}
|
||||
newMsg += ' '
|
||||
})
|
||||
|
||||
return newMsg.trim()
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
* @param {String} str - string to be decrypted
|
||||
* @return {String} decrypted string
|
||||
*/
|
||||
function ROT13 (str) {
|
||||
function ROT13(str) {
|
||||
if (typeof str !== 'string') {
|
||||
throw new TypeError('Argument should be string')
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
* @param {String} str - character to check
|
||||
* @return {object} An array with the character or null if isn't a letter
|
||||
*/
|
||||
function isLetter (str) {
|
||||
function isLetter(str) {
|
||||
return str.length === 1 && str.match(/[a-zA-Z]/i)
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ function isLetter (str) {
|
||||
* @param {String} character - character to check
|
||||
* @return {Boolean} result of the checking
|
||||
*/
|
||||
function isUpperCase (character) {
|
||||
function isUpperCase(character) {
|
||||
if (character === character.toUpperCase()) {
|
||||
return true
|
||||
}
|
||||
@ -27,16 +27,22 @@ function isUpperCase (character) {
|
||||
* @param {String} key - key for encrypt
|
||||
* @return {String} result - encrypted string
|
||||
*/
|
||||
function encrypt (message, key) {
|
||||
function encrypt(message, key) {
|
||||
let result = ''
|
||||
|
||||
for (let i = 0, j = 0; i < message.length; i++) {
|
||||
const c = message.charAt(i)
|
||||
if (isLetter(c)) {
|
||||
if (isUpperCase(c)) {
|
||||
result += String.fromCharCode((c.charCodeAt(0) + key.toUpperCase().charCodeAt(j) - 2 * 65) % 26 + 65) // A: 65
|
||||
result += String.fromCharCode(
|
||||
((c.charCodeAt(0) + key.toUpperCase().charCodeAt(j) - 2 * 65) % 26) +
|
||||
65
|
||||
) // A: 65
|
||||
} else {
|
||||
result += String.fromCharCode((c.charCodeAt(0) + key.toLowerCase().charCodeAt(j) - 2 * 97) % 26 + 97) // a: 97
|
||||
result += String.fromCharCode(
|
||||
((c.charCodeAt(0) + key.toLowerCase().charCodeAt(j) - 2 * 97) % 26) +
|
||||
97
|
||||
) // a: 97
|
||||
}
|
||||
} else {
|
||||
result += c
|
||||
@ -52,16 +58,21 @@ function encrypt (message, key) {
|
||||
* @param {String} key - key for decrypt
|
||||
* @return {String} result - decrypted string
|
||||
*/
|
||||
function decrypt (message, key) {
|
||||
function decrypt(message, key) {
|
||||
let result = ''
|
||||
|
||||
for (let i = 0, j = 0; i < message.length; i++) {
|
||||
const c = message.charAt(i)
|
||||
if (isLetter(c)) {
|
||||
if (isUpperCase(c)) {
|
||||
result += String.fromCharCode(90 - (25 - (c.charCodeAt(0) - key.toUpperCase().charCodeAt(j))) % 26)
|
||||
result += String.fromCharCode(
|
||||
90 - ((25 - (c.charCodeAt(0) - key.toUpperCase().charCodeAt(j))) % 26)
|
||||
)
|
||||
} else {
|
||||
result += String.fromCharCode(122 - (25 - (c.charCodeAt(0) - key.toLowerCase().charCodeAt(j))) % 26)
|
||||
result += String.fromCharCode(
|
||||
122 -
|
||||
((25 - (c.charCodeAt(0) - key.toLowerCase().charCodeAt(j))) % 26)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
result += c
|
||||
|
@ -14,8 +14,8 @@ const XORCipher = (str, key) => {
|
||||
throw new TypeError('Arguments type are invalid')
|
||||
}
|
||||
|
||||
return str.replace(
|
||||
/./g, (char) => String.fromCharCode(char.charCodeAt() ^ key)
|
||||
return str.replace(/./g, (char) =>
|
||||
String.fromCharCode(char.charCodeAt() ^ key)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -9,8 +9,14 @@ describe('Testing the caesarsCipher function', () => {
|
||||
|
||||
it('Test - 2, Testing for valid string and rotation', () => {
|
||||
expect(caesarCipher('middle-Outz', 2)).toBe('okffng-Qwvb')
|
||||
expect(caesarCipher('abcdefghijklmnopqrstuvwxyz', 3)).toBe('defghijklmnopqrstuvwxyzabc')
|
||||
expect(caesarCipher('Always-Look-on-the-Bright-Side-of-Life', 5)).toBe('Fqbfdx-Qttp-ts-ymj-Gwnlmy-Xnij-tk-Qnkj')
|
||||
expect(caesarCipher('THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG', 23)).toBe('QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD')
|
||||
expect(caesarCipher('abcdefghijklmnopqrstuvwxyz', 3)).toBe(
|
||||
'defghijklmnopqrstuvwxyzabc'
|
||||
)
|
||||
expect(caesarCipher('Always-Look-on-the-Bright-Side-of-Life', 5)).toBe(
|
||||
'Fqbfdx-Qttp-ts-ymj-Gwnlmy-Xnij-tk-Qnkj'
|
||||
)
|
||||
expect(
|
||||
caesarCipher('THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG', 23)
|
||||
).toBe('QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD')
|
||||
})
|
||||
})
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { encrypt, decrypt } from '../KeywordShiftedAlphabet'
|
||||
|
||||
test('Hello world! === decrypt(encrypt(Hello world!))', () => {
|
||||
const word = 'Hello world!'
|
||||
const result = decrypt('keyword', encrypt('keyword', word))
|
||||
expect(result).toMatch(word)
|
||||
})
|
||||
|
||||
test('The Algorithms === decrypt(encrypt(The Algorithms))', () => {
|
||||
const word = 'The Algorithms'
|
||||
const result = decrypt('keyword', encrypt('keyword', word))
|
||||
expect(result).toMatch(word)
|
||||
})
|
||||
import { encrypt, decrypt } from '../KeywordShiftedAlphabet'
|
||||
|
||||
test('Hello world! === decrypt(encrypt(Hello world!))', () => {
|
||||
const word = 'Hello world!'
|
||||
const result = decrypt('keyword', encrypt('keyword', word))
|
||||
expect(result).toMatch(word)
|
||||
})
|
||||
|
||||
test('The Algorithms === decrypt(encrypt(The Algorithms))', () => {
|
||||
const word = 'The Algorithms'
|
||||
const result = decrypt('keyword', encrypt('keyword', word))
|
||||
expect(result).toMatch(word)
|
||||
})
|
||||
|
@ -2,12 +2,16 @@ import { morse } from '../MorseCode'
|
||||
|
||||
describe('Testing morse function', () => {
|
||||
it('should return an enciphered string with a given input string', () => {
|
||||
expect(morse('Hello World!')).toBe('**** * *-** *-** --- *-- --- *-* *-** -** -*-*--')
|
||||
expect(morse('Hello World!')).toBe(
|
||||
'**** * *-** *-** --- *-- --- *-* *-** -** -*-*--'
|
||||
)
|
||||
expect(morse('1+1=2')).toBe('*---- *-*-* *---- -***- **---')
|
||||
})
|
||||
|
||||
it('should leave symbols that does not have its corresponding morse representation', () => {
|
||||
expect(morse('© 2023 GitHub, Inc.')).toBe('© **--- ----- **--- ***-- --* ** - **** **- -*** --**-- ** -* -*-* *-*-*-')
|
||||
expect(morse('© 2023 GitHub, Inc.')).toBe(
|
||||
'© **--- ----- **--- ***-- --* ** - **** **- -*** --**-- ** -* -*-* *-*-*-'
|
||||
)
|
||||
})
|
||||
|
||||
it('should be able to accept custom morse code symbols', () => {
|
||||
|
@ -12,7 +12,11 @@ describe('Testing ROT13 function', () => {
|
||||
|
||||
it('Test - 2, passing a string as an argument', () => {
|
||||
expect(ROT13('Uryyb Jbeyq')).toBe('Hello World')
|
||||
expect(ROT13('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')).toBe('NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm')
|
||||
expect(ROT13('The quick brown fox jumps over the lazy dog')).toBe('Gur dhvpx oebja sbk whzcf bire gur ynml qbt')
|
||||
expect(ROT13('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')).toBe(
|
||||
'NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm'
|
||||
)
|
||||
expect(ROT13('The quick brown fox jumps over the lazy dog')).toBe(
|
||||
'Gur dhvpx oebja sbk whzcf bire gur ynml qbt'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { encrypt, decrypt } from '../VigenereCipher'
|
||||
|
||||
test('Hello world! === decrypt(encrypt(Hello world!))', () => {
|
||||
const word = 'Hello world!'
|
||||
const result = decrypt(encrypt(word, 'code'), 'code')
|
||||
expect(result).toMatch(word)
|
||||
})
|
||||
|
||||
test('The Algorithms === decrypt(encrypt(The Algorithms))', () => {
|
||||
const word = 'The Algorithms'
|
||||
const result = decrypt(encrypt(word, 'code'), 'code')
|
||||
expect(result).toMatch(word)
|
||||
})
|
||||
import { encrypt, decrypt } from '../VigenereCipher'
|
||||
|
||||
test('Hello world! === decrypt(encrypt(Hello world!))', () => {
|
||||
const word = 'Hello world!'
|
||||
const result = decrypt(encrypt(word, 'code'), 'code')
|
||||
expect(result).toMatch(word)
|
||||
})
|
||||
|
||||
test('The Algorithms === decrypt(encrypt(The Algorithms))', () => {
|
||||
const word = 'The Algorithms'
|
||||
const result = decrypt(encrypt(word, 'code'), 'code')
|
||||
expect(result).toMatch(word)
|
||||
})
|
||||
|
@ -1,9 +1,9 @@
|
||||
/**
|
||||
* Divide two numbers and get the result of floor division and remainder
|
||||
* @param {number} dividend
|
||||
* @param {number} divisor
|
||||
* @returns {[result: number, remainder: number]}
|
||||
*/
|
||||
* Divide two numbers and get the result of floor division and remainder
|
||||
* @param {number} dividend
|
||||
* @param {number} divisor
|
||||
* @returns {[result: number, remainder: number]}
|
||||
*/
|
||||
const floorDiv = (dividend, divisor) => {
|
||||
const remainder = dividend % divisor
|
||||
const result = Math.floor(dividend / divisor)
|
||||
@ -12,14 +12,22 @@ const floorDiv = (dividend, divisor) => {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string from one base to other. Loses accuracy above the value of `Number.MAX_SAFE_INTEGER`.
|
||||
* @param {string} stringInBaseOne String in input base
|
||||
* @param {string} baseOneCharacters Character set for the input base
|
||||
* @param {string} baseTwoCharacters Character set for the output base
|
||||
* @returns {string}
|
||||
*/
|
||||
const convertArbitraryBase = (stringInBaseOne, baseOneCharacterString, baseTwoCharacterString) => {
|
||||
if ([stringInBaseOne, baseOneCharacterString, baseTwoCharacterString].map(arg => typeof arg).some(type => type !== 'string')) {
|
||||
* Converts a string from one base to other. Loses accuracy above the value of `Number.MAX_SAFE_INTEGER`.
|
||||
* @param {string} stringInBaseOne String in input base
|
||||
* @param {string} baseOneCharacters Character set for the input base
|
||||
* @param {string} baseTwoCharacters Character set for the output base
|
||||
* @returns {string}
|
||||
*/
|
||||
const convertArbitraryBase = (
|
||||
stringInBaseOne,
|
||||
baseOneCharacterString,
|
||||
baseTwoCharacterString
|
||||
) => {
|
||||
if (
|
||||
[stringInBaseOne, baseOneCharacterString, baseTwoCharacterString]
|
||||
.map((arg) => typeof arg)
|
||||
.some((type) => type !== 'string')
|
||||
) {
|
||||
throw new TypeError('Only string arguments are allowed')
|
||||
}
|
||||
|
||||
@ -28,7 +36,9 @@ const convertArbitraryBase = (stringInBaseOne, baseOneCharacterString, baseTwoCh
|
||||
|
||||
for (const charactersInBase of [baseOneCharacters, baseTwoCharacters]) {
|
||||
if (charactersInBase.length !== new Set(charactersInBase).size) {
|
||||
throw new TypeError('Duplicate characters in character set are not allowed')
|
||||
throw new TypeError(
|
||||
'Duplicate characters in character set are not allowed'
|
||||
)
|
||||
}
|
||||
}
|
||||
const reversedStringOneChars = [...stringInBaseOne].reverse()
|
||||
@ -40,7 +50,7 @@ const convertArbitraryBase = (stringInBaseOne, baseOneCharacterString, baseTwoCh
|
||||
if (digitNumber === -1) {
|
||||
throw new TypeError(`Not a valid character: ${digit}`)
|
||||
}
|
||||
value += (digitNumber * placeValue)
|
||||
value += digitNumber * placeValue
|
||||
placeValue *= stringOneBase
|
||||
}
|
||||
const outputChars = []
|
||||
@ -54,14 +64,22 @@ const convertArbitraryBase = (stringInBaseOne, baseOneCharacterString, baseTwoCh
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a arbitrary-length string from one base to other. Doesn't lose accuracy.
|
||||
* @param {string} stringInBaseOne String in input base
|
||||
* @param {string} baseOneCharacters Character set for the input base
|
||||
* @param {string} baseTwoCharacters Character set for the output base
|
||||
* @returns {string}
|
||||
*/
|
||||
const convertArbitraryBaseBigIntVersion = (stringInBaseOne, baseOneCharacterString, baseTwoCharacterString) => {
|
||||
if ([stringInBaseOne, baseOneCharacterString, baseTwoCharacterString].map(arg => typeof arg).some(type => type !== 'string')) {
|
||||
* Converts a arbitrary-length string from one base to other. Doesn't lose accuracy.
|
||||
* @param {string} stringInBaseOne String in input base
|
||||
* @param {string} baseOneCharacters Character set for the input base
|
||||
* @param {string} baseTwoCharacters Character set for the output base
|
||||
* @returns {string}
|
||||
*/
|
||||
const convertArbitraryBaseBigIntVersion = (
|
||||
stringInBaseOne,
|
||||
baseOneCharacterString,
|
||||
baseTwoCharacterString
|
||||
) => {
|
||||
if (
|
||||
[stringInBaseOne, baseOneCharacterString, baseTwoCharacterString]
|
||||
.map((arg) => typeof arg)
|
||||
.some((type) => type !== 'string')
|
||||
) {
|
||||
throw new TypeError('Only string arguments are allowed')
|
||||
}
|
||||
|
||||
@ -70,7 +88,9 @@ const convertArbitraryBaseBigIntVersion = (stringInBaseOne, baseOneCharacterStri
|
||||
|
||||
for (const charactersInBase of [baseOneCharacters, baseTwoCharacters]) {
|
||||
if (charactersInBase.length !== new Set(charactersInBase).size) {
|
||||
throw new TypeError('Duplicate characters in character set are not allowed')
|
||||
throw new TypeError(
|
||||
'Duplicate characters in character set are not allowed'
|
||||
)
|
||||
}
|
||||
}
|
||||
const reversedStringOneChars = [...stringInBaseOne].reverse()
|
||||
@ -82,7 +102,7 @@ const convertArbitraryBaseBigIntVersion = (stringInBaseOne, baseOneCharacterStri
|
||||
if (digitNumber === -1n) {
|
||||
throw new TypeError(`Not a valid character: ${digit}`)
|
||||
}
|
||||
value += (digitNumber * placeValue)
|
||||
value += digitNumber * placeValue
|
||||
placeValue *= stringOneBase
|
||||
}
|
||||
const outputChars = []
|
||||
|
@ -5,9 +5,10 @@
|
||||
* @param {ArrayBuffer} binaryData An ArrayBuffer which represents an array of bytes
|
||||
* @returns {string} A string containing the base64 encoding of `binaryData`
|
||||
*/
|
||||
function bufferToBase64 (binaryData) {
|
||||
function bufferToBase64(binaryData) {
|
||||
// The base64 encoding uses the following set of characters to encode any binary data as text
|
||||
const base64Table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
||||
const base64Table =
|
||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
||||
// Every 3 bytes translates to 4 base64 characters, if we have less than 3 bytes we must append '=' chars as padding
|
||||
const padding = 3 - (binaryData.byteLength % 3)
|
||||
// Create an instance of Uint8Array, to read from the binaryData array buffer
|
||||
@ -23,15 +24,16 @@ function bufferToBase64 (binaryData) {
|
||||
const char4 = byteView[i + 2] & 63
|
||||
|
||||
result +=
|
||||
base64Table[char1] +
|
||||
base64Table[char2] +
|
||||
base64Table[char3] +
|
||||
base64Table[char4]
|
||||
base64Table[char1] +
|
||||
base64Table[char2] +
|
||||
base64Table[char3] +
|
||||
base64Table[char4]
|
||||
}
|
||||
|
||||
// Add padding '=' chars if needed
|
||||
if (padding !== 3) {
|
||||
const paddedResult = result.slice(0, result.length - padding) + '='.repeat(padding)
|
||||
const paddedResult =
|
||||
result.slice(0, result.length - padding) + '='.repeat(padding)
|
||||
return paddedResult
|
||||
}
|
||||
|
||||
|
@ -5,9 +5,10 @@
|
||||
* @param {string} b64 A base64 string
|
||||
* @returns {ArrayBuffer} An ArrayBuffer representing the bytes encoded by the base64 string
|
||||
*/
|
||||
function base64ToBuffer (b64) {
|
||||
function base64ToBuffer(b64) {
|
||||
// The base64 encoding uses the following set of characters to encode any binary data as text
|
||||
const base64Table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
||||
const base64Table =
|
||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
||||
// Find the index of char '=' first occurrence
|
||||
const paddingIdx = b64.indexOf('=')
|
||||
// Remove padding chars from base64 string, if there are any
|
||||
|
@ -1,8 +1,8 @@
|
||||
export default function binaryToDecimal (binaryString) {
|
||||
export default function binaryToDecimal(binaryString) {
|
||||
let decimalNumber = 0
|
||||
const binaryDigits = binaryString.split('').reverse() // Splits the binary number into reversed single digits
|
||||
binaryDigits.forEach((binaryDigit, index) => {
|
||||
decimalNumber += binaryDigit * (Math.pow(2, index)) // Summation of all the decimal converted digits
|
||||
decimalNumber += binaryDigit * Math.pow(2, index) // Summation of all the decimal converted digits
|
||||
})
|
||||
return decimalNumber
|
||||
}
|
||||
|
@ -9,22 +9,38 @@ const hexLookup = (bin) => {
|
||||
binary = pad(binary, 4)
|
||||
}
|
||||
switch (binary) {
|
||||
case '0000': return '0'
|
||||
case '0001': return '1'
|
||||
case '0010': return '2'
|
||||
case '0011': return '3'
|
||||
case '0100': return '4'
|
||||
case '0101': return '5'
|
||||
case '0110': return '6'
|
||||
case '0111': return '7'
|
||||
case '1000': return '8'
|
||||
case '1001': return '9'
|
||||
case '1010': return 'A'
|
||||
case '1011': return 'B'
|
||||
case '1100': return 'C'
|
||||
case '1101': return 'D'
|
||||
case '1110': return 'E'
|
||||
case '1111': return 'F'
|
||||
case '0000':
|
||||
return '0'
|
||||
case '0001':
|
||||
return '1'
|
||||
case '0010':
|
||||
return '2'
|
||||
case '0011':
|
||||
return '3'
|
||||
case '0100':
|
||||
return '4'
|
||||
case '0101':
|
||||
return '5'
|
||||
case '0110':
|
||||
return '6'
|
||||
case '0111':
|
||||
return '7'
|
||||
case '1000':
|
||||
return '8'
|
||||
case '1001':
|
||||
return '9'
|
||||
case '1010':
|
||||
return 'A'
|
||||
case '1011':
|
||||
return 'B'
|
||||
case '1100':
|
||||
return 'C'
|
||||
case '1101':
|
||||
return 'D'
|
||||
case '1110':
|
||||
return 'E'
|
||||
case '1111':
|
||||
return 'F'
|
||||
}
|
||||
}
|
||||
const binaryToHex = (binaryString) => {
|
||||
|
@ -14,7 +14,15 @@ const isLeap = (year) => {
|
||||
else return false
|
||||
}
|
||||
const DateToDay = (dd, mm, yyyy) => {
|
||||
return Math.floor((365 * (yyyy - 1)) + ((yyyy - 1) / 4) - ((yyyy - 1) / 100) + ((yyyy - 1) / 400) + dd + (((367 * mm) - 362) / 12) + (mm <= 2 ? 0 : isLeap(yyyy) ? -1 : -2))
|
||||
return Math.floor(
|
||||
365 * (yyyy - 1) +
|
||||
(yyyy - 1) / 4 -
|
||||
(yyyy - 1) / 100 +
|
||||
(yyyy - 1) / 400 +
|
||||
dd +
|
||||
(367 * mm - 362) / 12 +
|
||||
(mm <= 2 ? 0 : isLeap(yyyy) ? -1 : -2)
|
||||
)
|
||||
}
|
||||
|
||||
const DateDayDifference = (date1, date2) => {
|
||||
@ -23,17 +31,30 @@ const DateDayDifference = (date1, date2) => {
|
||||
return new TypeError('Argument is not a string.')
|
||||
}
|
||||
// extract the first date
|
||||
const [firstDateDay, firstDateMonth, firstDateYear] = date1.split('/').map((ele) => Number(ele))
|
||||
const [firstDateDay, firstDateMonth, firstDateYear] = date1
|
||||
.split('/')
|
||||
.map((ele) => Number(ele))
|
||||
// extract the second date
|
||||
const [secondDateDay, secondDateMonth, secondDateYear] = date2.split('/').map((ele) => Number(ele))
|
||||
const [secondDateDay, secondDateMonth, secondDateYear] = date2
|
||||
.split('/')
|
||||
.map((ele) => Number(ele))
|
||||
// check the both data are valid or not.
|
||||
if (firstDateDay < 0 || firstDateDay > 31 ||
|
||||
firstDateMonth > 12 || firstDateMonth < 0 ||
|
||||
secondDateDay < 0 || secondDateDay > 31 ||
|
||||
secondDateMonth > 12 || secondDateMonth < 0) {
|
||||
if (
|
||||
firstDateDay < 0 ||
|
||||
firstDateDay > 31 ||
|
||||
firstDateMonth > 12 ||
|
||||
firstDateMonth < 0 ||
|
||||
secondDateDay < 0 ||
|
||||
secondDateDay > 31 ||
|
||||
secondDateMonth > 12 ||
|
||||
secondDateMonth < 0
|
||||
) {
|
||||
return new TypeError('Date is not valid.')
|
||||
}
|
||||
return Math.abs(DateToDay(secondDateDay, secondDateMonth, secondDateYear) - DateToDay(firstDateDay, firstDateMonth, firstDateYear))
|
||||
return Math.abs(
|
||||
DateToDay(secondDateDay, secondDateMonth, secondDateYear) -
|
||||
DateToDay(firstDateDay, firstDateMonth, firstDateYear)
|
||||
)
|
||||
}
|
||||
|
||||
// Example : DateDayDifference('17/08/2002', '10/10/2020') => 6630
|
||||
|
@ -13,7 +13,15 @@
|
||||
*/
|
||||
|
||||
// Array holding name of the day: Saturday - Sunday - Friday => 0 - 1 - 6
|
||||
const daysNameArr = ['Saturday', 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
|
||||
const daysNameArr = [
|
||||
'Saturday',
|
||||
'Sunday',
|
||||
'Monday',
|
||||
'Tuesday',
|
||||
'Wednesday',
|
||||
'Thursday',
|
||||
'Friday'
|
||||
]
|
||||
|
||||
const DateToDay = (date) => {
|
||||
// firstly, check that input is a string or not.
|
||||
@ -53,7 +61,14 @@ const DateToDay = (date) => {
|
||||
Without the adaption, the formula yields `weekDay = -6` for the date 2/3/2014;
|
||||
With the adaption, it yields the positive result `weekDay = 7 - 6 = 1` (Sunday), which is what we need to index the array
|
||||
*/
|
||||
const weekDay = (day + Math.floor((month + 1) * 2.6) + yearDigits + Math.floor(yearDigits / 4) + Math.floor(century / 4) + 5 * century) % 7
|
||||
const weekDay =
|
||||
(day +
|
||||
Math.floor((month + 1) * 2.6) +
|
||||
yearDigits +
|
||||
Math.floor(yearDigits / 4) +
|
||||
Math.floor(century / 4) +
|
||||
5 * century) %
|
||||
7
|
||||
return daysNameArr[weekDay] // name of the weekday
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
function decimalToBinary (num) {
|
||||
function decimalToBinary(num) {
|
||||
const bin = []
|
||||
while (num > 0) {
|
||||
bin.unshift(num % 2)
|
||||
|
@ -1,16 +1,22 @@
|
||||
function intToHex (num) {
|
||||
function intToHex(num) {
|
||||
switch (num) {
|
||||
case 10: return 'A'
|
||||
case 11: return 'B'
|
||||
case 12: return 'C'
|
||||
case 13: return 'D'
|
||||
case 14: return 'E'
|
||||
case 15: return 'F'
|
||||
case 10:
|
||||
return 'A'
|
||||
case 11:
|
||||
return 'B'
|
||||
case 12:
|
||||
return 'C'
|
||||
case 13:
|
||||
return 'D'
|
||||
case 14:
|
||||
return 'E'
|
||||
case 15:
|
||||
return 'F'
|
||||
}
|
||||
return num
|
||||
}
|
||||
|
||||
function decimalToHex (num) {
|
||||
function decimalToHex(num) {
|
||||
const hexOut = []
|
||||
while (num > 15) {
|
||||
hexOut.unshift(intToHex(num % 16))
|
||||
|
@ -1,9 +1,9 @@
|
||||
function decimalToOctal (num) {
|
||||
function decimalToOctal(num) {
|
||||
let oct = 0
|
||||
let c = 0
|
||||
while (num > 0) {
|
||||
const r = num % 8
|
||||
oct = oct + (r * Math.pow(10, c++))
|
||||
oct = oct + r * Math.pow(10, c++)
|
||||
num = Math.floor(num / 8) // basically /= 8 without remainder if any
|
||||
}
|
||||
return oct
|
||||
|
@ -38,7 +38,7 @@ const orders = [
|
||||
'I'
|
||||
]
|
||||
|
||||
function decimalToRoman (num) {
|
||||
function decimalToRoman(num) {
|
||||
let roman = ''
|
||||
for (const symbol of orders) {
|
||||
while (num >= values[symbol]) {
|
||||
|
@ -1,21 +1,22 @@
|
||||
const binLookup = (key) => ({
|
||||
0: '0000',
|
||||
1: '0001',
|
||||
2: '0010',
|
||||
3: '0011',
|
||||
4: '0100',
|
||||
5: '0101',
|
||||
6: '0110',
|
||||
7: '0111',
|
||||
8: '1000',
|
||||
9: '1001',
|
||||
a: '1010',
|
||||
b: '1011',
|
||||
c: '1100',
|
||||
d: '1101',
|
||||
e: '1110',
|
||||
f: '1111'
|
||||
}[key.toLowerCase()]) // select the binary number by valid hex key with the help javascript object
|
||||
const binLookup = (key) =>
|
||||
({
|
||||
0: '0000',
|
||||
1: '0001',
|
||||
2: '0010',
|
||||
3: '0011',
|
||||
4: '0100',
|
||||
5: '0101',
|
||||
6: '0110',
|
||||
7: '0111',
|
||||
8: '1000',
|
||||
9: '1001',
|
||||
a: '1010',
|
||||
b: '1011',
|
||||
c: '1100',
|
||||
d: '1101',
|
||||
e: '1110',
|
||||
f: '1111'
|
||||
})[key.toLowerCase()] // select the binary number by valid hex key with the help javascript object
|
||||
|
||||
const hexToBinary = (hexString) => {
|
||||
if (typeof hexString !== 'string') {
|
||||
@ -32,10 +33,7 @@ const hexToBinary = (hexString) => {
|
||||
2. Conversion goes by searching in the lookup table
|
||||
*/
|
||||
|
||||
return hexString.replace(
|
||||
/[0-9a-f]/gi,
|
||||
lexeme => binLookup(lexeme)
|
||||
)
|
||||
return hexString.replace(/[0-9a-f]/gi, (lexeme) => binLookup(lexeme))
|
||||
}
|
||||
|
||||
export default hexToBinary
|
||||
|
@ -1,22 +1,31 @@
|
||||
function hexToInt (hexNum) {
|
||||
function hexToInt(hexNum) {
|
||||
const numArr = hexNum.split('') // converts number to array
|
||||
return numArr.map((item, index) => {
|
||||
switch (item) {
|
||||
case 'A': return 10
|
||||
case 'B': return 11
|
||||
case 'C': return 12
|
||||
case 'D': return 13
|
||||
case 'E': return 14
|
||||
case 'F': return 15
|
||||
default: return parseInt(item)
|
||||
case 'A':
|
||||
return 10
|
||||
case 'B':
|
||||
return 11
|
||||
case 'C':
|
||||
return 12
|
||||
case 'D':
|
||||
return 13
|
||||
case 'E':
|
||||
return 14
|
||||
case 'F':
|
||||
return 15
|
||||
default:
|
||||
return parseInt(item)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function hexToDecimal (hexNum) {
|
||||
function hexToDecimal(hexNum) {
|
||||
const intItemsArr = hexToInt(hexNum)
|
||||
return intItemsArr.reduce((accumulator, current, index) => {
|
||||
return accumulator + (current * Math.pow(16, (intItemsArr.length - (1 + index))))
|
||||
return (
|
||||
accumulator + current * Math.pow(16, intItemsArr.length - (1 + index))
|
||||
)
|
||||
}, 0)
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
function hexStringToRGB (hexString) {
|
||||
function hexStringToRGB(hexString) {
|
||||
let r = hexString.substring(0, 2)
|
||||
let g = hexString.substring(2, 4)
|
||||
let b = hexString.substring(4, 6)
|
||||
|
@ -33,6 +33,4 @@ const lengthConversion = (length, fromUnit, toUnit) => {
|
||||
return convertedLength
|
||||
}
|
||||
|
||||
export {
|
||||
lengthConversion
|
||||
}
|
||||
export { lengthConversion }
|
||||
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
const LowerCaseConversion = (inputString) => {
|
||||
// Take a string and split it into characters.
|
||||
const newString = inputString.split('').map(char => {
|
||||
const newString = inputString.split('').map((char) => {
|
||||
// Get a character code by the use charCodeAt method.
|
||||
const presentCharCode = char.charCodeAt()
|
||||
// If the character code lies between 65 to 90 it means they are in the upper case so convert it.
|
||||
|
@ -1,10 +1,10 @@
|
||||
function octalToDecimal (num) {
|
||||
function octalToDecimal(num) {
|
||||
let dec = 0
|
||||
let base = 1
|
||||
while (num > 0) {
|
||||
const r = num % 10
|
||||
num = Math.floor(num / 10)
|
||||
dec = dec + (r * base)
|
||||
dec = dec + r * base
|
||||
base = base * 8
|
||||
}
|
||||
return dec
|
||||
|
@ -5,7 +5,7 @@
|
||||
* @param {number} oz - Amount of ounces to convert to kilograms
|
||||
*/
|
||||
const ouncesToKilograms = (oz) => {
|
||||
return oz * 28.3498 / 1000
|
||||
return (oz * 28.3498) / 1000
|
||||
}
|
||||
|
||||
export default ouncesToKilograms
|
||||
|
@ -1,13 +1,9 @@
|
||||
function RGBToHex (r, g, b) {
|
||||
if (
|
||||
typeof r !== 'number' ||
|
||||
typeof g !== 'number' ||
|
||||
typeof b !== 'number'
|
||||
) {
|
||||
function RGBToHex(r, g, b) {
|
||||
if (typeof r !== 'number' || typeof g !== 'number' || typeof b !== 'number') {
|
||||
throw new TypeError('argument is not a Number')
|
||||
}
|
||||
|
||||
const toHex = n => (n || '0').toString(16).padStart(2, '0')
|
||||
const toHex = (n) => (n || '0').toString(16).padStart(2, '0')
|
||||
|
||||
return `#${toHex(r)}${toHex(g)}${toHex(b)}`
|
||||
}
|
||||
|
@ -23,12 +23,23 @@ const RailwayTimeConversion = (timeString) => {
|
||||
// split the string by ':' character.
|
||||
const [hour, minute, secondWithShift] = timeString.split(':')
|
||||
// split second and shift value.
|
||||
const [second, shift] = [secondWithShift.substr(0, 2), secondWithShift.substr(2)]
|
||||
const [second, shift] = [
|
||||
secondWithShift.substr(0, 2),
|
||||
secondWithShift.substr(2)
|
||||
]
|
||||
// convert shifted time to not-shift time(Railway time) by using the above explanation.
|
||||
if (shift === 'PM') {
|
||||
if (parseInt(hour) === 12) { return `${hour}:${minute}:${second}` } else { return `${parseInt(hour) + 12}:${minute}:${second}` }
|
||||
if (parseInt(hour) === 12) {
|
||||
return `${hour}:${minute}:${second}`
|
||||
} else {
|
||||
return `${parseInt(hour) + 12}:${minute}:${second}`
|
||||
}
|
||||
} else {
|
||||
if (parseInt(hour) === 12) { return `00:${minute}:${second}` } else { return `${hour}:${minute}:${second}` }
|
||||
if (parseInt(hour) === 12) {
|
||||
return `00:${minute}:${second}`
|
||||
} else {
|
||||
return `${hour}:${minute}:${second}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
* @param value Brightness-value of the color.
|
||||
* @return The tuple of RGB-components.
|
||||
*/
|
||||
export function hsvToRgb (hue, saturation, value) {
|
||||
export function hsvToRgb(hue, saturation, value) {
|
||||
if (hue < 0 || hue > 360) {
|
||||
throw new Error('hue should be between 0 and 360')
|
||||
}
|
||||
@ -31,7 +31,7 @@ export function hsvToRgb (hue, saturation, value) {
|
||||
|
||||
const chroma = value * saturation
|
||||
const hueSection = hue / 60
|
||||
const secondLargestComponent = chroma * (1 - Math.abs(hueSection % 2 - 1))
|
||||
const secondLargestComponent = chroma * (1 - Math.abs((hueSection % 2) - 1))
|
||||
const matchValue = value - chroma
|
||||
|
||||
return getRgbBySection(hueSection, chroma, matchValue, secondLargestComponent)
|
||||
@ -45,7 +45,7 @@ export function hsvToRgb (hue, saturation, value) {
|
||||
* @param blue Blue-component of the color.
|
||||
* @return The tuple of HSV-components.
|
||||
*/
|
||||
export function rgbToHsv (red, green, blue) {
|
||||
export function rgbToHsv(red, green, blue) {
|
||||
if (red < 0 || red > 255) {
|
||||
throw new Error('red should be between 0 and 255')
|
||||
}
|
||||
@ -81,7 +81,7 @@ export function rgbToHsv (red, green, blue) {
|
||||
return [hue, saturation, value]
|
||||
}
|
||||
|
||||
export function approximatelyEqualHsv (hsv1, hsv2) {
|
||||
export function approximatelyEqualHsv(hsv1, hsv2) {
|
||||
const bHue = Math.abs(hsv1[0] - hsv2[0]) < 0.2
|
||||
const bSaturation = Math.abs(hsv1[1] - hsv2[1]) < 0.002
|
||||
const bValue = Math.abs(hsv1[2] - hsv2[2]) < 0.002
|
||||
@ -89,8 +89,13 @@ export function approximatelyEqualHsv (hsv1, hsv2) {
|
||||
return bHue && bSaturation && bValue
|
||||
}
|
||||
|
||||
function getRgbBySection (hueSection, chroma, matchValue, secondLargestComponent) {
|
||||
function convertToInt (input) {
|
||||
function getRgbBySection(
|
||||
hueSection,
|
||||
chroma,
|
||||
matchValue,
|
||||
secondLargestComponent
|
||||
) {
|
||||
function convertToInt(input) {
|
||||
return Math.round(255 * input)
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ const values = {
|
||||
M: 1000
|
||||
}
|
||||
|
||||
export function romanToDecimal (romanNumber) {
|
||||
export function romanToDecimal(romanNumber) {
|
||||
let prev = ' '
|
||||
|
||||
let sum = 0
|
||||
|
@ -1,102 +1,113 @@
|
||||
// This files has functions to convert different temperature units
|
||||
// Functions take temperature value as a argument and returns corresponding converted value
|
||||
|
||||
const celsiusToFahrenheit = (celsius) => {
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Celsius
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Fahrenheit
|
||||
return Math.round(((celsius) * 9 / 5) + 32)
|
||||
}
|
||||
|
||||
const celsiusToKelvin = (celsius) => {
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Celsius
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Kelvin
|
||||
return Math.round((celsius) + 273.15)
|
||||
}
|
||||
|
||||
const celsiusToRankine = (celsius) => {
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Celsius
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Rankine_scale
|
||||
return Math.round(((celsius) * 9 / 5) + 491.67)
|
||||
}
|
||||
|
||||
const fahrenheitToCelsius = (fahrenheit) => {
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Fahrenheit
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Celsius
|
||||
return Math.round(((fahrenheit) - 32) * 5 / 9)
|
||||
}
|
||||
|
||||
const fahrenheitToKelvin = (fahrenheit) => {
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Fahrenheit
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Kelvin
|
||||
return Math.round((((fahrenheit) - 32) * 5 / 9) + 273.15)
|
||||
}
|
||||
|
||||
const fahrenheitToRankine = (fahrenheit) => {
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Fahrenheit
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Rankine_scale
|
||||
return Math.round((fahrenheit) + 459.67)
|
||||
}
|
||||
|
||||
const kelvinToCelsius = (kelvin) => {
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Kelvin
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Celsius
|
||||
return Math.round((kelvin) - 273.15)
|
||||
}
|
||||
|
||||
const kelvinToFahrenheit = (kelvin) => {
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Kelvin
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Fahrenheit
|
||||
return Math.round((((kelvin) - 273.15) * 9 / 5) + 32)
|
||||
}
|
||||
|
||||
const kelvinToRankine = (kelvin) => {
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Kelvin
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Rankine_scale
|
||||
return Math.round(((kelvin) * 9 / 5))
|
||||
}
|
||||
|
||||
const rankineToCelsius = (rankine) => {
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Rankine_scale
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Celsius
|
||||
return Math.round(((rankine) - 491.67) * 5 / 9)
|
||||
}
|
||||
|
||||
const rankineToFahrenheit = (rankine) => {
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Rankine_scale
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Fahrenheit
|
||||
return Math.round((rankine) - 459.67)
|
||||
}
|
||||
|
||||
const rankineToKelvin = (rankine) => {
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Rankine_scale
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Kelvin
|
||||
return Math.round(((rankine) * 5 / 9))
|
||||
}
|
||||
|
||||
const reaumurToKelvin = (reaumur) => {
|
||||
// Reference:- http://www.csgnetwork.com/temp2conv.html
|
||||
return Math.round(((reaumur) * 1.25 + 273.15))
|
||||
}
|
||||
|
||||
const reaumurToFahrenheit = (reaumur) => {
|
||||
// Reference:- http://www.csgnetwork.com/temp2conv.html
|
||||
return Math.round(((reaumur) * 2.25 + 32))
|
||||
}
|
||||
|
||||
const reaumurToCelsius = (reaumur) => {
|
||||
// Reference:- http://www.csgnetwork.com/temp2conv.html
|
||||
return Math.round(((reaumur) * 1.25))
|
||||
}
|
||||
|
||||
const reaumurToRankine = (reaumur) => {
|
||||
// Reference:- http://www.csgnetwork.com/temp2conv.html
|
||||
return Math.round(((reaumur) * 2.25 + 32 + 459.67))
|
||||
}
|
||||
|
||||
export {
|
||||
celsiusToFahrenheit, celsiusToKelvin, celsiusToRankine,
|
||||
fahrenheitToCelsius, fahrenheitToKelvin, fahrenheitToRankine,
|
||||
kelvinToCelsius, kelvinToFahrenheit, kelvinToRankine,
|
||||
rankineToCelsius, rankineToFahrenheit, rankineToKelvin,
|
||||
reaumurToCelsius, reaumurToFahrenheit, reaumurToKelvin, reaumurToRankine
|
||||
}
|
||||
// This files has functions to convert different temperature units
|
||||
// Functions take temperature value as a argument and returns corresponding converted value
|
||||
|
||||
const celsiusToFahrenheit = (celsius) => {
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Celsius
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Fahrenheit
|
||||
return Math.round((celsius * 9) / 5 + 32)
|
||||
}
|
||||
|
||||
const celsiusToKelvin = (celsius) => {
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Celsius
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Kelvin
|
||||
return Math.round(celsius + 273.15)
|
||||
}
|
||||
|
||||
const celsiusToRankine = (celsius) => {
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Celsius
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Rankine_scale
|
||||
return Math.round((celsius * 9) / 5 + 491.67)
|
||||
}
|
||||
|
||||
const fahrenheitToCelsius = (fahrenheit) => {
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Fahrenheit
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Celsius
|
||||
return Math.round(((fahrenheit - 32) * 5) / 9)
|
||||
}
|
||||
|
||||
const fahrenheitToKelvin = (fahrenheit) => {
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Fahrenheit
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Kelvin
|
||||
return Math.round(((fahrenheit - 32) * 5) / 9 + 273.15)
|
||||
}
|
||||
|
||||
const fahrenheitToRankine = (fahrenheit) => {
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Fahrenheit
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Rankine_scale
|
||||
return Math.round(fahrenheit + 459.67)
|
||||
}
|
||||
|
||||
const kelvinToCelsius = (kelvin) => {
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Kelvin
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Celsius
|
||||
return Math.round(kelvin - 273.15)
|
||||
}
|
||||
|
||||
const kelvinToFahrenheit = (kelvin) => {
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Kelvin
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Fahrenheit
|
||||
return Math.round(((kelvin - 273.15) * 9) / 5 + 32)
|
||||
}
|
||||
|
||||
const kelvinToRankine = (kelvin) => {
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Kelvin
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Rankine_scale
|
||||
return Math.round((kelvin * 9) / 5)
|
||||
}
|
||||
|
||||
const rankineToCelsius = (rankine) => {
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Rankine_scale
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Celsius
|
||||
return Math.round(((rankine - 491.67) * 5) / 9)
|
||||
}
|
||||
|
||||
const rankineToFahrenheit = (rankine) => {
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Rankine_scale
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Fahrenheit
|
||||
return Math.round(rankine - 459.67)
|
||||
}
|
||||
|
||||
const rankineToKelvin = (rankine) => {
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Rankine_scale
|
||||
// Wikipedia reference: https://en.wikipedia.org/wiki/Kelvin
|
||||
return Math.round((rankine * 5) / 9)
|
||||
}
|
||||
|
||||
const reaumurToKelvin = (reaumur) => {
|
||||
// Reference:- http://www.csgnetwork.com/temp2conv.html
|
||||
return Math.round(reaumur * 1.25 + 273.15)
|
||||
}
|
||||
|
||||
const reaumurToFahrenheit = (reaumur) => {
|
||||
// Reference:- http://www.csgnetwork.com/temp2conv.html
|
||||
return Math.round(reaumur * 2.25 + 32)
|
||||
}
|
||||
|
||||
const reaumurToCelsius = (reaumur) => {
|
||||
// Reference:- http://www.csgnetwork.com/temp2conv.html
|
||||
return Math.round(reaumur * 1.25)
|
||||
}
|
||||
|
||||
const reaumurToRankine = (reaumur) => {
|
||||
// Reference:- http://www.csgnetwork.com/temp2conv.html
|
||||
return Math.round(reaumur * 2.25 + 32 + 459.67)
|
||||
}
|
||||
|
||||
export {
|
||||
celsiusToFahrenheit,
|
||||
celsiusToKelvin,
|
||||
celsiusToRankine,
|
||||
fahrenheitToCelsius,
|
||||
fahrenheitToKelvin,
|
||||
fahrenheitToRankine,
|
||||
kelvinToCelsius,
|
||||
kelvinToFahrenheit,
|
||||
kelvinToRankine,
|
||||
rankineToCelsius,
|
||||
rankineToFahrenheit,
|
||||
rankineToKelvin,
|
||||
reaumurToCelsius,
|
||||
reaumurToFahrenheit,
|
||||
reaumurToKelvin,
|
||||
reaumurToRankine
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
const titleCaseConversion = (inputString) => {
|
||||
if (inputString === '') return ''
|
||||
// Extract all space separated string.
|
||||
const stringCollections = inputString.split(' ').map(word => {
|
||||
const stringCollections = inputString.split(' ').map((word) => {
|
||||
let firstChar = ''
|
||||
// Get the [ASCII](https://en.wikipedia.org/wiki/ASCII) character code by the use charCodeAt method.
|
||||
const firstCharCode = word[0].charCodeAt()
|
||||
@ -25,17 +25,20 @@ const titleCaseConversion = (inputString) => {
|
||||
// Else store the characters without any modification.
|
||||
firstChar += word[0]
|
||||
}
|
||||
const newWordChar = word.slice(1).split('').map(char => {
|
||||
// Get the ASCII character code by the use charCodeAt method.
|
||||
const presentCharCode = char.charCodeAt()
|
||||
// If the ASCII character code lies between 65 to 90, it means they are in the uppercase so convert it.
|
||||
if (presentCharCode >= 65 && presentCharCode <= 90) {
|
||||
// Convert the case by use of the above explanation.
|
||||
return String.fromCharCode(presentCharCode + 32)
|
||||
}
|
||||
// Else return the characters without any modification.
|
||||
return char
|
||||
})
|
||||
const newWordChar = word
|
||||
.slice(1)
|
||||
.split('')
|
||||
.map((char) => {
|
||||
// Get the ASCII character code by the use charCodeAt method.
|
||||
const presentCharCode = char.charCodeAt()
|
||||
// If the ASCII character code lies between 65 to 90, it means they are in the uppercase so convert it.
|
||||
if (presentCharCode >= 65 && presentCharCode <= 90) {
|
||||
// Convert the case by use of the above explanation.
|
||||
return String.fromCharCode(presentCharCode + 32)
|
||||
}
|
||||
// Else return the characters without any modification.
|
||||
return char
|
||||
})
|
||||
// Return the first converted character and remaining character string.
|
||||
return firstChar + newWordChar.join('')
|
||||
})
|
||||
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
const upperCaseConversion = (inputString) => {
|
||||
// Take a string and split it into characters.
|
||||
const newString = inputString.split('').map(char => {
|
||||
const newString = inputString.split('').map((char) => {
|
||||
// Get a character code by the use charCodeAt method.
|
||||
const presentCharCode = char.charCodeAt()
|
||||
// If the character code lies between 97 to 122, it means they are in the lowercase so convert it.
|
||||
|
@ -1,4 +1,7 @@
|
||||
import { convertArbitraryBase, convertArbitraryBaseBigIntVersion } from '../ArbitraryBase'
|
||||
import {
|
||||
convertArbitraryBase,
|
||||
convertArbitraryBaseBigIntVersion
|
||||
} from '../ArbitraryBase'
|
||||
|
||||
test('Check the answer of convertArbitraryBase(98, 0123456789, 01234567) is 142', () => {
|
||||
const res = convertArbitraryBase('98', '0123456789', '01234567')
|
||||
|
@ -14,6 +14,8 @@ describe('BinaryToHex', () => {
|
||||
})
|
||||
|
||||
it('expects to return correct hexadecimal value, matching (num).toString(16)', () => {
|
||||
expect(binaryToHex('1111')).toBe(parseInt('1111', 2).toString(16).toUpperCase())
|
||||
expect(binaryToHex('1111')).toBe(
|
||||
parseInt('1111', 2).toString(16).toUpperCase()
|
||||
)
|
||||
})
|
||||
})
|
||||
|
@ -1,16 +1,16 @@
|
||||
import { hexStringToRGB } from '../HexToRGB'
|
||||
|
||||
test('The RGB form of Hex String E1E1E1 is {r: 225, g: 225, b: 225}', () => {
|
||||
const res = hexStringToRGB('E1E1E1')
|
||||
expect(res).toEqual({ r: 225, g: 225, b: 225 })
|
||||
})
|
||||
|
||||
test('The RGB form of Hex String 000000 is {r: 0, g: 0, b: 0}', () => {
|
||||
const res = hexStringToRGB('000000')
|
||||
expect(res).toEqual({ r: 0, g: 0, b: 0 })
|
||||
})
|
||||
|
||||
test('The RGB form of Hex String 6CE1CD is {r: 108, g: 225, b: 205}', () => {
|
||||
const res = hexStringToRGB('6CE1CD')
|
||||
expect(res).toEqual({ r: 108, g: 225, b: 205 })
|
||||
})
|
||||
import { hexStringToRGB } from '../HexToRGB'
|
||||
|
||||
test('The RGB form of Hex String E1E1E1 is {r: 225, g: 225, b: 225}', () => {
|
||||
const res = hexStringToRGB('E1E1E1')
|
||||
expect(res).toEqual({ r: 225, g: 225, b: 225 })
|
||||
})
|
||||
|
||||
test('The RGB form of Hex String 000000 is {r: 0, g: 0, b: 0}', () => {
|
||||
const res = hexStringToRGB('000000')
|
||||
expect(res).toEqual({ r: 0, g: 0, b: 0 })
|
||||
})
|
||||
|
||||
test('The RGB form of Hex String 6CE1CD is {r: 108, g: 225, b: 205}', () => {
|
||||
const res = hexStringToRGB('6CE1CD')
|
||||
expect(res).toEqual({ r: 108, g: 225, b: 205 })
|
||||
})
|
||||
|
@ -2,11 +2,11 @@ import { lengthConversion } from '../LengthConversion.js'
|
||||
|
||||
describe('LengthConversion', () => {
|
||||
it.each`
|
||||
length | fromUnit | toUnit | expected
|
||||
${10} | ${'km'} | ${'m'} | ${10000}
|
||||
${100} | ${'m'} | ${'km'} | ${0.1}
|
||||
${5} | ${'cm'} | ${'mm'} | ${50}
|
||||
${12} | ${'ft'} | ${'inch'}| ${144.00000000000003}
|
||||
length | fromUnit | toUnit | expected
|
||||
${10} | ${'km'} | ${'m'} | ${10000}
|
||||
${100} | ${'m'} | ${'km'} | ${0.1}
|
||||
${5} | ${'cm'} | ${'mm'} | ${50}
|
||||
${12} | ${'ft'} | ${'inch'} | ${144.00000000000003}
|
||||
`(
|
||||
'converts $length $fromUnit to $toUnit',
|
||||
({ length, fromUnit, toUnit, expected }) => {
|
||||
@ -20,10 +20,10 @@ describe('LengthConversion', () => {
|
||||
)
|
||||
|
||||
it.each`
|
||||
length | fromUnit | toUnit | expected
|
||||
${10} | ${'m'} | ${'km'} | ${0.01}
|
||||
${1000}| ${'mm'} | ${'cm'} | ${100}
|
||||
${1} | ${'inch'}| ${'ft'} | ${0.08333333333}
|
||||
length | fromUnit | toUnit | expected
|
||||
${10} | ${'m'} | ${'km'} | ${0.01}
|
||||
${1000} | ${'mm'} | ${'cm'} | ${100}
|
||||
${1} | ${'inch'} | ${'ft'} | ${0.08333333333}
|
||||
`(
|
||||
'converts $length $fromUnit to $toUnit (vice versa)',
|
||||
({ length, fromUnit, toUnit, expected }) => {
|
||||
@ -37,9 +37,9 @@ describe('LengthConversion', () => {
|
||||
)
|
||||
|
||||
it.each`
|
||||
length | fromUnit | toUnit | expectedError
|
||||
${10} | ${'km'} | ${'invalid'} | ${'Invalid units'}
|
||||
${5} | ${'invalid'} | ${'m'} | ${'Invalid units'}
|
||||
length | fromUnit | toUnit | expectedError
|
||||
${10} | ${'km'} | ${'invalid'} | ${'Invalid units'}
|
||||
${5} | ${'invalid'} | ${'m'} | ${'Invalid units'}
|
||||
`(
|
||||
'returns error message for invalid units: $fromUnit to $toUnit',
|
||||
({ length, fromUnit, toUnit, expectedError }) => {
|
||||
|
@ -20,14 +20,30 @@ describe('rgbToHsv', () => {
|
||||
// "approximatelyEqualHsv" needed because of small deviations due to rounding for the RGB-values
|
||||
it('should calculate the correct HSV values', () => {
|
||||
expect(approximatelyEqualHsv(rgbToHsv(0, 0, 0), [0, 0, 0])).toEqual(true)
|
||||
expect(approximatelyEqualHsv(rgbToHsv(255, 255, 255), [0, 0, 1])).toEqual(true)
|
||||
expect(approximatelyEqualHsv(rgbToHsv(255, 255, 255), [0, 0, 1])).toEqual(
|
||||
true
|
||||
)
|
||||
expect(approximatelyEqualHsv(rgbToHsv(255, 0, 0), [0, 1, 1])).toEqual(true)
|
||||
expect(approximatelyEqualHsv(rgbToHsv(255, 255, 0), [60, 1, 1])).toEqual(true)
|
||||
expect(approximatelyEqualHsv(rgbToHsv(0, 255, 0), [120, 1, 1])).toEqual(true)
|
||||
expect(approximatelyEqualHsv(rgbToHsv(0, 0, 255), [240, 1, 1])).toEqual(true)
|
||||
expect(approximatelyEqualHsv(rgbToHsv(255, 0, 255), [300, 1, 1])).toEqual(true)
|
||||
expect(approximatelyEqualHsv(rgbToHsv(64, 128, 128), [180, 0.5, 0.5])).toEqual(true)
|
||||
expect(approximatelyEqualHsv(rgbToHsv(193, 196, 224), [234, 0.14, 0.88])).toEqual(true)
|
||||
expect(approximatelyEqualHsv(rgbToHsv(128, 32, 80), [330, 0.75, 0.5])).toEqual(true)
|
||||
expect(approximatelyEqualHsv(rgbToHsv(255, 255, 0), [60, 1, 1])).toEqual(
|
||||
true
|
||||
)
|
||||
expect(approximatelyEqualHsv(rgbToHsv(0, 255, 0), [120, 1, 1])).toEqual(
|
||||
true
|
||||
)
|
||||
expect(approximatelyEqualHsv(rgbToHsv(0, 0, 255), [240, 1, 1])).toEqual(
|
||||
true
|
||||
)
|
||||
expect(approximatelyEqualHsv(rgbToHsv(255, 0, 255), [300, 1, 1])).toEqual(
|
||||
true
|
||||
)
|
||||
expect(
|
||||
approximatelyEqualHsv(rgbToHsv(64, 128, 128), [180, 0.5, 0.5])
|
||||
).toEqual(true)
|
||||
expect(
|
||||
approximatelyEqualHsv(rgbToHsv(193, 196, 224), [234, 0.14, 0.88])
|
||||
).toEqual(true)
|
||||
expect(
|
||||
approximatelyEqualHsv(rgbToHsv(128, 32, 80), [330, 0.75, 0.5])
|
||||
).toEqual(true)
|
||||
})
|
||||
})
|
||||
|
@ -1,106 +1,106 @@
|
||||
import * as tc from '../TemperatureConversion.js'
|
||||
|
||||
describe('Testing Conversion of Celsius to fahrenheit', () => {
|
||||
it('with celsius value', () => {
|
||||
const test1 = tc.celsiusToFahrenheit(10)
|
||||
expect(test1).toBe(50)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Testing Conversion of Celsius to kelvin', () => {
|
||||
it('with celsius value', () => {
|
||||
const test1 = tc.celsiusToKelvin(15)
|
||||
expect(test1).toBe(288)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Testing Conversion of Celsius to Rankine', () => {
|
||||
it('with celsius value', () => {
|
||||
const test1 = tc.celsiusToRankine(28)
|
||||
expect(test1).toBe(542)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Testing Conversion of Fahrenheit to Celsius', () => {
|
||||
it('with Fahrenheit value', () => {
|
||||
const test1 = tc.fahrenheitToCelsius(134)
|
||||
expect(test1).toBe(57)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Testing Conversion of Fahrenheit to Kelvin', () => {
|
||||
it('with Fahrenheit value', () => {
|
||||
const test1 = tc.fahrenheitToKelvin(125)
|
||||
expect(test1).toBe(325)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Testing Conversion of Fahrenheit to Rankine', () => {
|
||||
it('with Fahrenheit value', () => {
|
||||
const test1 = tc.fahrenheitToRankine(10)
|
||||
expect(test1).toBe(470)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Testing Conversion of Kelvin to Celsius', () => {
|
||||
it('with Kelvin value', () => {
|
||||
const test1 = tc.kelvinToCelsius(100)
|
||||
expect(test1).toBe(-173)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Testing Conversion of Kelvin to Fahrenheit', () => {
|
||||
it('with Kelvin value', () => {
|
||||
const test1 = tc.kelvinToFahrenheit(20)
|
||||
expect(test1).toBe(-424)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Testing Conversion of Kelvin to Rankine', () => {
|
||||
it('with kelvin value', () => {
|
||||
const test1 = tc.kelvinToRankine(69)
|
||||
expect(test1).toBe(124)
|
||||
})
|
||||
})
|
||||
describe('Testing Conversion of Rankine to Celsius', () => {
|
||||
it('with Rankine value', () => {
|
||||
const test1 = tc.rankineToCelsius(234)
|
||||
expect(test1).toBe(-143)
|
||||
})
|
||||
})
|
||||
describe('Testing Conversion of Rankine to Fahrenheit', () => {
|
||||
it('with Rankine value', () => {
|
||||
const test1 = tc.rankineToFahrenheit(98)
|
||||
expect(test1).toBe(-362)
|
||||
})
|
||||
})
|
||||
describe('Testing Conversion of Rankine to Kelvin', () => {
|
||||
it('with Rankine value', () => {
|
||||
const test1 = tc.rankineToKelvin(10)
|
||||
expect(test1).toBe(6)
|
||||
})
|
||||
})
|
||||
describe('Testing Conversion of Reaumur to Celsius', () => {
|
||||
it('with Reaumur value', () => {
|
||||
const test1 = tc.reaumurToCelsius(100)
|
||||
expect(test1).toBe(125)
|
||||
})
|
||||
})
|
||||
describe('Testing Conversion of Reaumur to Fahrenheit', () => {
|
||||
it('with Reaumur value', () => {
|
||||
const test1 = tc.reaumurToFahrenheit(100)
|
||||
expect(test1).toBe(257)
|
||||
})
|
||||
})
|
||||
describe('Testing Conversion of Reaumur to Kelvin', () => {
|
||||
it('with Reamur value', () => {
|
||||
const test1 = tc.reaumurToKelvin(100)
|
||||
expect(test1).toBe(398)
|
||||
})
|
||||
})
|
||||
describe('Testing Conversion of Reamur to Rankine', () => {
|
||||
it('with Reamur value', () => {
|
||||
const test1 = tc.reaumurToRankine(100)
|
||||
expect(test1).toBe(717)
|
||||
})
|
||||
})
|
||||
import * as tc from '../TemperatureConversion.js'
|
||||
|
||||
describe('Testing Conversion of Celsius to fahrenheit', () => {
|
||||
it('with celsius value', () => {
|
||||
const test1 = tc.celsiusToFahrenheit(10)
|
||||
expect(test1).toBe(50)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Testing Conversion of Celsius to kelvin', () => {
|
||||
it('with celsius value', () => {
|
||||
const test1 = tc.celsiusToKelvin(15)
|
||||
expect(test1).toBe(288)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Testing Conversion of Celsius to Rankine', () => {
|
||||
it('with celsius value', () => {
|
||||
const test1 = tc.celsiusToRankine(28)
|
||||
expect(test1).toBe(542)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Testing Conversion of Fahrenheit to Celsius', () => {
|
||||
it('with Fahrenheit value', () => {
|
||||
const test1 = tc.fahrenheitToCelsius(134)
|
||||
expect(test1).toBe(57)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Testing Conversion of Fahrenheit to Kelvin', () => {
|
||||
it('with Fahrenheit value', () => {
|
||||
const test1 = tc.fahrenheitToKelvin(125)
|
||||
expect(test1).toBe(325)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Testing Conversion of Fahrenheit to Rankine', () => {
|
||||
it('with Fahrenheit value', () => {
|
||||
const test1 = tc.fahrenheitToRankine(10)
|
||||
expect(test1).toBe(470)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Testing Conversion of Kelvin to Celsius', () => {
|
||||
it('with Kelvin value', () => {
|
||||
const test1 = tc.kelvinToCelsius(100)
|
||||
expect(test1).toBe(-173)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Testing Conversion of Kelvin to Fahrenheit', () => {
|
||||
it('with Kelvin value', () => {
|
||||
const test1 = tc.kelvinToFahrenheit(20)
|
||||
expect(test1).toBe(-424)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Testing Conversion of Kelvin to Rankine', () => {
|
||||
it('with kelvin value', () => {
|
||||
const test1 = tc.kelvinToRankine(69)
|
||||
expect(test1).toBe(124)
|
||||
})
|
||||
})
|
||||
describe('Testing Conversion of Rankine to Celsius', () => {
|
||||
it('with Rankine value', () => {
|
||||
const test1 = tc.rankineToCelsius(234)
|
||||
expect(test1).toBe(-143)
|
||||
})
|
||||
})
|
||||
describe('Testing Conversion of Rankine to Fahrenheit', () => {
|
||||
it('with Rankine value', () => {
|
||||
const test1 = tc.rankineToFahrenheit(98)
|
||||
expect(test1).toBe(-362)
|
||||
})
|
||||
})
|
||||
describe('Testing Conversion of Rankine to Kelvin', () => {
|
||||
it('with Rankine value', () => {
|
||||
const test1 = tc.rankineToKelvin(10)
|
||||
expect(test1).toBe(6)
|
||||
})
|
||||
})
|
||||
describe('Testing Conversion of Reaumur to Celsius', () => {
|
||||
it('with Reaumur value', () => {
|
||||
const test1 = tc.reaumurToCelsius(100)
|
||||
expect(test1).toBe(125)
|
||||
})
|
||||
})
|
||||
describe('Testing Conversion of Reaumur to Fahrenheit', () => {
|
||||
it('with Reaumur value', () => {
|
||||
const test1 = tc.reaumurToFahrenheit(100)
|
||||
expect(test1).toBe(257)
|
||||
})
|
||||
})
|
||||
describe('Testing Conversion of Reaumur to Kelvin', () => {
|
||||
it('with Reamur value', () => {
|
||||
const test1 = tc.reaumurToKelvin(100)
|
||||
expect(test1).toBe(398)
|
||||
})
|
||||
})
|
||||
describe('Testing Conversion of Reamur to Rankine', () => {
|
||||
it('with Reamur value', () => {
|
||||
const test1 = tc.reaumurToRankine(100)
|
||||
expect(test1).toBe(717)
|
||||
})
|
||||
})
|
||||
|
@ -1,12 +1,14 @@
|
||||
import { titleCaseConversion } from '../TitleCaseConversion'
|
||||
|
||||
describe(('Tests for the titleCaseConversion function'), () => {
|
||||
describe('Tests for the titleCaseConversion function', () => {
|
||||
it('should return an empty string when the input is an empty string', () => {
|
||||
expect(titleCaseConversion('')).toEqual('')
|
||||
})
|
||||
|
||||
it('should return the input string when the input string is a title case string', () => {
|
||||
expect(titleCaseConversion('A Proper Title Case String')).toEqual('A Proper Title Case String')
|
||||
expect(titleCaseConversion('A Proper Title Case String')).toEqual(
|
||||
'A Proper Title Case String'
|
||||
)
|
||||
})
|
||||
|
||||
it('should return a title case string when input is an all-uppercase string', () => {
|
||||
@ -34,7 +36,9 @@ describe(('Tests for the titleCaseConversion function'), () => {
|
||||
})
|
||||
|
||||
it('should return a title case string when input is an all-lowercase string with punctuation', () => {
|
||||
expect(titleCaseConversion('lower, case, input.')).toEqual('Lower, Case, Input.')
|
||||
expect(titleCaseConversion('lower, case, input.')).toEqual(
|
||||
'Lower, Case, Input.'
|
||||
)
|
||||
})
|
||||
|
||||
it('should return a title case string when input is an mixed-case string', () => {
|
||||
@ -46,6 +50,8 @@ describe(('Tests for the titleCaseConversion function'), () => {
|
||||
})
|
||||
|
||||
it('should return a title case string when input is an mixed-case string with punctuation', () => {
|
||||
expect(titleCaseConversion('mixeD, CaSe, INPuT!')).toEqual('Mixed, Case, Input!')
|
||||
expect(titleCaseConversion('mixeD, CaSe, INPuT!')).toEqual(
|
||||
'Mixed, Case, Input!'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { upperCaseConversion } from '../UpperCaseConversion'
|
||||
|
||||
describe(('Test the upperCaseConversion function'), () => {
|
||||
describe('Test the upperCaseConversion function', () => {
|
||||
it('should return an empty string when the input is an empty string', () => {
|
||||
expect(upperCaseConversion('')).toEqual('')
|
||||
})
|
||||
@ -26,7 +26,9 @@ describe(('Test the upperCaseConversion function'), () => {
|
||||
})
|
||||
|
||||
it('should return an all-uppercase string when input is an all-lowercase string with punctuation', () => {
|
||||
expect(upperCaseConversion('lower-case, input.')).toEqual('LOWER-CASE, INPUT.')
|
||||
expect(upperCaseConversion('lower-case, input.')).toEqual(
|
||||
'LOWER-CASE, INPUT.'
|
||||
)
|
||||
})
|
||||
|
||||
it('should return an all-uppercase string when input is an mixed-case string', () => {
|
||||
@ -38,6 +40,8 @@ describe(('Test the upperCaseConversion function'), () => {
|
||||
})
|
||||
|
||||
it('should return an all-uppercase string when input is an mixed-case string with punctuation', () => {
|
||||
expect(upperCaseConversion('mixeD-CaSe INPuT!')).toEqual('MIXED-CASE INPUT!')
|
||||
expect(upperCaseConversion('mixeD-CaSe INPuT!')).toEqual(
|
||||
'MIXED-CASE INPUT!'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
@ -47,6 +47,7 @@
|
||||
* [HexToBinary](Conversions/HexToBinary.js)
|
||||
* [HexToDecimal](Conversions/HexToDecimal.js)
|
||||
* [HexToRGB](Conversions/HexToRGB.js)
|
||||
* [LengthConversion](Conversions/LengthConversion.js)
|
||||
* [LitersToImperialGallons](Conversions/LitersToImperialGallons.js)
|
||||
* [LitersToUSGallons](Conversions/LitersToUSGallons.js)
|
||||
* [LowerCaseConversion](Conversions/LowerCaseConversion.js)
|
||||
@ -233,6 +234,7 @@
|
||||
* [PowLogarithmic](Maths/PowLogarithmic.js)
|
||||
* [PrimeCheck](Maths/PrimeCheck.js)
|
||||
* [PrimeFactors](Maths/PrimeFactors.js)
|
||||
* [QuadraticRoots](Maths/QuadraticRoots.js)
|
||||
* [RadianToDegree](Maths/RadianToDegree.js)
|
||||
* [ReverseNumber](Maths/ReverseNumber.js)
|
||||
* [ReversePolishNotation](Maths/ReversePolishNotation.js)
|
||||
@ -363,6 +365,7 @@
|
||||
* [HammingDistance](String/HammingDistance.js)
|
||||
* [IsPalindrome](String/IsPalindrome.js)
|
||||
* [KMPPatternSearching](String/KMPPatternSearching.js)
|
||||
* [LengthofLongestSubstringWithoutRepetition](String/LengthofLongestSubstringWithoutRepetition.js)
|
||||
* [LevenshteinDistance](String/LevenshteinDistance.js)
|
||||
* [Lower](String/Lower.js)
|
||||
* [MaxCharacter](String/MaxCharacter.js)
|
||||
|
@ -9,19 +9,38 @@
|
||||
* @complexity: O(log(n)) (worst case)
|
||||
* @flow
|
||||
*/
|
||||
const findMaxPointIndex = (array, rangeStartIndex, rangeEndIndex, originalLength) => {
|
||||
const findMaxPointIndex = (
|
||||
array,
|
||||
rangeStartIndex,
|
||||
rangeEndIndex,
|
||||
originalLength
|
||||
) => {
|
||||
// find index range middle point
|
||||
const middleIndex = rangeStartIndex + parseInt((rangeEndIndex - rangeStartIndex) / 2)
|
||||
const middleIndex =
|
||||
rangeStartIndex + parseInt((rangeEndIndex - rangeStartIndex) / 2)
|
||||
|
||||
// handle array bounds
|
||||
if ((middleIndex === 0 || array[middleIndex - 1] <= array[middleIndex]) &&
|
||||
(middleIndex === originalLength - 1 || array[middleIndex + 1] <= array[middleIndex])) {
|
||||
if (
|
||||
(middleIndex === 0 || array[middleIndex - 1] <= array[middleIndex]) &&
|
||||
(middleIndex === originalLength - 1 ||
|
||||
array[middleIndex + 1] <= array[middleIndex])
|
||||
) {
|
||||
return middleIndex
|
||||
} else if (middleIndex > 0 && array[middleIndex - 1] > array[middleIndex]) {
|
||||
return findMaxPointIndex(array, rangeStartIndex, (middleIndex - 1), originalLength)
|
||||
return findMaxPointIndex(
|
||||
array,
|
||||
rangeStartIndex,
|
||||
middleIndex - 1,
|
||||
originalLength
|
||||
)
|
||||
} else {
|
||||
// regular local max
|
||||
return findMaxPointIndex(array, (middleIndex + 1), rangeEndIndex, originalLength)
|
||||
return findMaxPointIndex(
|
||||
array,
|
||||
middleIndex + 1,
|
||||
rangeEndIndex,
|
||||
originalLength
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,10 +33,13 @@ const CountLocalMaximumPoints = (array, startIndex, endIndex) => {
|
||||
|
||||
// handle the two halves
|
||||
const middleIndex = parseInt((startIndex + endIndex) / 2)
|
||||
return CountLocalMaximumPoints(array, startIndex, middleIndex) +
|
||||
return (
|
||||
CountLocalMaximumPoints(array, startIndex, middleIndex) +
|
||||
CountLocalMaximumPoints(array, middleIndex + 1, endIndex)
|
||||
)
|
||||
}
|
||||
|
||||
const NumberOfLocalMaximumPoints = (A) => CountLocalMaximumPoints(A, 0, A.length - 1)
|
||||
const NumberOfLocalMaximumPoints = (A) =>
|
||||
CountLocalMaximumPoints(A, 0, A.length - 1)
|
||||
|
||||
export { NumberOfLocalMaximumPoints }
|
||||
|
@ -11,7 +11,8 @@
|
||||
* @flow
|
||||
*/
|
||||
|
||||
function QuickSelect (items, kth) { // eslint-disable-line no-unused-vars
|
||||
function QuickSelect(items, kth) {
|
||||
// eslint-disable-line no-unused-vars
|
||||
if (kth < 1 || kth > items.length) {
|
||||
throw new RangeError('Index Out of Bound')
|
||||
}
|
||||
@ -19,7 +20,7 @@ function QuickSelect (items, kth) { // eslint-disable-line no-unused-vars
|
||||
return RandomizedSelect(items, 0, items.length - 1, kth)
|
||||
}
|
||||
|
||||
function RandomizedSelect (items, left, right, i) {
|
||||
function RandomizedSelect(items, left, right, i) {
|
||||
if (left === right) return items[left]
|
||||
|
||||
const pivotIndex = RandomizedPartition(items, left, right)
|
||||
@ -31,13 +32,13 @@ function RandomizedSelect (items, left, right, i) {
|
||||
return RandomizedSelect(items, pivotIndex + 1, right, i - k)
|
||||
}
|
||||
|
||||
function RandomizedPartition (items, left, right) {
|
||||
function RandomizedPartition(items, left, right) {
|
||||
const rand = getRandomInt(left, right)
|
||||
Swap(items, rand, right)
|
||||
return Partition(items, left, right)
|
||||
}
|
||||
|
||||
function Partition (items, left, right) {
|
||||
function Partition(items, left, right) {
|
||||
const x = items[right]
|
||||
let pivotIndex = left - 1
|
||||
|
||||
@ -53,12 +54,12 @@ function Partition (items, left, right) {
|
||||
return pivotIndex + 1
|
||||
}
|
||||
|
||||
function getRandomInt (min, max) {
|
||||
function getRandomInt(min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min
|
||||
}
|
||||
|
||||
function Swap (arr, x, y) {
|
||||
[arr[x], arr[y]] = [arr[y], arr[x]]
|
||||
function Swap(arr, x, y) {
|
||||
;[arr[x], arr[y]] = [arr[y], arr[x]]
|
||||
}
|
||||
|
||||
export { QuickSelect }
|
||||
|
@ -1,13 +1,14 @@
|
||||
import { Reverse } from '../Reverse.js'
|
||||
import each from 'jest-each'
|
||||
|
||||
describe('reverse elements in an array', () => {
|
||||
each`
|
||||
array | expected
|
||||
${[]} | ${[]}
|
||||
${[1]} | ${[1]}
|
||||
${[1, 2, 3, 4]} | ${[4, 3, 2, 1]}
|
||||
`.test('returns $expected when given $array', ({ array, expected }) => {
|
||||
expect(Reverse(array)).toEqual(expected)
|
||||
})
|
||||
it.each([
|
||||
[[], []],
|
||||
[[1], [1]],
|
||||
[
|
||||
[1, 2, 3, 4],
|
||||
[4, 3, 2, 1]
|
||||
]
|
||||
])('returns %j when given %j', (array, expected) => {
|
||||
expect(Reverse(array)).toEqual(expected)
|
||||
})
|
||||
})
|
||||
|
@ -1,24 +1,24 @@
|
||||
class Graph {
|
||||
constructor () {
|
||||
constructor() {
|
||||
this.adjacencyMap = {}
|
||||
}
|
||||
|
||||
addVertex (vertex) {
|
||||
addVertex(vertex) {
|
||||
this.adjacencyMap[vertex] = []
|
||||
}
|
||||
|
||||
containsVertex (vertex) {
|
||||
return typeof (this.adjacencyMap[vertex]) !== 'undefined'
|
||||
containsVertex(vertex) {
|
||||
return typeof this.adjacencyMap[vertex] !== 'undefined'
|
||||
}
|
||||
|
||||
addEdge (vertex1, vertex2) {
|
||||
addEdge(vertex1, vertex2) {
|
||||
if (this.containsVertex(vertex1) && this.containsVertex(vertex2)) {
|
||||
this.adjacencyMap[vertex1].push(vertex2)
|
||||
this.adjacencyMap[vertex2].push(vertex1)
|
||||
}
|
||||
}
|
||||
|
||||
printGraph (output = value => console.log(value)) {
|
||||
printGraph(output = (value) => console.log(value)) {
|
||||
const keys = Object.keys(this.adjacencyMap)
|
||||
for (const i of keys) {
|
||||
const values = this.adjacencyMap[i]
|
||||
@ -34,13 +34,14 @@ class Graph {
|
||||
* Prints the Breadth first traversal of the graph from source.
|
||||
* @param {number} source The source vertex to start BFS.
|
||||
*/
|
||||
bfs (source, output = value => console.log(value)) {
|
||||
bfs(source, output = (value) => console.log(value)) {
|
||||
const queue = [[source, 0]] // level of source is 0
|
||||
const visited = new Set()
|
||||
|
||||
while (queue.length) {
|
||||
const [node, level] = queue.shift() // remove the front of the queue
|
||||
if (visited.has(node)) { // visited
|
||||
if (visited.has(node)) {
|
||||
// visited
|
||||
continue
|
||||
}
|
||||
|
||||
@ -56,8 +57,9 @@ class Graph {
|
||||
* Prints the Depth first traversal of the graph from source.
|
||||
* @param {number} source The source vertex to start DFS.
|
||||
*/
|
||||
dfs (source, visited = new Set(), output = value => console.log(value)) {
|
||||
if (visited.has(source)) { // visited
|
||||
dfs(source, visited = new Set(), output = (value) => console.log(value)) {
|
||||
if (visited.has(source)) {
|
||||
// visited
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
class Graph {
|
||||
// defining vertex array and
|
||||
// adjacent list
|
||||
constructor (noOfVertices) {
|
||||
constructor(noOfVertices) {
|
||||
this.noOfVertices = noOfVertices
|
||||
this.AdjList = new Map()
|
||||
}
|
||||
@ -17,7 +17,7 @@ class Graph {
|
||||
// dfs(v)
|
||||
|
||||
// add vertex to the graph
|
||||
addVertex (v) {
|
||||
addVertex(v) {
|
||||
// initialize the adjacent list with a
|
||||
// null array
|
||||
|
||||
@ -25,7 +25,7 @@ class Graph {
|
||||
}
|
||||
|
||||
// add edge to the graph
|
||||
addEdge (v, w) {
|
||||
addEdge(v, w) {
|
||||
// get the list for vertex v and put the
|
||||
// vertex w denoting edge between v and w
|
||||
this.AdjList.get(v).push(w)
|
||||
@ -36,7 +36,7 @@ class Graph {
|
||||
}
|
||||
|
||||
// Prints the vertex and adjacency list
|
||||
printGraph (output = value => console.log(value)) {
|
||||
printGraph(output = (value) => console.log(value)) {
|
||||
// get all the vertices
|
||||
const getKeys = this.AdjList.keys()
|
||||
|
||||
|
@ -1,18 +1,18 @@
|
||||
class Graph {
|
||||
constructor () {
|
||||
constructor() {
|
||||
this.adjacencyObject = {}
|
||||
}
|
||||
|
||||
addVertex (vertex) {
|
||||
addVertex(vertex) {
|
||||
if (!this.adjacencyObject[vertex]) this.adjacencyObject[vertex] = []
|
||||
}
|
||||
|
||||
addEdge (vertex1, vertex2) {
|
||||
addEdge(vertex1, vertex2) {
|
||||
this.adjacencyObject[vertex1].push(vertex2)
|
||||
this.adjacencyObject[vertex2].push(vertex1)
|
||||
}
|
||||
|
||||
removeEdge (vertex1, vertex2) {
|
||||
removeEdge(vertex1, vertex2) {
|
||||
this.adjacencyObject[vertex1] = this.adjacencyObject[vertex1].filter(
|
||||
(v) => v !== vertex2
|
||||
)
|
||||
@ -21,7 +21,7 @@ class Graph {
|
||||
)
|
||||
}
|
||||
|
||||
removeVertex (vertex) {
|
||||
removeVertex(vertex) {
|
||||
while (this.adjacencyObject[vertex].length) {
|
||||
const adjacentVertex = this.adjacencyObject[vertex].pop()
|
||||
this.removeEdge(vertex, adjacentVertex)
|
||||
@ -31,14 +31,14 @@ class Graph {
|
||||
/**
|
||||
* Return DFS (Depth First Search) List Using Recursive Method
|
||||
*/
|
||||
DFS (start) {
|
||||
DFS(start) {
|
||||
if (!start) return null
|
||||
|
||||
const result = []
|
||||
const visited = {}
|
||||
const adjacencyObject = this.adjacencyObject
|
||||
|
||||
function dfs (vertex) {
|
||||
function dfs(vertex) {
|
||||
if (!vertex) return null
|
||||
visited[vertex] = true
|
||||
result.push(vertex)
|
||||
@ -56,7 +56,7 @@ class Graph {
|
||||
/**
|
||||
* Return DFS(Depth First Search) List Using Iteration
|
||||
*/
|
||||
DFSIterative (start) {
|
||||
DFSIterative(start) {
|
||||
if (!start) return null
|
||||
|
||||
const stack = [start]
|
||||
@ -80,7 +80,7 @@ class Graph {
|
||||
return result
|
||||
}
|
||||
|
||||
BFS (start) {
|
||||
BFS(start) {
|
||||
if (!start) return null
|
||||
|
||||
const queue = [start]
|
||||
|
@ -18,7 +18,7 @@ describe('Test Graph2', () => {
|
||||
graph.addEdge('C', 'F')
|
||||
|
||||
it('Check adjacency lists', () => {
|
||||
const mockFn = jest.fn()
|
||||
const mockFn = vi.fn()
|
||||
graph.printGraph(mockFn)
|
||||
|
||||
// Expect one call per vertex
|
||||
|
@ -19,12 +19,12 @@
|
||||
*/
|
||||
|
||||
// Priority Queue Helper functions
|
||||
const getParentPosition = position => Math.floor((position - 1) / 2)
|
||||
const getChildrenPositions = position => [2 * position + 1, 2 * position + 2]
|
||||
const getParentPosition = (position) => Math.floor((position - 1) / 2)
|
||||
const getChildrenPositions = (position) => [2 * position + 1, 2 * position + 2]
|
||||
|
||||
class KeyPriorityQueue {
|
||||
// Priority Queue class using Minimum Binary Heap
|
||||
constructor () {
|
||||
constructor() {
|
||||
this._heap = []
|
||||
this.priorities = new Map()
|
||||
}
|
||||
@ -33,7 +33,7 @@ class KeyPriorityQueue {
|
||||
* Checks if the heap is empty
|
||||
* @returns boolean
|
||||
*/
|
||||
isEmpty () {
|
||||
isEmpty() {
|
||||
return this._heap.length === 0
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ class KeyPriorityQueue {
|
||||
* @param {*} key
|
||||
* @param {number} priority
|
||||
*/
|
||||
push (key, priority) {
|
||||
push(key, priority) {
|
||||
this._heap.push(key)
|
||||
this.priorities.set(key, priority)
|
||||
this._shiftUp(this._heap.length - 1)
|
||||
@ -52,7 +52,7 @@ class KeyPriorityQueue {
|
||||
* Removes the element with least priority
|
||||
* @returns the key of the element with least priority
|
||||
*/
|
||||
pop () {
|
||||
pop() {
|
||||
this._swap(0, this._heap.length - 1)
|
||||
const key = this._heap.pop()
|
||||
this.priorities.delete(key)
|
||||
@ -65,7 +65,7 @@ class KeyPriorityQueue {
|
||||
* @param {*} key
|
||||
* @returns boolean
|
||||
*/
|
||||
contains (key) {
|
||||
contains(key) {
|
||||
return this.priorities.has(key)
|
||||
}
|
||||
|
||||
@ -75,7 +75,7 @@ class KeyPriorityQueue {
|
||||
* @param {*} key the element to change
|
||||
* @param {number} priority new priority of the element
|
||||
*/
|
||||
update (key, priority) {
|
||||
update(key, priority) {
|
||||
const currPos = this._heap.indexOf(key)
|
||||
// if the key does not exist yet, add it
|
||||
if (currPos === -1) return this.push(key, priority)
|
||||
@ -95,13 +95,14 @@ class KeyPriorityQueue {
|
||||
}
|
||||
}
|
||||
|
||||
_getPriorityOrInfinite (position) {
|
||||
_getPriorityOrInfinite(position) {
|
||||
// Helper function, returns priority of the node, or Infinite if no node corresponds to this position
|
||||
if (position >= 0 && position < this._heap.length) return this.priorities.get(this._heap[position])
|
||||
if (position >= 0 && position < this._heap.length)
|
||||
return this.priorities.get(this._heap[position])
|
||||
else return Infinity
|
||||
}
|
||||
|
||||
_shiftUp (position) {
|
||||
_shiftUp(position) {
|
||||
// Helper function to shift up a node to proper position (equivalent to bubbleUp)
|
||||
let currPos = position
|
||||
let parentPos = getParentPosition(currPos)
|
||||
@ -117,7 +118,7 @@ class KeyPriorityQueue {
|
||||
}
|
||||
}
|
||||
|
||||
_shiftDown (position) {
|
||||
_shiftDown(position) {
|
||||
// Helper function to shift down a node to proper position (equivalent to bubbleDown)
|
||||
let currPos = position
|
||||
let [child1Pos, child2Pos] = getChildrenPositions(currPos)
|
||||
@ -137,16 +138,19 @@ class KeyPriorityQueue {
|
||||
this._swap(child2Pos, currPos)
|
||||
currPos = child2Pos
|
||||
}
|
||||
[child1Pos, child2Pos] = getChildrenPositions(currPos)
|
||||
;[child1Pos, child2Pos] = getChildrenPositions(currPos)
|
||||
child1Priority = this._getPriorityOrInfinite(child1Pos)
|
||||
child2Priority = this._getPriorityOrInfinite(child2Pos)
|
||||
currPriority = this._getPriorityOrInfinite(currPos)
|
||||
}
|
||||
}
|
||||
|
||||
_swap (position1, position2) {
|
||||
_swap(position1, position2) {
|
||||
// Helper function to swap 2 nodes
|
||||
[this._heap[position1], this._heap[position2]] = [this._heap[position2], this._heap[position1]]
|
||||
;[this._heap[position1], this._heap[position2]] = [
|
||||
this._heap[position2],
|
||||
this._heap[position1]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,25 +4,25 @@
|
||||
*/
|
||||
|
||||
class BinaryHeap {
|
||||
constructor () {
|
||||
constructor() {
|
||||
this.heap = []
|
||||
}
|
||||
|
||||
insert (value) {
|
||||
insert(value) {
|
||||
this.heap.push(value)
|
||||
this.heapify()
|
||||
}
|
||||
|
||||
size () {
|
||||
size() {
|
||||
return this.heap.length
|
||||
}
|
||||
|
||||
empty () {
|
||||
empty() {
|
||||
return this.size() === 0
|
||||
}
|
||||
|
||||
// using iterative approach to reorder the heap after insertion
|
||||
heapify () {
|
||||
heapify() {
|
||||
let index = this.size() - 1
|
||||
|
||||
while (index > 0) {
|
||||
@ -38,7 +38,7 @@ class BinaryHeap {
|
||||
}
|
||||
|
||||
// Extracting the maximum element from the Heap
|
||||
extractMax () {
|
||||
extractMax() {
|
||||
const max = this.heap[0]
|
||||
const tmp = this.heap.pop()
|
||||
if (!this.empty()) {
|
||||
@ -49,7 +49,7 @@ class BinaryHeap {
|
||||
}
|
||||
|
||||
// To restore the balance of the heap after extraction.
|
||||
sinkDown (index) {
|
||||
sinkDown(index) {
|
||||
const left = 2 * index + 1
|
||||
const right = 2 * index + 2
|
||||
let largest = index
|
||||
|
@ -19,15 +19,15 @@
|
||||
*/
|
||||
|
||||
class MinHeap {
|
||||
constructor (array) {
|
||||
constructor(array) {
|
||||
this.heap = this.initializeHeap(array)
|
||||
}
|
||||
|
||||
/**
|
||||
* startingParent represents the parent of the last index (=== array.length-1)
|
||||
* and iterates towards 0 with all index values below sorted to meet heap conditions
|
||||
*/
|
||||
initializeHeap (array) {
|
||||
*/
|
||||
initializeHeap(array) {
|
||||
const startingParent = Math.floor((array.length - 2) / 2)
|
||||
|
||||
for (let currIdx = startingParent; currIdx >= 0; currIdx--) {
|
||||
@ -52,15 +52,16 @@ class MinHeap {
|
||||
* update currIdx and recalculate the new childOneIdx to check heap conditions again.
|
||||
*
|
||||
* if there is no swap, it means the children indices and the parent index satisfy heap conditions and can exit the function.
|
||||
*/
|
||||
sinkDown (currIdx, endIdx, heap) {
|
||||
*/
|
||||
sinkDown(currIdx, endIdx, heap) {
|
||||
let childOneIdx = currIdx * 2 + 1
|
||||
|
||||
while (childOneIdx <= endIdx) {
|
||||
const childTwoIdx = childOneIdx + 1 <= endIdx ? childOneIdx + 1 : -1
|
||||
const swapIdx = childTwoIdx !== -1 && heap[childTwoIdx] < heap[childOneIdx]
|
||||
? childTwoIdx
|
||||
: childOneIdx
|
||||
const swapIdx =
|
||||
childTwoIdx !== -1 && heap[childTwoIdx] < heap[childOneIdx]
|
||||
? childTwoIdx
|
||||
: childOneIdx
|
||||
|
||||
if (heap[swapIdx] < heap[currIdx]) {
|
||||
this.swap(currIdx, swapIdx, heap)
|
||||
@ -79,8 +80,8 @@ class MinHeap {
|
||||
* update currIdx and recalculate the new parentIdx to check heap condition again.
|
||||
*
|
||||
* iteration does not end while a valid currIdx has a value smaller than its parentIdx's value
|
||||
*/
|
||||
bubbleUp (currIdx) {
|
||||
*/
|
||||
bubbleUp(currIdx) {
|
||||
let parentIdx = Math.floor((currIdx - 1) / 2)
|
||||
|
||||
while (currIdx > 0 && this.heap[currIdx] < this.heap[parentIdx]) {
|
||||
@ -90,7 +91,7 @@ class MinHeap {
|
||||
}
|
||||
}
|
||||
|
||||
peek () {
|
||||
peek() {
|
||||
return this.heap[0]
|
||||
}
|
||||
|
||||
@ -101,8 +102,8 @@ class MinHeap {
|
||||
* the resulting min heap value now resides at heap[heap.length-1] which is popped and later returned.
|
||||
*
|
||||
* the remaining values in the heap are re-sorted
|
||||
*/
|
||||
extractMin () {
|
||||
*/
|
||||
extractMin() {
|
||||
this.swap(0, this.heap.length - 1, this.heap)
|
||||
const min = this.heap.pop()
|
||||
this.sinkDown(0, this.heap.length - 1, this.heap)
|
||||
@ -110,13 +111,13 @@ class MinHeap {
|
||||
}
|
||||
|
||||
// a new value is pushed to the end of the heap and sorted up
|
||||
insert (value) {
|
||||
insert(value) {
|
||||
this.heap.push(value)
|
||||
this.bubbleUp(this.heap.length - 1)
|
||||
}
|
||||
|
||||
// index-swapping helper method
|
||||
swap (idx1, idx2, heap) {
|
||||
swap(idx1, idx2, heap) {
|
||||
const temp = heap[idx1]
|
||||
heap[idx1] = heap[idx2]
|
||||
heap[idx2] = temp
|
||||
|
@ -1,18 +1,18 @@
|
||||
/* Minimum Priority Queue
|
||||
* It is a part of heap data structure
|
||||
* A heap is a specific tree based data structure
|
||||
* in which all the nodes of tree are in a specific order.
|
||||
* that is the children are arranged in some
|
||||
* respect of their parents, can either be greater
|
||||
* or less than the parent. This makes it a min priority queue
|
||||
* or max priority queue.
|
||||
*/
|
||||
* It is a part of heap data structure
|
||||
* A heap is a specific tree based data structure
|
||||
* in which all the nodes of tree are in a specific order.
|
||||
* that is the children are arranged in some
|
||||
* respect of their parents, can either be greater
|
||||
* or less than the parent. This makes it a min priority queue
|
||||
* or max priority queue.
|
||||
*/
|
||||
|
||||
// Functions: insert, delete, peek, isEmpty, print, heapSort, sink
|
||||
|
||||
class MinPriorityQueue {
|
||||
// calls the constructor and initializes the capacity
|
||||
constructor (c) {
|
||||
constructor(c) {
|
||||
this.heap = []
|
||||
this.capacity = c
|
||||
this.size = 0
|
||||
@ -20,7 +20,7 @@ class MinPriorityQueue {
|
||||
|
||||
// inserts the key at the end and rearranges it
|
||||
// so that the binary heap is in appropriate order
|
||||
insert (key) {
|
||||
insert(key) {
|
||||
if (this.isFull()) return
|
||||
this.heap[this.size + 1] = key
|
||||
let k = this.size + 1
|
||||
@ -36,33 +36,36 @@ class MinPriorityQueue {
|
||||
}
|
||||
|
||||
// returns the highest priority value
|
||||
peek () {
|
||||
peek() {
|
||||
return this.heap[1]
|
||||
}
|
||||
|
||||
// returns boolean value whether the heap is empty or not
|
||||
isEmpty () {
|
||||
isEmpty() {
|
||||
return this.size === 0
|
||||
}
|
||||
|
||||
// returns boolean value whether the heap is full or not
|
||||
isFull () {
|
||||
isFull() {
|
||||
return this.size === this.capacity
|
||||
}
|
||||
|
||||
// prints the heap
|
||||
print (output = value => console.log(value)) {
|
||||
print(output = (value) => console.log(value)) {
|
||||
output(this.heap.slice(1))
|
||||
}
|
||||
|
||||
// heap reverse can be done by performing swapping the first
|
||||
// element with the last, removing the last element to
|
||||
// new array and calling sink function.
|
||||
heapReverse () {
|
||||
heapReverse() {
|
||||
const heapSort = []
|
||||
while (this.size > 0) {
|
||||
// swap first element with last element
|
||||
[this.heap[1], this.heap[this.size]] = [this.heap[this.size], this.heap[1]]
|
||||
;[this.heap[1], this.heap[this.size]] = [
|
||||
this.heap[this.size],
|
||||
this.heap[1]
|
||||
]
|
||||
heapSort.push(this.heap.pop())
|
||||
this.size--
|
||||
this.sink()
|
||||
@ -74,7 +77,7 @@ class MinPriorityQueue {
|
||||
}
|
||||
|
||||
// this function reorders the heap after every delete function
|
||||
sink () {
|
||||
sink() {
|
||||
let k = 1
|
||||
while (2 * k <= this.size || 2 * k + 1 <= this.size) {
|
||||
let minIndex
|
||||
@ -92,8 +95,7 @@ class MinPriorityQueue {
|
||||
this.heap[k] > this.heap[2 * k] ||
|
||||
this.heap[k] > this.heap[2 * k + 1]
|
||||
) {
|
||||
minIndex =
|
||||
this.heap[2 * k] < this.heap[2 * k + 1] ? 2 * k : 2 * k + 1
|
||||
minIndex = this.heap[2 * k] < this.heap[2 * k + 1] ? 2 * k : 2 * k + 1
|
||||
} else {
|
||||
minIndex = k
|
||||
}
|
||||
@ -107,7 +109,7 @@ class MinPriorityQueue {
|
||||
|
||||
// deletes the highest priority value from the heap. The last
|
||||
// element goes to ahead to first position and reorder heap
|
||||
delete () {
|
||||
delete() {
|
||||
// checks empty and one element array conditions
|
||||
if (this.isEmpty()) return
|
||||
if (this.size === 1) {
|
||||
|
@ -9,7 +9,9 @@ describe('MinHeap', () => {
|
||||
})
|
||||
|
||||
it('should initialize a heap from an input array', () => {
|
||||
expect(heap).toEqual({ 'heap': [1, 4, 2, 7, 16, 10, 39, 23, 9, 43, 85, 42, 51] }) // eslint-disable-line
|
||||
expect(heap).toEqual({
|
||||
heap: [1, 4, 2, 7, 16, 10, 39, 23, 9, 43, 85, 42, 51]
|
||||
}) // eslint-disable-line
|
||||
})
|
||||
|
||||
it('should show the top value in the heap', () => {
|
||||
@ -22,12 +24,14 @@ describe('MinHeap', () => {
|
||||
const minValue = heap.extractMin()
|
||||
|
||||
expect(minValue).toEqual(1)
|
||||
expect(heap).toEqual({ 'heap': [2, 4, 10, 7, 16, 42, 39, 23, 9, 43, 85, 51] }) // eslint-disable-line
|
||||
expect(heap).toEqual({ heap: [2, 4, 10, 7, 16, 42, 39, 23, 9, 43, 85, 51] }) // eslint-disable-line
|
||||
})
|
||||
|
||||
it('should insert a new value and sort until it meets heap conditions', () => {
|
||||
heap.insert(15)
|
||||
|
||||
expect(heap).toEqual({ 'heap': [2, 4, 10, 7, 16, 15, 39, 23, 9, 43, 85, 51, 42] }) // eslint-disable-line
|
||||
expect(heap).toEqual({
|
||||
heap: [2, 4, 10, 7, 16, 15, 39, 23, 9, 43, 85, 51, 42]
|
||||
}) // eslint-disable-line
|
||||
})
|
||||
})
|
||||
|
@ -7,11 +7,11 @@ describe('MinPriorityQueue', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
queue = new MinPriorityQueue(capacity)
|
||||
values.forEach(v => queue.insert(v))
|
||||
values.forEach((v) => queue.insert(v))
|
||||
})
|
||||
|
||||
it('Check heap ordering', () => {
|
||||
const mockFn = jest.fn()
|
||||
const mockFn = vi.fn()
|
||||
queue.print(mockFn)
|
||||
|
||||
expect(mockFn.mock.calls.length).toBe(1) // Expect one call
|
||||
@ -24,7 +24,7 @@ describe('MinPriorityQueue', () => {
|
||||
|
||||
it('heapSort() expected to reverse the heap ordering', () => {
|
||||
queue.heapReverse()
|
||||
const mockFn = jest.fn()
|
||||
const mockFn = vi.fn()
|
||||
queue.print(mockFn)
|
||||
|
||||
expect(mockFn.mock.calls.length).toBe(1)
|
||||
|
@ -14,11 +14,11 @@ Link for the Problem: https://leetcode.com/problems/add-two-numbers/
|
||||
*/
|
||||
|
||||
class AddTwoNumbers {
|
||||
constructor () {
|
||||
constructor() {
|
||||
this.dummyNode = new Node(0)
|
||||
}
|
||||
|
||||
solution (firstList, secondList) {
|
||||
solution(firstList, secondList) {
|
||||
let firstRunner = firstList
|
||||
let secondRunner = secondList
|
||||
let tail = this.dummyNode
|
||||
@ -44,7 +44,7 @@ class AddTwoNumbers {
|
||||
return this.dummyNode.next
|
||||
}
|
||||
|
||||
solutionToArray () {
|
||||
solutionToArray() {
|
||||
const list = []
|
||||
let currentNode = this.dummyNode.next
|
||||
while (currentNode) {
|
||||
|
@ -3,18 +3,22 @@
|
||||
* https://en.wikipedia.org/wiki/Cycle_detection
|
||||
*/
|
||||
|
||||
function detectCycle (head) {
|
||||
function detectCycle(head) {
|
||||
/*
|
||||
Problem Statement:
|
||||
Given head, the head of a linked list, determine if the linked list has a cycle in it.
|
||||
Link for the Problem: https://leetcode.com/problems/linked-list-cycle/
|
||||
*/
|
||||
if (!head) { return false }
|
||||
if (!head) {
|
||||
return false
|
||||
}
|
||||
|
||||
let slow = head
|
||||
let fast = head.next
|
||||
while (fast && fast.next) {
|
||||
if (fast === slow) { return true }
|
||||
if (fast === slow) {
|
||||
return true
|
||||
}
|
||||
fast = fast.next.next
|
||||
slow = slow.next
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
class Node {
|
||||
constructor (element) {
|
||||
constructor(element) {
|
||||
this.element = element
|
||||
this.next = null
|
||||
this.prev = null
|
||||
@ -7,14 +7,14 @@ class Node {
|
||||
}
|
||||
|
||||
class DoubleLinkedList {
|
||||
constructor () {
|
||||
constructor() {
|
||||
this.length = 0
|
||||
this.head = null
|
||||
this.tail = null
|
||||
}
|
||||
|
||||
// Add new element
|
||||
append (element) {
|
||||
append(element) {
|
||||
const node = new Node(element)
|
||||
|
||||
if (!this.head) {
|
||||
@ -30,7 +30,7 @@ class DoubleLinkedList {
|
||||
}
|
||||
|
||||
// Add element
|
||||
insert (position, element) {
|
||||
insert(position, element) {
|
||||
// Check of out-of-bound values
|
||||
if (position >= 0 && position <= this.length) {
|
||||
const node = new Node(element)
|
||||
@ -74,7 +74,7 @@ class DoubleLinkedList {
|
||||
}
|
||||
|
||||
// Remove element at any position
|
||||
removeAt (position) {
|
||||
removeAt(position) {
|
||||
// look for out-of-bounds value
|
||||
if (position > -1 && position < this.length) {
|
||||
let current = this.head
|
||||
@ -114,7 +114,7 @@ class DoubleLinkedList {
|
||||
}
|
||||
|
||||
// Get the indexOf item
|
||||
indexOf (elm) {
|
||||
indexOf(elm) {
|
||||
let current = this.head
|
||||
let index = -1
|
||||
|
||||
@ -133,27 +133,27 @@ class DoubleLinkedList {
|
||||
}
|
||||
|
||||
// Find the item in the list
|
||||
isPresent (elm) {
|
||||
isPresent(elm) {
|
||||
return this.indexOf(elm) !== -1
|
||||
}
|
||||
|
||||
// Delete an item from the list
|
||||
delete (elm) {
|
||||
delete(elm) {
|
||||
return this.removeAt(this.indexOf(elm))
|
||||
}
|
||||
|
||||
// Delete first item from the list
|
||||
deleteHead () {
|
||||
deleteHead() {
|
||||
this.removeAt(0)
|
||||
}
|
||||
|
||||
// Delete last item from the list
|
||||
deleteTail () {
|
||||
deleteTail() {
|
||||
this.removeAt(this.length - 1)
|
||||
}
|
||||
|
||||
// Print item of the string
|
||||
toString () {
|
||||
toString() {
|
||||
let current = this.head
|
||||
let string = ''
|
||||
|
||||
@ -166,7 +166,7 @@ class DoubleLinkedList {
|
||||
}
|
||||
|
||||
// Convert list to array
|
||||
toArray () {
|
||||
toArray() {
|
||||
const arr = []
|
||||
let current = this.head
|
||||
|
||||
@ -179,31 +179,31 @@ class DoubleLinkedList {
|
||||
}
|
||||
|
||||
// Check if list is empty
|
||||
isEmpty () {
|
||||
isEmpty() {
|
||||
return this.length === 0
|
||||
}
|
||||
|
||||
// Get the size of the list
|
||||
size () {
|
||||
size() {
|
||||
return this.length
|
||||
}
|
||||
|
||||
// Get the this.head
|
||||
getHead () {
|
||||
getHead() {
|
||||
return this.head
|
||||
}
|
||||
|
||||
// Get the this.tail
|
||||
getTail () {
|
||||
getTail() {
|
||||
return this.tail
|
||||
}
|
||||
|
||||
// Method to iterate over the LinkedList
|
||||
iterator () {
|
||||
iterator() {
|
||||
let currentNode = this.getHead()
|
||||
if (currentNode === null) return -1
|
||||
|
||||
const iterate = function * () {
|
||||
const iterate = function* () {
|
||||
while (currentNode) {
|
||||
yield currentNode.element
|
||||
currentNode = currentNode.next
|
||||
@ -214,7 +214,7 @@ class DoubleLinkedList {
|
||||
|
||||
// Method to log the LinkedList, for debugging
|
||||
// it' a circular structure, so can't use stringify to debug the whole structure
|
||||
log () {
|
||||
log() {
|
||||
let currentNode = this.getHead()
|
||||
while (currentNode) {
|
||||
console.log(currentNode.element)
|
||||
|
@ -1,7 +1,7 @@
|
||||
/** A LinkedList based solution to reverse a number
|
||||
Problem Statement: Given a number such that each of its digit is stored in a singly linked list. Reverse the linked list and return the head of the linked list Link for the Problem: https://leetcode.com/problems/reverse-linked-list/ */
|
||||
class ReverseSinglyLinkedList {
|
||||
solution (head) {
|
||||
solution(head) {
|
||||
let prev = null
|
||||
let next = null
|
||||
while (head) {
|
||||
@ -11,6 +11,6 @@ class ReverseSinglyLinkedList {
|
||||
head = next
|
||||
}
|
||||
return prev
|
||||
};
|
||||
}
|
||||
}
|
||||
export { ReverseSinglyLinkedList }
|
||||
|
@ -2,7 +2,7 @@
|
||||
import { Node } from './SinglyLinkedList.js'
|
||||
|
||||
class SinglyCircularLinkedList {
|
||||
constructor () {
|
||||
constructor() {
|
||||
this.headNode = null
|
||||
this.length = 0
|
||||
}
|
||||
@ -15,12 +15,12 @@ class SinglyCircularLinkedList {
|
||||
isEmpty = () => this.length === 0
|
||||
|
||||
// initiate the node and index
|
||||
initiateNodeAndIndex () {
|
||||
initiateNodeAndIndex() {
|
||||
return { currentNode: this.headNode, currentIndex: 0 }
|
||||
}
|
||||
|
||||
// get the data specific to an index
|
||||
getElementAt (index) {
|
||||
getElementAt(index) {
|
||||
if (this.length !== 0 && index >= 0 && index <= this.length) {
|
||||
let { currentNode } = this.initiateNodeAndIndex()
|
||||
for (let i = 0; i < index && currentNode !== null; i++) {
|
||||
@ -32,7 +32,7 @@ class SinglyCircularLinkedList {
|
||||
}
|
||||
|
||||
// Add the element in the first position
|
||||
addAtFirst (data) {
|
||||
addAtFirst(data) {
|
||||
const node = new Node(data)
|
||||
node.next = this.headNode
|
||||
this.headNode = node
|
||||
@ -41,8 +41,10 @@ class SinglyCircularLinkedList {
|
||||
}
|
||||
|
||||
// Add any data to the end of the linkedList
|
||||
add (data) {
|
||||
if (!this.headNode) { return this.addAtFirst(data) }
|
||||
add(data) {
|
||||
if (!this.headNode) {
|
||||
return this.addAtFirst(data)
|
||||
}
|
||||
const node = new Node(data)
|
||||
// Getting the last node
|
||||
const currentNode = this.getElementAt(this.length - 1)
|
||||
@ -53,10 +55,11 @@ class SinglyCircularLinkedList {
|
||||
}
|
||||
|
||||
// insert data at a specific position
|
||||
insertAt (index, data) {
|
||||
insertAt(index, data) {
|
||||
if (index === 0) return this.addAtFirst(data)
|
||||
if (index === this.length) return this.add(data)
|
||||
if (index < 0 || index > this.length) throw new RangeError(`Index is out of range max ${this.length}`)
|
||||
if (index < 0 || index > this.length)
|
||||
throw new RangeError(`Index is out of range max ${this.length}`)
|
||||
const node = new Node(data)
|
||||
const previousNode = this.getElementAt(index - 1)
|
||||
node.next = previousNode.next
|
||||
@ -66,7 +69,7 @@ class SinglyCircularLinkedList {
|
||||
}
|
||||
|
||||
// find the first index of the data
|
||||
indexOf (data) {
|
||||
indexOf(data) {
|
||||
let { currentNode } = this.initiateNodeAndIndex()
|
||||
// initializing currentIndex as -1
|
||||
let currentIndex = -1
|
||||
@ -81,7 +84,7 @@ class SinglyCircularLinkedList {
|
||||
}
|
||||
|
||||
// remove the data from the end of the list
|
||||
remove () {
|
||||
remove() {
|
||||
if (this.isEmpty()) return null
|
||||
const secondLastNode = this.getElementAt(this.length - 2)
|
||||
const removedNode = secondLastNode.next
|
||||
@ -91,7 +94,7 @@ class SinglyCircularLinkedList {
|
||||
}
|
||||
|
||||
// remove the data from the first of the list
|
||||
removeFirst () {
|
||||
removeFirst() {
|
||||
if (this.isEmpty()) return null
|
||||
const removedNode = this.headNode
|
||||
if (this.length === 1) {
|
||||
@ -106,7 +109,7 @@ class SinglyCircularLinkedList {
|
||||
}
|
||||
|
||||
// remove the data from the index
|
||||
removeAt (index) {
|
||||
removeAt(index) {
|
||||
if (this.isEmpty()) return null
|
||||
if (index === 0) return this.removeFirst()
|
||||
if (index === this.length) return this.remove()
|
||||
@ -119,14 +122,14 @@ class SinglyCircularLinkedList {
|
||||
}
|
||||
|
||||
// remove if the data is present
|
||||
removeData (data) {
|
||||
removeData(data) {
|
||||
if (this.isEmpty()) return null
|
||||
const index = this.indexOf(data)
|
||||
return this.removeAt(index)
|
||||
}
|
||||
|
||||
// logs the data
|
||||
printData (output = value => console.log(value)) {
|
||||
printData(output = (value) => console.log(value)) {
|
||||
let { currentIndex, currentNode } = this.initiateNodeAndIndex()
|
||||
|
||||
while (currentNode !== null && currentIndex < this.length) {
|
||||
@ -137,7 +140,7 @@ class SinglyCircularLinkedList {
|
||||
}
|
||||
|
||||
// get the data from the linkedList
|
||||
get () {
|
||||
get() {
|
||||
let { currentIndex, currentNode } = this.initiateNodeAndIndex()
|
||||
const list = []
|
||||
while (currentNode !== null && currentIndex < this.length) {
|
||||
@ -148,7 +151,7 @@ class SinglyCircularLinkedList {
|
||||
return list
|
||||
}
|
||||
|
||||
clear () {
|
||||
clear() {
|
||||
this.headNode = null
|
||||
this.length = 0
|
||||
}
|
||||
|
@ -9,14 +9,14 @@
|
||||
// Methods - size, head, addLast, addFirst, addAt, removeFirst, removeLast, remove, removeAt, indexOf, isEmpty, elementAt, findMiddle, get, clean, rotateListRight
|
||||
|
||||
class Node {
|
||||
constructor (data) {
|
||||
constructor(data) {
|
||||
this.data = data
|
||||
this.next = null
|
||||
}
|
||||
}
|
||||
|
||||
class LinkedList {
|
||||
constructor (listOfValues) {
|
||||
constructor(listOfValues) {
|
||||
this.headNode = null
|
||||
this.tailNode = null
|
||||
this.length = 0
|
||||
@ -29,32 +29,32 @@ class LinkedList {
|
||||
}
|
||||
|
||||
// initiates the currentNode and currentIndex and return as an object
|
||||
initiateNodeAndIndex () {
|
||||
initiateNodeAndIndex() {
|
||||
return { currentNode: this.headNode, currentIndex: 0 }
|
||||
}
|
||||
|
||||
// Returns length
|
||||
size () {
|
||||
size() {
|
||||
return this.length
|
||||
}
|
||||
|
||||
// Returns the head
|
||||
head () {
|
||||
head() {
|
||||
return this.headNode?.data ?? null
|
||||
}
|
||||
|
||||
// Returns the tail
|
||||
tail () {
|
||||
tail() {
|
||||
return this.tailNode?.data ?? null
|
||||
}
|
||||
|
||||
// Return if the list is empty
|
||||
isEmpty () {
|
||||
isEmpty() {
|
||||
return this.length === 0
|
||||
}
|
||||
|
||||
// add a node at last it to linklist
|
||||
addLast (element) {
|
||||
addLast(element) {
|
||||
// Check if its the first element
|
||||
if (this.headNode === null) {
|
||||
return this.addFirst(element)
|
||||
@ -68,7 +68,7 @@ class LinkedList {
|
||||
}
|
||||
|
||||
// add a node at first it to linklist
|
||||
addFirst (element) {
|
||||
addFirst(element) {
|
||||
const node = new Node(element)
|
||||
// Check if its the first element
|
||||
if (this.headNode === null) {
|
||||
@ -82,7 +82,7 @@ class LinkedList {
|
||||
}
|
||||
|
||||
// remove the first from the linklist
|
||||
removeFirst () {
|
||||
removeFirst() {
|
||||
// Check if head is null
|
||||
if (this.headNode === null) {
|
||||
return null
|
||||
@ -99,7 +99,7 @@ class LinkedList {
|
||||
}
|
||||
|
||||
// remove the last from the linklist
|
||||
removeLast () {
|
||||
removeLast() {
|
||||
if (this.isEmpty()) return null
|
||||
// Check if there is only one element
|
||||
if (this.length === 1) {
|
||||
@ -118,7 +118,7 @@ class LinkedList {
|
||||
}
|
||||
|
||||
// Removes the node with the value as param
|
||||
remove (element) {
|
||||
remove(element) {
|
||||
if (this.isEmpty()) return null
|
||||
let { currentNode } = this.initiateNodeAndIndex()
|
||||
let removedNode = null
|
||||
@ -144,7 +144,7 @@ class LinkedList {
|
||||
}
|
||||
|
||||
// Returns the index of the element passed as param otherwise -1
|
||||
indexOf (element) {
|
||||
indexOf(element) {
|
||||
if (this.isEmpty()) return -1
|
||||
let { currentNode, currentIndex } = this.initiateNodeAndIndex()
|
||||
while (currentNode) {
|
||||
@ -158,7 +158,7 @@ class LinkedList {
|
||||
}
|
||||
|
||||
// Returns the element at an index
|
||||
elementAt (index) {
|
||||
elementAt(index) {
|
||||
if (index >= this.length || index < 0) {
|
||||
throw new RangeError('Out of Range index')
|
||||
}
|
||||
@ -171,7 +171,7 @@ class LinkedList {
|
||||
}
|
||||
|
||||
// Adds the element at specified index
|
||||
addAt (index, element) {
|
||||
addAt(index, element) {
|
||||
// Check if index is out of bounds of list
|
||||
if (index > this.length || index < 0) {
|
||||
throw new RangeError('Out of Range index')
|
||||
@ -196,7 +196,7 @@ class LinkedList {
|
||||
}
|
||||
|
||||
// Removes the node at specified index
|
||||
removeAt (index) {
|
||||
removeAt(index) {
|
||||
// Check if index is present in list
|
||||
if (index < 0 || index >= this.length) {
|
||||
throw new RangeError('Out of Range index')
|
||||
@ -216,7 +216,7 @@ class LinkedList {
|
||||
}
|
||||
|
||||
// Returns a reference to middle node of linked list
|
||||
findMiddle () {
|
||||
findMiddle() {
|
||||
// If there are two middle nodes, return the second middle node.
|
||||
let fast = this.headNode
|
||||
let slow = this.headNode
|
||||
@ -229,14 +229,14 @@ class LinkedList {
|
||||
}
|
||||
|
||||
// make the linkedList Empty
|
||||
clean () {
|
||||
clean() {
|
||||
this.headNode = null
|
||||
this.tailNode = null
|
||||
this.length = 0
|
||||
}
|
||||
|
||||
// Method to get the LinkedList
|
||||
get () {
|
||||
get() {
|
||||
const list = []
|
||||
let { currentNode } = this.initiateNodeAndIndex()
|
||||
while (currentNode) {
|
||||
@ -247,7 +247,7 @@ class LinkedList {
|
||||
}
|
||||
|
||||
// Method for Rotating a List to the right by k places
|
||||
rotateListRight (k) {
|
||||
rotateListRight(k) {
|
||||
if (!this.headNode) return
|
||||
let current = this.headNode
|
||||
let tail = this.tailNode
|
||||
@ -268,11 +268,11 @@ class LinkedList {
|
||||
}
|
||||
|
||||
// Method to iterate over the LinkedList
|
||||
iterator () {
|
||||
iterator() {
|
||||
let { currentNode } = this.initiateNodeAndIndex()
|
||||
if (currentNode === null) return -1
|
||||
|
||||
const iterate = function * () {
|
||||
const iterate = function* () {
|
||||
while (currentNode) {
|
||||
yield currentNode.data
|
||||
currentNode = currentNode.next
|
||||
@ -282,12 +282,12 @@ class LinkedList {
|
||||
}
|
||||
|
||||
// Method to log the LinkedList
|
||||
log () {
|
||||
log() {
|
||||
console.log(JSON.stringify(this.headNode, null, 2))
|
||||
}
|
||||
|
||||
// Method to reverse the LinkedList
|
||||
reverse () {
|
||||
reverse() {
|
||||
let head = this.headNode
|
||||
let prev = null
|
||||
let next = null
|
||||
@ -299,7 +299,7 @@ class LinkedList {
|
||||
}
|
||||
this.tailNode = this.headNode
|
||||
this.headNode = prev
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export { Node, LinkedList }
|
||||
|
@ -1,147 +1,147 @@
|
||||
import { SinglyCircularLinkedList } from '../SinglyCircularLinkedList'
|
||||
|
||||
describe('SinglyCircularLinkedList', () => {
|
||||
let list
|
||||
beforeEach(() => {
|
||||
list = new SinglyCircularLinkedList()
|
||||
})
|
||||
it('Check get', () => {
|
||||
expect(list.get()).toEqual([])
|
||||
expect(list.add(1)).toEqual(1)
|
||||
expect(list.get()).toEqual([1])
|
||||
expect(list.add(5)).toEqual(2)
|
||||
expect(list.get()).toEqual([1, 5])
|
||||
})
|
||||
|
||||
it('Check size', () => {
|
||||
expect(list.size()).toEqual(0)
|
||||
expect(list.add(1)).toEqual(1)
|
||||
expect(list.add(1)).toEqual(2)
|
||||
expect(list.size()).toEqual(2)
|
||||
})
|
||||
|
||||
it('Check head', () => {
|
||||
expect(list.head()).toEqual(null)
|
||||
expect(list.add(1)).toEqual(1)
|
||||
expect(list.head()).toEqual(1)
|
||||
expect(list.add(1)).toEqual(2)
|
||||
expect(list.head()).toEqual(1)
|
||||
expect(list.addAtFirst(100)).toEqual(3)
|
||||
expect(list.head()).toEqual(100)
|
||||
expect(list.insertAt(0, 500)).toEqual(4)
|
||||
expect(list.head()).toEqual(500)
|
||||
list.clear()
|
||||
expect(list.head()).toEqual(null)
|
||||
})
|
||||
|
||||
it('Check isEmpty', () => {
|
||||
expect(list.isEmpty()).toEqual(true)
|
||||
expect(list.add(1)).toEqual(1)
|
||||
expect(list.add(1)).toEqual(2)
|
||||
expect(list.isEmpty()).toEqual(false)
|
||||
})
|
||||
|
||||
it('Check getElementAt', () => {
|
||||
list.add(100)
|
||||
list.add(200)
|
||||
list.add(300)
|
||||
list.add(500)
|
||||
list.add(900)
|
||||
|
||||
expect(list.getElementAt(1).data).toEqual(200)
|
||||
expect(list.getElementAt(3).data).toEqual(500)
|
||||
})
|
||||
|
||||
it('Check addAtFirst', () => {
|
||||
list.add(1)
|
||||
list.add(5)
|
||||
list.add(7)
|
||||
list.add(9)
|
||||
list.add(0)
|
||||
expect(list.get()).toEqual([1, 5, 7, 9, 0])
|
||||
list.addAtFirst(100)
|
||||
expect(list.get()).toEqual([100, 1, 5, 7, 9, 0])
|
||||
})
|
||||
|
||||
it('Check add', () => {
|
||||
list.add(1)
|
||||
list.add(5)
|
||||
list.add(7)
|
||||
list.add(9)
|
||||
list.add(0)
|
||||
expect(list.get()).toEqual([1, 5, 7, 9, 0])
|
||||
list.add(100)
|
||||
expect(list.get()).toEqual([1, 5, 7, 9, 0, 100])
|
||||
})
|
||||
|
||||
it('Check insertAt', () => {
|
||||
expect(list.insertAt(0, 100)).toEqual(1)
|
||||
expect(list.get()).toEqual([100])
|
||||
expect(list.insertAt(0, 200)).toEqual(2)
|
||||
expect(list.get()).toEqual([200, 100])
|
||||
expect(list.insertAt(2, 300)).toEqual(3)
|
||||
expect(list.get()).toEqual([200, 100, 300])
|
||||
})
|
||||
|
||||
it('Checks indexOf', () => {
|
||||
expect(list.indexOf(200)).toEqual(-1)
|
||||
list.add(100)
|
||||
list.add(200)
|
||||
list.add(300)
|
||||
list.add(500)
|
||||
list.add(900)
|
||||
expect(list.indexOf(200)).toEqual(1)
|
||||
})
|
||||
|
||||
it('Check remove', () => {
|
||||
expect(list.remove()).toEqual(null)
|
||||
list.add(100)
|
||||
list.add(200)
|
||||
list.add(300)
|
||||
list.add(500)
|
||||
list.add(900)
|
||||
expect(list.get()).toEqual([100, 200, 300, 500, 900])
|
||||
const removedData = list.remove()
|
||||
expect(removedData).toEqual(900)
|
||||
expect(list.get()).toEqual([100, 200, 300, 500])
|
||||
})
|
||||
|
||||
it('Check removeFirst', () => {
|
||||
expect(list.removeFirst()).toEqual(null)
|
||||
list.add(100)
|
||||
list.add(200)
|
||||
list.add(300)
|
||||
list.add(500)
|
||||
list.add(900)
|
||||
expect(list.get()).toEqual([100, 200, 300, 500, 900])
|
||||
const removedData = list.removeFirst()
|
||||
expect(removedData).toEqual(100)
|
||||
expect(list.get()).toEqual([200, 300, 500, 900])
|
||||
})
|
||||
|
||||
it('Check removeAt', () => {
|
||||
expect(list.removeAt(1)).toEqual(null)
|
||||
list.add(100)
|
||||
list.add(200)
|
||||
list.add(300)
|
||||
list.add(500)
|
||||
list.add(900)
|
||||
expect(list.get()).toEqual([100, 200, 300, 500, 900])
|
||||
const removedData = list.removeAt(2)
|
||||
expect(removedData).toEqual(300)
|
||||
expect(list.get()).toEqual([100, 200, 500, 900])
|
||||
})
|
||||
|
||||
it('Check removeData', () => {
|
||||
expect(list.removeData(100)).toEqual(null)
|
||||
list.add(100)
|
||||
list.add(200)
|
||||
list.add(300)
|
||||
list.add(500)
|
||||
list.add(900)
|
||||
expect(list.get()).toEqual([100, 200, 300, 500, 900])
|
||||
const removedData = list.removeData(200)
|
||||
expect(removedData).toEqual(200)
|
||||
expect(list.get()).toEqual([100, 300, 500, 900])
|
||||
})
|
||||
})
|
||||
import { SinglyCircularLinkedList } from '../SinglyCircularLinkedList'
|
||||
|
||||
describe('SinglyCircularLinkedList', () => {
|
||||
let list
|
||||
beforeEach(() => {
|
||||
list = new SinglyCircularLinkedList()
|
||||
})
|
||||
it('Check get', () => {
|
||||
expect(list.get()).toEqual([])
|
||||
expect(list.add(1)).toEqual(1)
|
||||
expect(list.get()).toEqual([1])
|
||||
expect(list.add(5)).toEqual(2)
|
||||
expect(list.get()).toEqual([1, 5])
|
||||
})
|
||||
|
||||
it('Check size', () => {
|
||||
expect(list.size()).toEqual(0)
|
||||
expect(list.add(1)).toEqual(1)
|
||||
expect(list.add(1)).toEqual(2)
|
||||
expect(list.size()).toEqual(2)
|
||||
})
|
||||
|
||||
it('Check head', () => {
|
||||
expect(list.head()).toEqual(null)
|
||||
expect(list.add(1)).toEqual(1)
|
||||
expect(list.head()).toEqual(1)
|
||||
expect(list.add(1)).toEqual(2)
|
||||
expect(list.head()).toEqual(1)
|
||||
expect(list.addAtFirst(100)).toEqual(3)
|
||||
expect(list.head()).toEqual(100)
|
||||
expect(list.insertAt(0, 500)).toEqual(4)
|
||||
expect(list.head()).toEqual(500)
|
||||
list.clear()
|
||||
expect(list.head()).toEqual(null)
|
||||
})
|
||||
|
||||
it('Check isEmpty', () => {
|
||||
expect(list.isEmpty()).toEqual(true)
|
||||
expect(list.add(1)).toEqual(1)
|
||||
expect(list.add(1)).toEqual(2)
|
||||
expect(list.isEmpty()).toEqual(false)
|
||||
})
|
||||
|
||||
it('Check getElementAt', () => {
|
||||
list.add(100)
|
||||
list.add(200)
|
||||
list.add(300)
|
||||
list.add(500)
|
||||
list.add(900)
|
||||
|
||||
expect(list.getElementAt(1).data).toEqual(200)
|
||||
expect(list.getElementAt(3).data).toEqual(500)
|
||||
})
|
||||
|
||||
it('Check addAtFirst', () => {
|
||||
list.add(1)
|
||||
list.add(5)
|
||||
list.add(7)
|
||||
list.add(9)
|
||||
list.add(0)
|
||||
expect(list.get()).toEqual([1, 5, 7, 9, 0])
|
||||
list.addAtFirst(100)
|
||||
expect(list.get()).toEqual([100, 1, 5, 7, 9, 0])
|
||||
})
|
||||
|
||||
it('Check add', () => {
|
||||
list.add(1)
|
||||
list.add(5)
|
||||
list.add(7)
|
||||
list.add(9)
|
||||
list.add(0)
|
||||
expect(list.get()).toEqual([1, 5, 7, 9, 0])
|
||||
list.add(100)
|
||||
expect(list.get()).toEqual([1, 5, 7, 9, 0, 100])
|
||||
})
|
||||
|
||||
it('Check insertAt', () => {
|
||||
expect(list.insertAt(0, 100)).toEqual(1)
|
||||
expect(list.get()).toEqual([100])
|
||||
expect(list.insertAt(0, 200)).toEqual(2)
|
||||
expect(list.get()).toEqual([200, 100])
|
||||
expect(list.insertAt(2, 300)).toEqual(3)
|
||||
expect(list.get()).toEqual([200, 100, 300])
|
||||
})
|
||||
|
||||
it('Checks indexOf', () => {
|
||||
expect(list.indexOf(200)).toEqual(-1)
|
||||
list.add(100)
|
||||
list.add(200)
|
||||
list.add(300)
|
||||
list.add(500)
|
||||
list.add(900)
|
||||
expect(list.indexOf(200)).toEqual(1)
|
||||
})
|
||||
|
||||
it('Check remove', () => {
|
||||
expect(list.remove()).toEqual(null)
|
||||
list.add(100)
|
||||
list.add(200)
|
||||
list.add(300)
|
||||
list.add(500)
|
||||
list.add(900)
|
||||
expect(list.get()).toEqual([100, 200, 300, 500, 900])
|
||||
const removedData = list.remove()
|
||||
expect(removedData).toEqual(900)
|
||||
expect(list.get()).toEqual([100, 200, 300, 500])
|
||||
})
|
||||
|
||||
it('Check removeFirst', () => {
|
||||
expect(list.removeFirst()).toEqual(null)
|
||||
list.add(100)
|
||||
list.add(200)
|
||||
list.add(300)
|
||||
list.add(500)
|
||||
list.add(900)
|
||||
expect(list.get()).toEqual([100, 200, 300, 500, 900])
|
||||
const removedData = list.removeFirst()
|
||||
expect(removedData).toEqual(100)
|
||||
expect(list.get()).toEqual([200, 300, 500, 900])
|
||||
})
|
||||
|
||||
it('Check removeAt', () => {
|
||||
expect(list.removeAt(1)).toEqual(null)
|
||||
list.add(100)
|
||||
list.add(200)
|
||||
list.add(300)
|
||||
list.add(500)
|
||||
list.add(900)
|
||||
expect(list.get()).toEqual([100, 200, 300, 500, 900])
|
||||
const removedData = list.removeAt(2)
|
||||
expect(removedData).toEqual(300)
|
||||
expect(list.get()).toEqual([100, 200, 500, 900])
|
||||
})
|
||||
|
||||
it('Check removeData', () => {
|
||||
expect(list.removeData(100)).toEqual(null)
|
||||
list.add(100)
|
||||
list.add(200)
|
||||
list.add(300)
|
||||
list.add(500)
|
||||
list.add(900)
|
||||
expect(list.get()).toEqual([100, 200, 300, 500, 900])
|
||||
const removedData = list.removeData(200)
|
||||
expect(removedData).toEqual(200)
|
||||
expect(list.get()).toEqual([100, 300, 500, 900])
|
||||
})
|
||||
})
|
||||
|
@ -4,7 +4,7 @@
|
||||
// Doesn’t use dynamic memory so No memory leaks
|
||||
|
||||
class CircularQueue {
|
||||
constructor (maxLength) {
|
||||
constructor(maxLength) {
|
||||
this.queue = []
|
||||
this.front = 0
|
||||
this.rear = 0
|
||||
@ -12,7 +12,7 @@ class CircularQueue {
|
||||
}
|
||||
|
||||
// ADD ELEMENTS TO QUEUE
|
||||
enqueue (value) {
|
||||
enqueue(value) {
|
||||
if (this.checkOverflow()) return
|
||||
if (this.checkEmpty()) {
|
||||
this.front += 1
|
||||
@ -26,7 +26,7 @@ class CircularQueue {
|
||||
}
|
||||
|
||||
// REMOVES ELEMENTS
|
||||
dequeue () {
|
||||
dequeue() {
|
||||
if (this.checkEmpty()) {
|
||||
// UNDERFLOW
|
||||
return
|
||||
@ -44,13 +44,13 @@ class CircularQueue {
|
||||
}
|
||||
|
||||
// checks if the queue is empty or not
|
||||
checkEmpty () {
|
||||
checkEmpty() {
|
||||
if (this.front === 0 && this.rear === 0) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
checkSingleelement () {
|
||||
checkSingleelement() {
|
||||
if (this.front === this.rear && this.rear !== 0) {
|
||||
this.front = this.rear = 0
|
||||
return true
|
||||
@ -58,27 +58,30 @@ class CircularQueue {
|
||||
}
|
||||
|
||||
// Checks if max capacity of queue has been reached or not
|
||||
checkOverflow () {
|
||||
if ((this.front === 1 && this.rear === this.maxLength) || (this.front === this.rear + 1)) {
|
||||
checkOverflow() {
|
||||
if (
|
||||
(this.front === 1 && this.rear === this.maxLength) ||
|
||||
this.front === this.rear + 1
|
||||
) {
|
||||
// CIRCULAR QUEUE OVERFLOW
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Prints the entire array ('*' represents blank space)
|
||||
display (output = value => console.log(value)) {
|
||||
display(output = (value) => console.log(value)) {
|
||||
for (let index = 1; index < this.queue.length; index++) {
|
||||
output(this.queue[index])
|
||||
}
|
||||
}
|
||||
|
||||
// Displays the length of queue
|
||||
length () {
|
||||
length() {
|
||||
return this.queue.length - 1
|
||||
}
|
||||
|
||||
// Display the top most value of queue
|
||||
peek () {
|
||||
peek() {
|
||||
return this.queue[this.front]
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,15 @@
|
||||
/* Queue
|
||||
* A Queue is a data structure that allows you to add an element to the end of
|
||||
* a list and remove the item at the front. A queue follows a FIFO (First In First Out)
|
||||
* system, where the first item to enter the queue is the first to be removed,
|
||||
* All these operation complexities are O(1).
|
||||
* This implementation following the linked list structure.
|
||||
*/
|
||||
* A Queue is a data structure that allows you to add an element to the end of
|
||||
* a list and remove the item at the front. A queue follows a FIFO (First In First Out)
|
||||
* system, where the first item to enter the queue is the first to be removed,
|
||||
* All these operation complexities are O(1).
|
||||
* This implementation following the linked list structure.
|
||||
*/
|
||||
|
||||
class Queue {
|
||||
#size
|
||||
|
||||
constructor () {
|
||||
constructor() {
|
||||
this.head = null
|
||||
this.tail = null
|
||||
this.#size = 0
|
||||
@ -17,7 +17,7 @@ class Queue {
|
||||
return Object.seal(this)
|
||||
}
|
||||
|
||||
get length () {
|
||||
get length() {
|
||||
return this.#size
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ class Queue {
|
||||
* @param {*} data
|
||||
* @returns {number} - The current size of queue
|
||||
*/
|
||||
enqueue (data) {
|
||||
enqueue(data) {
|
||||
const node = { data, next: null }
|
||||
|
||||
if (!this.head && !this.tail) {
|
||||
@ -44,7 +44,7 @@ class Queue {
|
||||
* @description - Removes the value at the front of the queue
|
||||
* @returns {*} - The first data of the queue
|
||||
*/
|
||||
dequeue () {
|
||||
dequeue() {
|
||||
if (this.isEmpty()) {
|
||||
throw new Error('Queue is Empty')
|
||||
}
|
||||
@ -66,7 +66,7 @@ class Queue {
|
||||
* @description - Return the item at the front of the queue
|
||||
* @returns {*}
|
||||
*/
|
||||
peekFirst () {
|
||||
peekFirst() {
|
||||
if (this.isEmpty()) {
|
||||
throw new Error('Queue is Empty')
|
||||
}
|
||||
@ -78,7 +78,7 @@ class Queue {
|
||||
* @description - Return the item at the tail of the queue
|
||||
* @returns {*}
|
||||
*/
|
||||
peekLast () {
|
||||
peekLast() {
|
||||
if (this.isEmpty()) {
|
||||
throw new Error('Queue is Empty')
|
||||
}
|
||||
@ -90,7 +90,7 @@ class Queue {
|
||||
* @description - Return the array of Queue
|
||||
* @returns {Array<*>}
|
||||
*/
|
||||
toArray () {
|
||||
toArray() {
|
||||
const array = []
|
||||
let node = this.head
|
||||
|
||||
@ -103,10 +103,10 @@ class Queue {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description - Return is queue empty or not
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isEmpty () {
|
||||
* @description - Return is queue empty or not
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isEmpty() {
|
||||
return this.length === 0
|
||||
}
|
||||
}
|
||||
|
@ -2,17 +2,17 @@
|
||||
// contribution made by hamza chabchoub for a university project
|
||||
|
||||
class Queue {
|
||||
constructor () {
|
||||
constructor() {
|
||||
this.inputStack = []
|
||||
this.outputStack = []
|
||||
}
|
||||
|
||||
// Push item into the inputstack
|
||||
enqueue (item) {
|
||||
enqueue(item) {
|
||||
this.inputStack.push(item)
|
||||
}
|
||||
|
||||
dequeue () {
|
||||
dequeue() {
|
||||
// push all items to outputstack
|
||||
this.outputStack = []
|
||||
while (this.inputStack.length > 0) {
|
||||
@ -31,7 +31,7 @@ class Queue {
|
||||
}
|
||||
|
||||
// display elements of the inputstack
|
||||
listIn (output = value => console.log(value)) {
|
||||
listIn(output = (value) => console.log(value)) {
|
||||
let i = 0
|
||||
while (i < this.inputStack.length) {
|
||||
output(this.inputStack[i])
|
||||
@ -40,7 +40,7 @@ class Queue {
|
||||
}
|
||||
|
||||
// display element of the outputstack
|
||||
listOut (output = value => console.log(value)) {
|
||||
listOut(output = (value) => console.log(value)) {
|
||||
let i = 0
|
||||
while (i < this.outputStack.length) {
|
||||
output(this.outputStack[i])
|
||||
|
@ -1,15 +1,15 @@
|
||||
/* Stack!!
|
||||
* A stack is exactly what it sounds like. An element gets added to the top of
|
||||
* the stack and only the element on the top may be removed. This is an example
|
||||
* of an array implementation of a Stack. So an element can only be added/removed
|
||||
* from the end of the array.
|
||||
*/
|
||||
* A stack is exactly what it sounds like. An element gets added to the top of
|
||||
* the stack and only the element on the top may be removed. This is an example
|
||||
* of an array implementation of a Stack. So an element can only be added/removed
|
||||
* from the end of the array.
|
||||
*/
|
||||
|
||||
// Functions: push, pop, peek, view, length
|
||||
|
||||
// Creates a stack constructor
|
||||
const Stack = (function () {
|
||||
function Stack () {
|
||||
function Stack() {
|
||||
// The top of the Stack
|
||||
this.top = 0
|
||||
// The array representation of the stack
|
||||
@ -45,13 +45,13 @@ const Stack = (function () {
|
||||
}
|
||||
|
||||
// To see all the elements in the stack
|
||||
Stack.prototype.view = function (output = value => console.log(value)) {
|
||||
Stack.prototype.view = function (output = (value) => console.log(value)) {
|
||||
for (let i = 0; i < this.top; i++) {
|
||||
output(this.stack[i])
|
||||
}
|
||||
}
|
||||
|
||||
return Stack
|
||||
}())
|
||||
})()
|
||||
|
||||
export { Stack }
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user