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:
Roland Hummel
2023-10-03 23:08:19 +02:00
committed by GitHub
parent 0ca18c2b2c
commit 86d333ee94
392 changed files with 5849 additions and 16622 deletions

View File

@ -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

View File

@ -63,7 +63,7 @@ globby([
"!**/test/**/*",
'!**/*.test.js',
'!**/*.manual-test.js',
'!babel.config.js'
'!vitest.config.ts'
])
// create markdown content
.then(pathsToMarkdown)

View File

@ -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: |

View File

@ -2,4 +2,4 @@
. "$(dirname "$0")/_/husky.sh"
npm run style
npm run test-changed
npm run test

2
.prettierignore Normal file
View File

@ -0,0 +1,2 @@
.github
DIRECTORY.md

View File

@ -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

View File

@ -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) {

View File

@ -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 = ''

View File

@ -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')
}

View File

@ -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)

View File

@ -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])
)
}
}
}

View File

@ -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]
])
})
})

View File

@ -1,5 +1,11 @@
import { generateParentheses } from '../generateParentheses'
test('generate all valid parentheses of input 3', () => {
expect(generateParentheses(3)).toStrictEqual(['((()))', '(()())', '(())()', '()(())', '()()()'])
expect(generateParentheses(3)).toStrictEqual([
'((()))',
'(()())',
'(())()',
'()(())',
'()()()'
])
})

View File

@ -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)
})
})

View File

@ -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('')
})

View File

@ -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', () => {

View File

@ -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

View File

@ -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 }

View File

@ -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).

View File

@ -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]

View File

@ -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]

View File

@ -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)
}

View File

@ -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,

View File

@ -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))

View File

@ -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], []))
}

View File

@ -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

View File

@ -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

View File

@ -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]
])
})
})

View File

@ -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])
})
})
})

View File

@ -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(' ')

View File

@ -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

View File

@ -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 }

View File

@ -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()
}

View File

@ -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')
}

View File

@ -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

View File

@ -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)
)
}

View File

@ -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')
})
})

View File

@ -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)
})

View File

@ -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', () => {

View File

@ -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'
)
})
})

View File

@ -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)
})

View File

@ -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 = []

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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) => {

View File

@ -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

View File

@ -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
}

View File

@ -1,4 +1,4 @@
function decimalToBinary (num) {
function decimalToBinary(num) {
const bin = []
while (num > 0) {
bin.unshift(num % 2)

View File

@ -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))

View File

@ -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

View File

@ -38,7 +38,7 @@ const orders = [
'I'
]
function decimalToRoman (num) {
function decimalToRoman(num) {
let roman = ''
for (const symbol of orders) {
while (num >= values[symbol]) {

View File

@ -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

View File

@ -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)
}

View File

@ -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)

View File

@ -33,6 +33,4 @@ const lengthConversion = (length, fromUnit, toUnit) => {
return convertedLength
}
export {
lengthConversion
}
export { lengthConversion }

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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)}`
}

View File

@ -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}`
}
}
}

View File

@ -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)
}

View File

@ -8,7 +8,7 @@ const values = {
M: 1000
}
export function romanToDecimal (romanNumber) {
export function romanToDecimal(romanNumber) {
let prev = ' '
let sum = 0

View File

@ -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
}

View File

@ -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('')
})

View File

@ -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.

View File

@ -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')

View File

@ -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()
)
})
})

View File

@ -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 })
})

View File

@ -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 }) => {

View File

@ -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)
})
})

View File

@ -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)
})
})

View File

@ -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!'
)
})
})

View File

@ -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!'
)
})
})

View File

@ -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)

View File

@ -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
)
}
}

View File

@ -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 }

View File

@ -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 }

View File

@ -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)
})
})

View File

@ -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
}

View File

@ -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()

View File

@ -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]

View File

@ -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

View File

@ -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]
]
}
}

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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
})
})

View File

@ -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)

View File

@ -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) {

View File

@ -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
}

View File

@ -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)

View File

@ -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 }

View File

@ -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
}

View File

@ -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 }

View File

@ -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])
})
})

View File

@ -4,7 +4,7 @@
// Doesnt 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]
}
}

View File

@ -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
}
}

View File

@ -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])

View File

@ -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