Refactor: Implement SmartCube renderer, improve UI styling, and fix gaps
This commit is contained in:
22
node_modules/@gkucmierz/utils/.github/workflows/deploy-docs.yml
generated
vendored
Normal file
22
node_modules/@gkucmierz/utils/.github/workflows/deploy-docs.yml
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
name: Deploy docs
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main # Change this to your default branch
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
concurrency: ci-${{ github.ref }} # Recommended if you intend to make multiple deployments in quick succession.
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout 🛎️
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install and Build 🔧 # This example project is built using npm and outputs the result to the 'build' folder. Replace with the commands required to build your project, or remove this step entirely if your site is pre-built.
|
||||
run: |
|
||||
npm i
|
||||
npm run docs:build
|
||||
|
||||
- name: Deploy 🚀
|
||||
uses: JamesIves/github-pages-deploy-action@v4
|
||||
with:
|
||||
folder: docs # The folder the action should deploy.
|
||||
25
node_modules/@gkucmierz/utils/.github/workflows/npm-publish.yml
generated
vendored
Normal file
25
node_modules/@gkucmierz/utils/.github/workflows/npm-publish.yml
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
name: npm-publish
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main # Change this to your default branch
|
||||
jobs:
|
||||
npm-publish:
|
||||
name: npm-publish
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Publish if version has been updated
|
||||
uses: pascalgn/npm-publish-action@1.3.9
|
||||
with: # All of theses inputs are optional
|
||||
tag_name: "v%s"
|
||||
tag_message: "v%s"
|
||||
create_tag: "true"
|
||||
commit_pattern: "^Release (\\S+)"
|
||||
workspace: "."
|
||||
publish_command: "yarn"
|
||||
publish_args: "--non-interactive --access public"
|
||||
env: # More info about the environment variables in the README
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Leave this as is, it's automatically generated
|
||||
NPM_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} # You need to set this in your repo settings
|
||||
4
node_modules/@gkucmierz/utils/.husky/pre-commit
generated
vendored
Executable file
4
node_modules/@gkucmierz/utils/.husky/pre-commit
generated
vendored
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
npm test
|
||||
11
node_modules/@gkucmierz/utils/README.md
generated
vendored
Normal file
11
node_modules/@gkucmierz/utils/README.md
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
### Install
|
||||
|
||||
```bash
|
||||
npm i @gkucmierz/utils
|
||||
```
|
||||
|
||||
### Docs
|
||||
|
||||
[https://gkucmierz.github.io/utils](https://gkucmierz.github.io/utils)
|
||||
|
||||
10
node_modules/@gkucmierz/utils/jsdoc.json
generated
vendored
Normal file
10
node_modules/@gkucmierz/utils/jsdoc.json
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"source": {
|
||||
"include": ["src"],
|
||||
"includePattern": ".+\\.(js(doc|x)?|mjs)$"
|
||||
},
|
||||
"opts": {
|
||||
"destination": "./docs/",
|
||||
"template": "node_modules/docdash"
|
||||
}
|
||||
}
|
||||
94
node_modules/@gkucmierz/utils/main.mjs
generated
vendored
Normal file
94
node_modules/@gkucmierz/utils/main.mjs
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
|
||||
import {
|
||||
SetCnt
|
||||
} from './src/SetCnt.mjs'
|
||||
import {
|
||||
fromBase64, fromBase64Url, toBase64, toBase64Url
|
||||
} from './src/base64.mjs'
|
||||
import {
|
||||
bijective2num, bijective2numBI, num2bijective, num2bijectiveBI
|
||||
} from './src/bijective-numeration.mjs'
|
||||
import {
|
||||
binarySearchArr
|
||||
} from './src/binary-search.mjs'
|
||||
import {
|
||||
copyCase
|
||||
} from './src/copy-case.mjs'
|
||||
import {
|
||||
egcd
|
||||
} from './src/egcd.mjs'
|
||||
import {
|
||||
factors, factorsBI
|
||||
} from './src/factors.mjs'
|
||||
import {
|
||||
gcd, gcdBI
|
||||
} from './src/gcd.mjs'
|
||||
import {
|
||||
getType
|
||||
} from './src/get-type.mjs'
|
||||
import {
|
||||
gpn, gpnBI
|
||||
} from './src/gpn.mjs'
|
||||
import {
|
||||
Heap
|
||||
} from './src/heap.mjs'
|
||||
import {
|
||||
heronsFormula, heronsFormulaBI
|
||||
} from './src/herons-formula.mjs'
|
||||
import {
|
||||
lcm, lcmBI
|
||||
} from './src/lcm.mjs'
|
||||
import {
|
||||
ListNode
|
||||
} from './src/list-node.mjs'
|
||||
import {
|
||||
matrixAsArray
|
||||
} from './src/matrix.mjs'
|
||||
import {
|
||||
memoize
|
||||
} from './src/memoize.mjs'
|
||||
import {
|
||||
mod, modBI
|
||||
} from './src/mod.mjs'
|
||||
import {
|
||||
phi, phiBI
|
||||
} from './src/phi.mjs'
|
||||
import {
|
||||
powMod, powModBI
|
||||
} from './src/pow-mod.mjs'
|
||||
import {
|
||||
array2range, range2array
|
||||
} from './src/range-array.mjs'
|
||||
import {
|
||||
squareRoot, squareRootBI
|
||||
} from './src/square-root.mjs'
|
||||
import {
|
||||
tonelliShanksBI
|
||||
} from './src/tonelli-shanks.mjs'
|
||||
|
||||
export * from './src/SetCnt.mjs';
|
||||
export * from './src/base64.mjs';
|
||||
export * from './src/bijective-numeration.mjs';
|
||||
export * from './src/binary-search.mjs';
|
||||
export * from './src/copy-case.mjs';
|
||||
export * from './src/egcd.mjs';
|
||||
export * from './src/factors.mjs';
|
||||
export * from './src/gcd.mjs';
|
||||
export * from './src/get-type.mjs';
|
||||
export * from './src/gpn.mjs';
|
||||
export * from './src/heap.mjs';
|
||||
export * from './src/herons-formula.mjs';
|
||||
export * from './src/lcm.mjs';
|
||||
export * from './src/list-node.mjs';
|
||||
export * from './src/matrix.mjs';
|
||||
export * from './src/memoize.mjs';
|
||||
export * from './src/mod.mjs';
|
||||
export * from './src/phi.mjs';
|
||||
export * from './src/pow-mod.mjs';
|
||||
export * from './src/range-array.mjs';
|
||||
export * from './src/square-root.mjs';
|
||||
export * from './src/tonelli-shanks.mjs';
|
||||
|
||||
export default [
|
||||
SetCnt, fromBase64, fromBase64Url, toBase64, toBase64Url, bijective2num, bijective2numBI, num2bijective, num2bijectiveBI, binarySearchArr, copyCase, egcd, factors, factorsBI, gcd, gcdBI, getType, gpn, gpnBI, Heap, heronsFormula, heronsFormulaBI, lcm, lcmBI, ListNode, matrixAsArray, memoize, mod, modBI, phi, phiBI, powMod, powModBI, array2range, range2array, squareRoot, squareRootBI, tonelliShanksBI
|
||||
];
|
||||
1422
node_modules/@gkucmierz/utils/package-lock.json
generated
vendored
Normal file
1422
node_modules/@gkucmierz/utils/package-lock.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
27
node_modules/@gkucmierz/utils/package.json
generated
vendored
Normal file
27
node_modules/@gkucmierz/utils/package.json
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "@gkucmierz/utils",
|
||||
"version": "1.28.3",
|
||||
"description": "Usefull functions for solving programming tasks",
|
||||
"main": "main.mjs",
|
||||
"scripts": {
|
||||
"test": "jasmine",
|
||||
"watch": "nodemon --exec 'npm test'",
|
||||
"main": "node scripts/generate_main.mjs",
|
||||
"docs": "npm run docs:build; npm run docs:open",
|
||||
"docs:build": "jsdoc -c jsdoc.json --readme README.md",
|
||||
"docs:open": "open docs/index.html"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/gkucmierz/utils"
|
||||
},
|
||||
"author": "Grzegorz Kućmierz",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"docdash": "^2.0.2",
|
||||
"husky": "^8.0.1",
|
||||
"jasmine": "^4.4.0",
|
||||
"jsdoc": "^4.0.4",
|
||||
"nodemon": "^2.0.20"
|
||||
}
|
||||
}
|
||||
43
node_modules/@gkucmierz/utils/scripts/generate_main.mjs
generated
vendored
Normal file
43
node_modules/@gkucmierz/utils/scripts/generate_main.mjs
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const MAIN_FILE = './main.mjs';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname([path.dirname(__filename), '/../src/.'].join(''));
|
||||
|
||||
const files = fs.readdirSync(__dirname);
|
||||
|
||||
const utilsFiles = files
|
||||
.filter(name => name.match(/\.mjs$/))
|
||||
.filter(name => name !== 'main.mjs');
|
||||
|
||||
const allMethods = {};
|
||||
const map = new Map();
|
||||
|
||||
for (const file of utilsFiles) {
|
||||
const f = [__dirname, file].join('/');
|
||||
const obj = await import(f);
|
||||
map.set(file, Object.keys(obj));
|
||||
Object.keys(obj).map(key => {
|
||||
if (key in allMethods) throw Error('Duplicate method name');
|
||||
allMethods[key] = obj[key];
|
||||
});
|
||||
};
|
||||
|
||||
fs.writeFileSync(MAIN_FILE, [
|
||||
'',
|
||||
...[...map].map(([file, methods]) => {
|
||||
return `import {\n ${methods.join(', ')}\n} from './src/${file}'`;
|
||||
}),
|
||||
'',
|
||||
...utilsFiles.map(file => `export * from './src/${file}';`),
|
||||
'',
|
||||
`export default [`,
|
||||
` ${Object.keys(allMethods).join(', ')}`,
|
||||
`];`,
|
||||
'',
|
||||
].join('\n'));
|
||||
|
||||
58
node_modules/@gkucmierz/utils/spec/SetCnt.spec.mjs
generated
vendored
Normal file
58
node_modules/@gkucmierz/utils/spec/SetCnt.spec.mjs
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
|
||||
import {
|
||||
SetCnt,
|
||||
} from '../src/SetCnt.mjs';
|
||||
|
||||
const set = new Set([1,2,3,5])
|
||||
const map = new Map([[1,2],[3,5]])
|
||||
// console.log([...sc.entries()]);
|
||||
|
||||
describe('SetCnt', () => {
|
||||
it('has', () => {
|
||||
const sc = new SetCnt([1,2,5,6,1,1]);
|
||||
expect(sc.has(1)).toBe(true);
|
||||
expect(sc.has(2)).toBe(true);
|
||||
expect(sc.has(5)).toBe(true);
|
||||
});
|
||||
|
||||
it('add', () => {
|
||||
const sc = new SetCnt([1,2,5,6,1,1]);
|
||||
expect(sc.add(123)).toBe(sc);
|
||||
expect(sc.has(123)).toBe(true);
|
||||
});
|
||||
|
||||
it('delete', () => {
|
||||
const sc = new SetCnt();
|
||||
expect(sc.add(123)).toBe(sc);
|
||||
expect(sc.add(123)).toBe(sc);
|
||||
|
||||
expect(sc.delete(123)).toBe(true);
|
||||
expect(sc.has(123)).toBe(true);
|
||||
|
||||
expect(sc.delete(123)).toBe(true);
|
||||
expect(sc.has(123)).toBe(false);
|
||||
|
||||
expect(sc.delete(123)).toBe(false);
|
||||
});
|
||||
|
||||
it('deleteAll', () => {
|
||||
const sc = new SetCnt();
|
||||
expect(sc.add(123)).toBe(sc);
|
||||
expect(sc.add(123)).toBe(sc);
|
||||
|
||||
expect(sc.deleteAll(123)).toBe(true);
|
||||
expect(sc.has(123)).toBe(false);
|
||||
});
|
||||
|
||||
it('cnt', () => {
|
||||
const sc = new SetCnt();
|
||||
expect(sc.cnt(123)).toBe(0);
|
||||
|
||||
expect(sc.add(123)).toBe(sc);
|
||||
expect(sc.add(123)).toBe(sc);
|
||||
|
||||
expect(sc.cnt(123)).toBe(2);
|
||||
expect(sc.deleteAll(123)).toBe(true);
|
||||
expect(sc.cnt(123)).toBe(0);
|
||||
});
|
||||
});
|
||||
69
node_modules/@gkucmierz/utils/spec/Trie.spec.mjs
generated
vendored
Normal file
69
node_modules/@gkucmierz/utils/spec/Trie.spec.mjs
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
|
||||
import {
|
||||
Trie,
|
||||
} from '../src/Trie.mjs';
|
||||
|
||||
describe('Trie', () => {
|
||||
it('check empty', () => {
|
||||
const trie = Trie();
|
||||
expect(trie.has('')).toBe(false);
|
||||
expect(trie.has('abc')).toBe(false);
|
||||
});
|
||||
|
||||
it('init data', () => {
|
||||
const trie = Trie(['abc', '']);
|
||||
expect(trie.has('')).toBe(true);
|
||||
expect(trie.has('abc')).toBe(true);
|
||||
});
|
||||
|
||||
it('add/readd data', () => {
|
||||
const trie = Trie();
|
||||
expect(trie.has('')).toBe(false);
|
||||
expect(trie.add('')).toBe(true);
|
||||
expect(trie.has('')).toBe(true);
|
||||
expect(trie.add('')).toBe(false);
|
||||
});
|
||||
|
||||
it('list data', () => {
|
||||
const trie = Trie(['abc', '', 'abcdef', 'xyz']);
|
||||
const abc = ['abc', 'abcdef'];
|
||||
expect(trie.get('a')).toEqual(abc);
|
||||
expect(trie.get('ab')).toEqual(abc);
|
||||
expect(trie.get('abc')).toEqual(abc);
|
||||
expect(trie.get('aa')).toEqual([]);
|
||||
expect(trie.get('')).toEqual(['', 'abc', 'abcdef', 'xyz']);
|
||||
});
|
||||
|
||||
it('remove node', () => {
|
||||
const trie = Trie(['a', 'ab', 'abc']);
|
||||
|
||||
expect(trie.has('abc')).toEqual(true);
|
||||
expect(trie.remove('abc')).toEqual(true);
|
||||
expect(trie.remove('abc')).toEqual(false);
|
||||
expect(trie.has('abc')).toEqual(false);
|
||||
|
||||
expect(trie.has('ab')).toEqual(true);
|
||||
expect(trie.remove('ab')).toEqual(true);
|
||||
expect(trie.remove('ab')).toEqual(false);
|
||||
expect(trie.has('ab')).toEqual(false);
|
||||
|
||||
expect(trie.has('a')).toEqual(true);
|
||||
expect(trie.remove('a')).toEqual(true);
|
||||
expect(trie.remove('a')).toEqual(false);
|
||||
expect(trie.has('a')).toEqual(false);
|
||||
});
|
||||
|
||||
it('keep child node after parent removal', () => {
|
||||
const trie = Trie(['a', 'abc']);
|
||||
|
||||
expect(trie.has('a')).toEqual(true);
|
||||
expect(trie.remove('a')).toEqual(true);
|
||||
expect(trie.remove('a')).toEqual(false);
|
||||
expect(trie.has('a')).toEqual(false);
|
||||
|
||||
expect(trie.has('abc')).toEqual(true);
|
||||
expect(trie.remove('abc')).toEqual(true);
|
||||
expect(trie.remove('abc')).toEqual(false);
|
||||
expect(trie.has('abc')).toEqual(false);
|
||||
})
|
||||
});
|
||||
29
node_modules/@gkucmierz/utils/spec/base64.spec.mjs
generated
vendored
Normal file
29
node_modules/@gkucmierz/utils/spec/base64.spec.mjs
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
import {
|
||||
toBase64,
|
||||
fromBase64,
|
||||
toBase64Url,
|
||||
fromBase64Url,
|
||||
} from '../src/base64.mjs';
|
||||
|
||||
describe('base64', () => {
|
||||
it('toBase64', () => {
|
||||
expect(toBase64('🥚')).toBe('Ptha3Q==');
|
||||
expect(toBase64('🐔')).toBe('PdgU3A==');
|
||||
expect(toBase64('')).toBe('++8=');
|
||||
});
|
||||
|
||||
it('fromBase64', () => {
|
||||
expect(fromBase64('Ptha3Q==')).toBe('🥚');
|
||||
expect(fromBase64('PdgU3A==')).toBe('🐔');
|
||||
expect(fromBase64('++8=')).toBe('');
|
||||
});
|
||||
|
||||
it('toBase64Url', () => {
|
||||
expect(toBase64Url('')).toBe('--8=');
|
||||
});
|
||||
|
||||
it('fromBase64', () => {
|
||||
expect(fromBase64Url('--8=')).toBe('');
|
||||
});
|
||||
});
|
||||
123
node_modules/@gkucmierz/utils/spec/bijective-numeration.spec.mjs
generated
vendored
Normal file
123
node_modules/@gkucmierz/utils/spec/bijective-numeration.spec.mjs
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
|
||||
import {
|
||||
num2bijective,
|
||||
bijective2num,
|
||||
num2bijectiveBI,
|
||||
bijective2numBI,
|
||||
} from '../src/bijective-numeration.mjs';
|
||||
|
||||
describe('bijective-numeration', () => {
|
||||
const alpha = 'abcdefghijklmnopqrstuvwxyz';
|
||||
|
||||
const map = [
|
||||
[0, ''],
|
||||
[1, '1'],
|
||||
[2, '2'],
|
||||
[3, '11'],
|
||||
[4, '12'],
|
||||
[5, '21'],
|
||||
[6, '22'],
|
||||
[7, '111'],
|
||||
];
|
||||
|
||||
const mapAlpha = [
|
||||
[0, ''],
|
||||
[1, 'a'],
|
||||
[26, 'z'],
|
||||
[26 + 1, 'aa'],
|
||||
[26 * 26 + 26, 'zz'],
|
||||
[26 * 26 + 26 + 1, 'aaa'],
|
||||
];
|
||||
|
||||
it('num2bijective', () => {
|
||||
map.map(([num, bij]) => {
|
||||
expect(num2bijective(num)).toEqual(bij);
|
||||
});
|
||||
});
|
||||
|
||||
it('num2bijective alpha', () => {
|
||||
mapAlpha.map(([num, bij]) => {
|
||||
expect(num2bijective(num, alpha)).toEqual(bij);
|
||||
});
|
||||
});
|
||||
|
||||
it('bijective2num', () => {
|
||||
map.map(([num, bij]) => {
|
||||
expect(bijective2num(bij)).toEqual(num);
|
||||
});
|
||||
});
|
||||
|
||||
it('bijective2num alpha', () => {
|
||||
mapAlpha.map(([num, bij]) => {
|
||||
expect(bijective2num(bij, alpha)).toEqual(num);
|
||||
});
|
||||
});
|
||||
|
||||
it('random tests', () => {
|
||||
for (let i = 0; i < 1e3; ++i) {
|
||||
const n = Math.round(Math.random() * 1e6);
|
||||
const bj = num2bijective(n, alpha);
|
||||
expect(bijective2num(bj, alpha)).toEqual(n);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('bijective-numeration BigInt', () => {
|
||||
const alpha = 'abcdefghijklmnopqrstuvwxyz';
|
||||
|
||||
const map = [
|
||||
[0n, ''],
|
||||
[1n, '1'],
|
||||
[2n, '2'],
|
||||
[3n, '11'],
|
||||
[4n, '12'],
|
||||
[5n, '21'],
|
||||
[6n, '22'],
|
||||
[7n, '111'],
|
||||
];
|
||||
|
||||
const mapAlpha = [
|
||||
[0n, ''],
|
||||
[1n, 'a'],
|
||||
[26n, 'z'],
|
||||
[26n + 1n, 'aa'],
|
||||
[26n * 26n + 26n, 'zz'],
|
||||
[26n * 26n + 26n + 1n, 'aaa'],
|
||||
];
|
||||
|
||||
it('num2bijectiveBI', () => {
|
||||
map.map(([num, bij]) => {
|
||||
expect(num2bijectiveBI(num)).toEqual(bij);
|
||||
});
|
||||
});
|
||||
|
||||
it('num2bijectiveBI alpha', () => {
|
||||
mapAlpha.map(([num, bij]) => {
|
||||
expect(num2bijectiveBI(num, alpha)).toEqual(bij);
|
||||
});
|
||||
});
|
||||
|
||||
it('bijective2numBI', () => {
|
||||
map.map(([num, bij]) => {
|
||||
expect(bijective2numBI(bij)).toEqual(num);
|
||||
});
|
||||
});
|
||||
|
||||
it('bijective2numBI alpha', () => {
|
||||
mapAlpha.map(([num, bij]) => {
|
||||
expect(bijective2numBI(bij, alpha)).toEqual(num);
|
||||
});
|
||||
});
|
||||
|
||||
it('random tests', () => {
|
||||
for (let i = 0; i < 1e3; ++i) {
|
||||
const b = BigInt(Math.round(Math.random() * 1000));
|
||||
const n = BigInt(Math.round(Math.random() * 100));
|
||||
const bi = b ** n;
|
||||
|
||||
const bj = num2bijectiveBI(bi, alpha);
|
||||
expect(bijective2numBI(bj, alpha)).toEqual(bi);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
91
node_modules/@gkucmierz/utils/spec/binary-search.spec.mjs
generated
vendored
Normal file
91
node_modules/@gkucmierz/utils/spec/binary-search.spec.mjs
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
|
||||
import {
|
||||
binarySearchArr,
|
||||
binarySearchLE,
|
||||
binarySearchGE,
|
||||
binarySearchRangeIncl,
|
||||
} from '../src/binary-search.mjs';
|
||||
|
||||
describe('binarySearchArr', () => {
|
||||
it('few cases', () => {
|
||||
expect(binarySearchArr([1, 2, 3, 4], 1)).toBe(0);
|
||||
expect(binarySearchArr([1, 2, 3, 4], 2)).toBe(1);
|
||||
expect(binarySearchArr([1, 2, 3, 4], 3)).toBe(2);
|
||||
expect(binarySearchArr([1, 2, 3, 4], 4)).toBe(3);
|
||||
expect(binarySearchArr([1, 2, 3, 4], 0)).toBe(-1);
|
||||
expect(binarySearchArr([1, 2, 3, 4], 5)).toBe(-1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('binarySearchLE', () => {
|
||||
it('mid group', () => {
|
||||
const arr = [0,1,2,2,3];
|
||||
expect(binarySearchLE(arr, -100)).toBe(-1);
|
||||
expect(binarySearchLE(arr, 0)).toBe(0);
|
||||
expect(binarySearchLE(arr, 1)).toBe(1);
|
||||
expect(binarySearchLE(arr, 2)).toBe(3);
|
||||
expect(binarySearchLE(arr, 3)).toBe(4);
|
||||
expect(binarySearchLE(arr, 100)).toBe(4);
|
||||
});
|
||||
|
||||
it('begin group', () => {
|
||||
const arr = [2,2,3];
|
||||
expect(binarySearchLE(arr, -100)).toBe(-1);
|
||||
expect(binarySearchLE(arr, 2)).toBe(1);
|
||||
expect(binarySearchLE(arr, 3)).toBe(2);
|
||||
expect(binarySearchLE(arr, 100)).toBe(2);
|
||||
});
|
||||
|
||||
it('end group', () => {
|
||||
const arr = [1,2,2];
|
||||
expect(binarySearchLE(arr, -100)).toBe(-1);
|
||||
expect(binarySearchLE(arr, 1)).toBe(0);
|
||||
expect(binarySearchLE(arr, 2)).toBe(2);
|
||||
expect(binarySearchLE(arr, 100)).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('binarySearchGE', () => {
|
||||
it('mid group', () => {
|
||||
const arr = [0,1,2,2,3];
|
||||
expect(binarySearchGE(arr, -100)).toBe(0);
|
||||
expect(binarySearchGE(arr, 0)).toBe(0);
|
||||
expect(binarySearchGE(arr, 1)).toBe(1);
|
||||
expect(binarySearchGE(arr, 2)).toBe(2);
|
||||
expect(binarySearchGE(arr, 3)).toBe(4);
|
||||
expect(binarySearchGE(arr, 100)).toBe(5);
|
||||
});
|
||||
|
||||
it('begin group', () => {
|
||||
const arr = [2,2,3];
|
||||
expect(binarySearchGE(arr, -100)).toBe(0);
|
||||
expect(binarySearchGE(arr, 2)).toBe(0);
|
||||
expect(binarySearchGE(arr, 3)).toBe(2);
|
||||
expect(binarySearchGE(arr, 100)).toBe(3);
|
||||
});
|
||||
|
||||
it('end group', () => {
|
||||
const arr = [1,2,2];
|
||||
expect(binarySearchGE(arr, -100)).toBe(0);
|
||||
expect(binarySearchGE(arr, 1)).toBe(0);
|
||||
expect(binarySearchGE(arr, 2)).toBe(1);
|
||||
expect(binarySearchGE(arr, 100)).toBe(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('binarySearchRangeIncl', () => {
|
||||
it('basic', () => {
|
||||
const arr = [0,1,1,3];
|
||||
const check = [-10, ...arr, 10];
|
||||
const expected = [
|
||||
[0, -1],
|
||||
[0, 0], [1, 2], [1, 2], [3, 3],
|
||||
[4, 3],
|
||||
];
|
||||
|
||||
for (let i = 0; i < check.length; ++i) {
|
||||
expect(binarySearchRangeIncl(arr, check[i])).toEqual(expected[i]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
12
node_modules/@gkucmierz/utils/spec/copy-case.spec.mjs
generated
vendored
Normal file
12
node_modules/@gkucmierz/utils/spec/copy-case.spec.mjs
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
import {
|
||||
copyCase,
|
||||
} from '../src/copy-case.mjs';
|
||||
|
||||
describe('copy-case', () => {
|
||||
it('few tests', () => {
|
||||
expect(copyCase('styczeń', 'january')).toBe('styczeń');
|
||||
expect(copyCase('styczeń', 'January')).toBe('Styczeń');
|
||||
expect(copyCase('styczeń', 'JANUARY')).toBe('STYCZEŃ');
|
||||
});
|
||||
});
|
||||
35
node_modules/@gkucmierz/utils/spec/factors.spec.mjs
generated
vendored
Normal file
35
node_modules/@gkucmierz/utils/spec/factors.spec.mjs
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
|
||||
import {
|
||||
factors,
|
||||
factorsBI,
|
||||
} from '../src/factors.mjs';
|
||||
|
||||
describe('factors', () => {
|
||||
it('Number', () => {
|
||||
expect(factors(0)).toEqual([]);
|
||||
expect(factors(1)).toEqual([]);
|
||||
expect(factors(2)).toEqual([2]);
|
||||
expect(factors(3)).toEqual([3]);
|
||||
expect(factors(4)).toEqual([2, 2]);
|
||||
expect(factors(5)).toEqual([5]);
|
||||
expect(factors(6)).toEqual([2, 3]);
|
||||
expect(factors(7)).toEqual([7]);
|
||||
expect(factors(8)).toEqual([2, 2, 2]);
|
||||
expect(factors(9)).toEqual([3, 3]);
|
||||
expect(factors(10)).toEqual([2, 5]);
|
||||
});
|
||||
|
||||
it('BigInt', () => {
|
||||
expect(factorsBI(0n)).toEqual([]);
|
||||
expect(factorsBI(1n)).toEqual([]);
|
||||
expect(factorsBI(2n)).toEqual([2n]);
|
||||
expect(factorsBI(3n)).toEqual([3n]);
|
||||
expect(factorsBI(4n)).toEqual([2n, 2n]);
|
||||
expect(factorsBI(5n)).toEqual([5n]);
|
||||
expect(factorsBI(6n)).toEqual([2n, 3n]);
|
||||
expect(factorsBI(7n)).toEqual([7n]);
|
||||
expect(factorsBI(8n)).toEqual([2n, 2n, 2n]);
|
||||
expect(factorsBI(9n)).toEqual([3n, 3n]);
|
||||
expect(factorsBI(10n)).toEqual([2n, 5n]);
|
||||
});
|
||||
});
|
||||
27
node_modules/@gkucmierz/utils/spec/gcd.spec.mjs
generated
vendored
Normal file
27
node_modules/@gkucmierz/utils/spec/gcd.spec.mjs
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
import {
|
||||
gcd,
|
||||
gcdBI,
|
||||
} from '../src/gcd.mjs';
|
||||
|
||||
describe('gcd', () => {
|
||||
it('Number', () => {
|
||||
expect(gcd(42, 56)).toEqual(14);
|
||||
expect(gcd(461952, 116298)).toEqual(18);
|
||||
expect(gcd(7966496, 314080416)).toEqual(32);
|
||||
expect(gcd(24826148, 45296490)).toEqual(526);
|
||||
expect(gcd(12, 0)).toEqual(12);
|
||||
expect(gcd(0, 0)).toEqual(0);
|
||||
expect(gcd(0, 9)).toEqual(9);
|
||||
});
|
||||
|
||||
it('BigInt', () => {
|
||||
expect(gcdBI(42n, 56n)).toEqual(14n);
|
||||
expect(gcdBI(461952n, 116298n)).toEqual(18n);
|
||||
expect(gcdBI(7966496n, 314080416n)).toEqual(32n);
|
||||
expect(gcdBI(24826148n, 45296490n)).toEqual(526n);
|
||||
expect(gcdBI(12n, 0n)).toEqual(12n);
|
||||
expect(gcdBI(0n, 0n)).toEqual(0n);
|
||||
expect(gcdBI(0n, 9n)).toEqual(9n);
|
||||
});
|
||||
});
|
||||
75
node_modules/@gkucmierz/utils/spec/get-type.spec.mjs
generated
vendored
Normal file
75
node_modules/@gkucmierz/utils/spec/get-type.spec.mjs
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
|
||||
import { getType } from '../src/get-type.mjs';
|
||||
|
||||
describe('get-type', () => {
|
||||
|
||||
it('should undefined', () => {
|
||||
expect(getType(undefined)).toEqual('undefined');
|
||||
});
|
||||
|
||||
it('should null', () => {
|
||||
expect(getType(null)).toEqual('null');
|
||||
});
|
||||
|
||||
it('should boolean', () => {
|
||||
expect(getType(true)).toEqual('boolean');
|
||||
expect(getType(false)).toEqual('boolean');
|
||||
expect(getType(new Boolean)).toEqual('boolean');
|
||||
});
|
||||
|
||||
it('should number', () => {
|
||||
expect(getType(1)).toEqual('number');
|
||||
expect(getType(1e3)).toEqual('number');
|
||||
expect(getType(1_000)).toEqual('number');
|
||||
expect(getType(NaN)).toEqual('number');
|
||||
expect(getType(Infinity)).toEqual('number');
|
||||
});
|
||||
|
||||
it('should bigint', () => {
|
||||
expect(getType(1n)).toEqual('bigint');
|
||||
});
|
||||
|
||||
it('should string', () => {
|
||||
expect(getType('hello')).toEqual('string');
|
||||
expect(getType(new String)).toEqual('string');
|
||||
});
|
||||
|
||||
it('should Symbol', () => {
|
||||
expect(getType(Symbol())).toEqual('symbol');
|
||||
});
|
||||
|
||||
it('should function', () => {
|
||||
expect(getType(() => 0)).toEqual('function');
|
||||
expect(getType(function() { })).toEqual('function');
|
||||
expect(getType(new Function)).toEqual('function');
|
||||
});
|
||||
|
||||
it('should generatorfunction', () => {
|
||||
expect(getType(function*() { })).toEqual('generatorfunction');
|
||||
});
|
||||
|
||||
it('should date', () => {
|
||||
expect(getType(new Date)).toEqual('date');
|
||||
});
|
||||
|
||||
it('should array', () => {
|
||||
expect(getType([])).toEqual('array');
|
||||
expect(getType(new Array)).toEqual('array');
|
||||
});
|
||||
|
||||
it('should object', () => {
|
||||
expect(getType({})).toEqual('object');
|
||||
expect(getType(new Object)).toEqual('object');
|
||||
expect(getType(new Proxy({}, {}))).toEqual('object');
|
||||
});
|
||||
|
||||
it('should map', () => {
|
||||
expect(getType(new Map)).toEqual('map');
|
||||
expect(getType(new WeakMap)).toEqual('weakmap');
|
||||
});
|
||||
|
||||
it('should set', () => {
|
||||
expect(getType(new Set)).toEqual('set');
|
||||
expect(getType(new WeakSet)).toEqual('weakset');
|
||||
});
|
||||
});
|
||||
35
node_modules/@gkucmierz/utils/spec/gpn.spec.mjs
generated
vendored
Normal file
35
node_modules/@gkucmierz/utils/spec/gpn.spec.mjs
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
|
||||
import {
|
||||
gpn,
|
||||
gpnBI,
|
||||
} from '../src/gpn.mjs';
|
||||
|
||||
describe('gpn', () => {
|
||||
it('first terms', () => {
|
||||
expect(gpn(0)).toBe(0);
|
||||
expect(gpn(1)).toBe(1);
|
||||
expect(gpn(2)).toBe(2);
|
||||
expect(gpn(3)).toBe(5);
|
||||
expect(gpn(4)).toBe(7);
|
||||
expect(gpn(5)).toBe(12);
|
||||
expect(gpn(6)).toBe(15);
|
||||
expect(gpn(7)).toBe(22);
|
||||
expect(gpn(8)).toBe(26);
|
||||
expect(gpn(9)).toBe(35);
|
||||
});
|
||||
});
|
||||
|
||||
describe('gpn BI', () => {
|
||||
it('first terms', () => {
|
||||
expect(gpnBI(0n)).toBe(0n);
|
||||
expect(gpnBI(1n)).toBe(1n);
|
||||
expect(gpnBI(2n)).toBe(2n);
|
||||
expect(gpnBI(3n)).toBe(5n);
|
||||
expect(gpnBI(4n)).toBe(7n);
|
||||
expect(gpnBI(5n)).toBe(12n);
|
||||
expect(gpnBI(6n)).toBe(15n);
|
||||
expect(gpnBI(7n)).toBe(22n);
|
||||
expect(gpnBI(8n)).toBe(26n);
|
||||
expect(gpnBI(9n)).toBe(35n);
|
||||
});
|
||||
});
|
||||
32
node_modules/@gkucmierz/utils/spec/heap.spec.mjs
generated
vendored
Normal file
32
node_modules/@gkucmierz/utils/spec/heap.spec.mjs
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
import { Heap } from '../src/heap.mjs';
|
||||
|
||||
describe('Heap', () => {
|
||||
it('size', () => {
|
||||
const heap = Heap();
|
||||
expect(heap.size()).toBe(0);
|
||||
heap.add(1);
|
||||
expect(heap.size()).toBe(1);
|
||||
heap.add(1);
|
||||
heap.add(1);
|
||||
expect(heap.size()).toBe(3);
|
||||
});
|
||||
|
||||
it('take', () => {
|
||||
const heap = Heap();
|
||||
heap.add(2);
|
||||
heap.add(1);
|
||||
heap.add(3);
|
||||
expect(heap.take()).toBe(1);
|
||||
expect(heap.take()).toBe(2);
|
||||
expect(heap.take()).toBe(3);
|
||||
});
|
||||
|
||||
it('valFn', () => {
|
||||
const heap = Heap(obj => obj.value);
|
||||
heap.add({ value: 42, other: 'second' });
|
||||
heap.add({ value: 23, other: 'first' });
|
||||
expect(heap.take().other).toBe('first');
|
||||
expect(heap.take().other).toBe('second');
|
||||
});
|
||||
});
|
||||
41
node_modules/@gkucmierz/utils/spec/herons-formula.spec.mjs
generated
vendored
Normal file
41
node_modules/@gkucmierz/utils/spec/herons-formula.spec.mjs
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
|
||||
import {
|
||||
heronsFormula,
|
||||
heronsFormulaBI,
|
||||
} from '../src/herons-formula.mjs';
|
||||
|
||||
describe('herons-formula', () => {
|
||||
it('Integer', () => {
|
||||
expect(heronsFormula(5, 12, 13)).toEqual(30);
|
||||
expect(heronsFormula(6, 8, 10)).toEqual(24);
|
||||
expect(heronsFormula(7, 15, 20)).toEqual(42);
|
||||
expect(heronsFormula(17, 17, 30)).toEqual(120);
|
||||
expect(heronsFormula(13, 37, 30)).toEqual(180);
|
||||
expect(heronsFormula(6, 25, 29)).toEqual(60);
|
||||
expect(heronsFormula(73, 9, 80)).toEqual(216);
|
||||
expect(heronsFormula(12, 35, 37)).toEqual(210);
|
||||
expect(heronsFormula(120, 109, 13)).toEqual(396);
|
||||
expect(heronsFormula(9, 10, 17)).toEqual(36);
|
||||
});
|
||||
|
||||
it('Float', () => {
|
||||
expect(heronsFormula(2, 3, 4)).toEqual(2.9047375096555625);
|
||||
expect(heronsFormula(7, 10, 12)).toEqual(34.977671449083054);
|
||||
expect(heronsFormula(6, 11, 12)).toEqual(32.839572165300815);
|
||||
expect(heronsFormula(25, 25, 45)).toEqual(245.1880655741629);
|
||||
expect(heronsFormula(10, 11, 18)).toEqual(48.59976851796724);
|
||||
});
|
||||
|
||||
it('BigInt', () => {
|
||||
expect(heronsFormulaBI(5n, 12n, 13n)).toEqual(30n);
|
||||
expect(heronsFormulaBI(6n, 8n, 10n)).toEqual(24n);
|
||||
expect(heronsFormulaBI(7n, 15n, 20n)).toEqual(42n);
|
||||
expect(heronsFormulaBI(17n, 17n, 30n)).toEqual(120n);
|
||||
expect(heronsFormulaBI(13n, 37n, 30n)).toEqual(180n);
|
||||
expect(heronsFormulaBI(6n, 25n, 29n)).toEqual(60n);
|
||||
expect(heronsFormulaBI(73n, 9n, 80n)).toEqual(216n);
|
||||
expect(heronsFormulaBI(12n, 35n, 37n)).toEqual(210n);
|
||||
expect(heronsFormulaBI(120n, 109n, 13n)).toEqual(396n);
|
||||
expect(heronsFormulaBI(9n, 10n, 17n)).toEqual(36n);
|
||||
});
|
||||
});
|
||||
33
node_modules/@gkucmierz/utils/spec/list-node.spec.mjs
generated
vendored
Normal file
33
node_modules/@gkucmierz/utils/spec/list-node.spec.mjs
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
|
||||
import { ListNode } from '../src/list-node.mjs';
|
||||
|
||||
describe('ListNode', () => {
|
||||
it('constructor', () => {
|
||||
expect(new ListNode().val).toEqual(0);
|
||||
expect(new ListNode().next).toEqual(null);
|
||||
expect(new ListNode(123).val).toEqual(123);
|
||||
expect(new ListNode(123).next).toEqual(null);
|
||||
expect(new ListNode(123, 'next').next).toEqual('next');
|
||||
});
|
||||
|
||||
it('toArr', () => {
|
||||
expect(new ListNode().toArr()).toEqual([0]);
|
||||
expect(new ListNode(123).toArr()).toEqual([123]);
|
||||
expect(new ListNode(1, new ListNode(2)).toArr()).toEqual([1, 2]);
|
||||
});
|
||||
|
||||
it('fromArr', () => {
|
||||
expect(ListNode.fromArr([1, 2])).toEqual(new ListNode(1, new ListNode(2)));
|
||||
});
|
||||
|
||||
it('both', () => {
|
||||
const arr = [1, 2, 3, 4, 5];
|
||||
expect(ListNode.fromArr(arr).toArr()).toEqual(arr);
|
||||
});
|
||||
|
||||
it('cyclic reference', () => {
|
||||
const node = ListNode.fromArr([1, 2]);
|
||||
node.next.next = node;
|
||||
expect(() => node.toArr()).toThrow(new Error('Cyclic reference detected'));
|
||||
});
|
||||
});
|
||||
8
node_modules/@gkucmierz/utils/spec/main.spec.mjs
generated
vendored
Normal file
8
node_modules/@gkucmierz/utils/spec/main.spec.mjs
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
import * as all from '../main.mjs';
|
||||
|
||||
describe('main', () => {
|
||||
it('default', () => {
|
||||
expect(all.default).toBeDefined();
|
||||
});
|
||||
});
|
||||
19
node_modules/@gkucmierz/utils/spec/matrix.spec.mjs
generated
vendored
Normal file
19
node_modules/@gkucmierz/utils/spec/matrix.spec.mjs
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
import {
|
||||
matrixAsArray,
|
||||
} from '../src/matrix.mjs';
|
||||
|
||||
describe('matrix', () => {
|
||||
it('matrixAsArray', () => {
|
||||
const m = [
|
||||
[1, 2],
|
||||
[3, 4],
|
||||
];
|
||||
const arr = matrixAsArray(m);
|
||||
expect(arr.length).toBe(4);
|
||||
expect(arr[0]).toBe(1);
|
||||
expect(arr[1]).toBe(2);
|
||||
expect(arr[2]).toBe(3);
|
||||
expect(arr[3]).toBe(4);
|
||||
});
|
||||
});
|
||||
46
node_modules/@gkucmierz/utils/spec/memoize.spec.mjs
generated
vendored
Normal file
46
node_modules/@gkucmierz/utils/spec/memoize.spec.mjs
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
|
||||
import {
|
||||
memoize,
|
||||
} from '../src/memoize.mjs';
|
||||
|
||||
describe('memoize', () => {
|
||||
it('called once', () => {
|
||||
let cnt = 0;
|
||||
const add = memoize((a, b) => {
|
||||
++cnt;
|
||||
return a + b;
|
||||
});
|
||||
|
||||
expect(add(1, 2)).toBe(3);
|
||||
expect(cnt).toBe(1);
|
||||
expect(add(1, 2)).toBe(3);
|
||||
expect(cnt).toBe(1);
|
||||
|
||||
expect(add(2, 1)).toBe(3);
|
||||
expect(cnt).toBe(2);
|
||||
});
|
||||
|
||||
it('variable args length', () => {
|
||||
const fn = memoize((...args) => args.length);
|
||||
|
||||
expect(fn()).toBe(0);
|
||||
expect(fn(1)).toBe(1);
|
||||
expect(fn(1, 2)).toBe(2);
|
||||
expect(fn(1, 2, 3)).toBe(3);
|
||||
});
|
||||
|
||||
it('different empty object arrays', () => {
|
||||
let cnt = 0;
|
||||
const fn = memoize(() => ++cnt);
|
||||
const emptyArr = [];
|
||||
fn(emptyArr);
|
||||
expect(cnt).toBe(1);
|
||||
fn(emptyArr);
|
||||
expect(cnt).toBe(1);
|
||||
fn([]);
|
||||
expect(cnt).toBe(2);
|
||||
fn([]);
|
||||
expect(cnt).toBe(3);
|
||||
});
|
||||
});
|
||||
|
||||
39
node_modules/@gkucmierz/utils/spec/mod.spec.mjs
generated
vendored
Normal file
39
node_modules/@gkucmierz/utils/spec/mod.spec.mjs
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
import {
|
||||
mod,
|
||||
modBI,
|
||||
} from '../src/mod.mjs';
|
||||
|
||||
describe('mod', () => {
|
||||
it('mod', () => {
|
||||
expect(mod(4, 100)).toEqual(4);
|
||||
expect(mod(104, 100)).toEqual(4);
|
||||
expect(mod(4 - 100, 100)).toEqual(4);
|
||||
expect(mod(4 + 96, 100)).toEqual(0);
|
||||
expect(mod(-4 - 96, 100)).toEqual(0);
|
||||
});
|
||||
|
||||
it('mod sign', () => {
|
||||
expect(mod(4, 100)).toEqual(4);
|
||||
expect(mod(-4, 100)).toEqual(96);
|
||||
expect(mod(4, -100)).toEqual(-96);
|
||||
expect(mod(-4, -100)).toEqual(-4);
|
||||
});
|
||||
});
|
||||
|
||||
describe('mod BI', () => {
|
||||
it('mod', () => {
|
||||
expect(modBI(4n, 100n)).toEqual(4n);
|
||||
expect(modBI(104n, 100n)).toEqual(4n);
|
||||
expect(modBI(4n - 100n, 100n)).toEqual(4n);
|
||||
expect(modBI(4n + 96n, 100n)).toEqual(0n);
|
||||
expect(modBI(-4n - 96n, 100n)).toEqual(0n);
|
||||
});
|
||||
|
||||
it('mod sign', () => {
|
||||
expect(modBI(4n, 100n)).toEqual(4n);
|
||||
expect(modBI(-4n, 100n)).toEqual(96n);
|
||||
expect(modBI(4n, -100n)).toEqual(-96n);
|
||||
expect(modBI(-4n, -100n)).toEqual(-4n);
|
||||
});
|
||||
});
|
||||
60
node_modules/@gkucmierz/utils/spec/phi.spec.mjs
generated
vendored
Normal file
60
node_modules/@gkucmierz/utils/spec/phi.spec.mjs
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
|
||||
import {
|
||||
phi,
|
||||
phiBI,
|
||||
} from '../src/phi.mjs';
|
||||
|
||||
describe('phi', () => {
|
||||
it('Number x1', () => {
|
||||
expect(phi(1)).toBe(1);
|
||||
expect(phi(11)).toBe(10);
|
||||
expect(phi(21)).toBe(12);
|
||||
expect(phi(31)).toBe(30);
|
||||
expect(phi(41)).toBe(40);
|
||||
expect(phi(51)).toBe(32);
|
||||
expect(phi(61)).toBe(60);
|
||||
expect(phi(71)).toBe(70);
|
||||
expect(phi(81)).toBe(54);
|
||||
expect(phi(91)).toBe(72);
|
||||
});
|
||||
|
||||
it('Number x5', () => {
|
||||
expect(phi(5)).toBe(4);
|
||||
expect(phi(15)).toBe(8);
|
||||
expect(phi(25)).toBe(20);
|
||||
expect(phi(35)).toBe(24);
|
||||
expect(phi(45)).toBe(24);
|
||||
expect(phi(55)).toBe(40);
|
||||
expect(phi(65)).toBe(48);
|
||||
expect(phi(75)).toBe(40);
|
||||
expect(phi(85)).toBe(64);
|
||||
expect(phi(95)).toBe(72);
|
||||
});
|
||||
|
||||
it('BigInt x1', () => {
|
||||
expect(phiBI(1n)).toBe(1n);
|
||||
expect(phiBI(11n)).toBe(10n);
|
||||
expect(phiBI(21n)).toBe(12n);
|
||||
expect(phiBI(31n)).toBe(30n);
|
||||
expect(phiBI(41n)).toBe(40n);
|
||||
expect(phiBI(51n)).toBe(32n);
|
||||
expect(phiBI(61n)).toBe(60n);
|
||||
expect(phiBI(71n)).toBe(70n);
|
||||
expect(phiBI(81n)).toBe(54n);
|
||||
expect(phiBI(91n)).toBe(72n);
|
||||
});
|
||||
|
||||
it('BigInt x5', () => {
|
||||
expect(phiBI(5n)).toBe(4n);
|
||||
expect(phiBI(15n)).toBe(8n);
|
||||
expect(phiBI(25n)).toBe(20n);
|
||||
expect(phiBI(35n)).toBe(24n);
|
||||
expect(phiBI(45n)).toBe(24n);
|
||||
expect(phiBI(55n)).toBe(40n);
|
||||
expect(phiBI(65n)).toBe(48n);
|
||||
expect(phiBI(75n)).toBe(40n);
|
||||
expect(phiBI(85n)).toBe(64n);
|
||||
expect(phiBI(95n)).toBe(72n);
|
||||
});
|
||||
});
|
||||
|
||||
21
node_modules/@gkucmierz/utils/spec/pow-mod.spec.mjs
generated
vendored
Normal file
21
node_modules/@gkucmierz/utils/spec/pow-mod.spec.mjs
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
import {
|
||||
powMod,
|
||||
powModBI,
|
||||
} from '../src/pow-mod.mjs';
|
||||
|
||||
describe('pow-mod', () => {
|
||||
it('powMod', () => {
|
||||
expect(powMod(2, 1)).toEqual(2);
|
||||
expect(powMod(2, 1, 10)).toEqual(2);
|
||||
expect(powMod(2, 1, 2)).toEqual(0);
|
||||
expect(powMod(2, 0, 2)).toEqual(1);
|
||||
});
|
||||
|
||||
it('powModBI', () => {
|
||||
expect(powModBI(2n, 1n)).toEqual(2n);
|
||||
expect(powModBI(2n, 1n, 10n)).toEqual(2n);
|
||||
expect(powModBI(2n, 1n, 2n)).toEqual(0n);
|
||||
expect(powModBI(2n, 0n, 2n)).toEqual(1n);
|
||||
});
|
||||
});
|
||||
19
node_modules/@gkucmierz/utils/spec/range-array.spec.mjs
generated
vendored
Normal file
19
node_modules/@gkucmierz/utils/spec/range-array.spec.mjs
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
import {
|
||||
range2array,
|
||||
array2range,
|
||||
} from '../src/range-array.mjs';
|
||||
|
||||
describe('range-array', () => {
|
||||
it('array2range', () => {
|
||||
expect(array2range([])).toEqual([]);
|
||||
expect(array2range([1,3,4,5,7,9,10])).toEqual([[1,1],[3,5],[7,7],[9,10]]);
|
||||
expect(array2range([10,12,13,14,15,16,17,20,22,23,27])).toEqual([[10,10],[12,17],[20,20],[22,23],[27,27]]);
|
||||
});
|
||||
|
||||
it('range2array', () => {
|
||||
expect(range2array([])).toEqual([]);
|
||||
expect(range2array([[1],[3,5],[7],[9,10]])).toEqual([1,3,4,5,7,9,10]);
|
||||
expect(range2array([[10],[12,17],[20],[22,23],[27]])).toEqual([10,12,13,14,15,16,17,20,22,23,27]);
|
||||
});
|
||||
});
|
||||
22
node_modules/@gkucmierz/utils/spec/square-root.spec.mjs
generated
vendored
Normal file
22
node_modules/@gkucmierz/utils/spec/square-root.spec.mjs
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
import {
|
||||
squareRoot,
|
||||
squareRootBI,
|
||||
} from '../src/square-root.mjs';
|
||||
|
||||
describe('square-root', () => {
|
||||
it('squareRootBI small', () => {
|
||||
expect(squareRootBI(0n)).toEqual(0n);
|
||||
expect(squareRootBI(1n)).toEqual(1n);
|
||||
expect(squareRootBI(2n)).toEqual(1n);
|
||||
expect(squareRootBI(3n)).toEqual(1n);
|
||||
expect(squareRootBI(4n)).toEqual(2n);
|
||||
});
|
||||
|
||||
it('squareRootBI 0-1e3', () => {
|
||||
for (let i = 0; i < 1e3; ++i) {
|
||||
const sqf = BigInt(Math.floor(i ** 0.5));
|
||||
expect(squareRootBI(BigInt(i))).toEqual(sqf);
|
||||
}
|
||||
});
|
||||
});
|
||||
16
node_modules/@gkucmierz/utils/spec/support/jasmine.json
generated
vendored
Normal file
16
node_modules/@gkucmierz/utils/spec/support/jasmine.json
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"spec_dir": "spec",
|
||||
"spec_files": [
|
||||
"**/*[sS]pec.?(m)js"
|
||||
],
|
||||
"helpers": [
|
||||
"helpers/**/*.?(m)js"
|
||||
],
|
||||
"env": {
|
||||
"stopSpecOnExpectationFailure": false,
|
||||
"random": true
|
||||
},
|
||||
"client": {
|
||||
"captureConsole": false
|
||||
}
|
||||
}
|
||||
15
node_modules/@gkucmierz/utils/spec/tonelli-shanks.spec.mjs
generated
vendored
Normal file
15
node_modules/@gkucmierz/utils/spec/tonelli-shanks.spec.mjs
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
import {
|
||||
tonelliShanksBI,
|
||||
} from '../src/tonelli-shanks.mjs';
|
||||
|
||||
describe('tonelli-shanks', () => {
|
||||
it('tonelliShanksBI', () => {
|
||||
const a = 8479994658316772151941616510097127087554541274812435112009425778595495359700244470400642403747058566807127814165396640215844192327900454116257979487432016769329970767046735091249898678088061634796559556704959846424131820416048436501387617211770124292793308079214153179977624440438616958575058361193975686620046439877308339989295604537867493683872778843921771307305602776398786978353866231661453376056771972069776398999013769588936194859344941268223184197231368887060609212875507518936172060702209557124430477137421847130682601666968691651447236917018634902407704797328509461854842432015009878011354022108661461024768n;
|
||||
const p = 30531851861994333252675935111487950694414332763909083514133769861350960895076504687261369815735742549428789138300843082086550059082835141454526618160634109969195486322015775943030060449557090064811940139431735209185996454739163555910726493597222646855506445602953689527405362207926990442391705014604777038685880527537489845359101552442292804398472642356609304810680731556542002301547846635101455995732584071355903010856718680732337369128498655255277003643669031694516851390505923416710601212618443109844041514942401969629158975457079026906304328749039997262960301209158175920051890620947063936347307238412281568760161n;
|
||||
const r = tonelliShanksBI(a, p);
|
||||
|
||||
expect((r * r) % p).toEqual(a);
|
||||
});
|
||||
|
||||
});
|
||||
64
node_modules/@gkucmierz/utils/src/SetCnt.mjs
generated
vendored
Normal file
64
node_modules/@gkucmierz/utils/src/SetCnt.mjs
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
// set-like data structure built using map
|
||||
// with elements counter.
|
||||
// .delete - removes one element
|
||||
// .deleteAll - removes all occurrences
|
||||
// .cnt - get element occurrences
|
||||
|
||||
export class SetCnt {
|
||||
#map = new Map();
|
||||
|
||||
constructor(iter) {
|
||||
for (const el of iter ?? []) {
|
||||
this.add(el);
|
||||
}
|
||||
}
|
||||
|
||||
add(el) {
|
||||
const cnt = this.cnt(el);
|
||||
this.#map.set(el, cnt + 1);
|
||||
return this;
|
||||
}
|
||||
|
||||
has(el) {
|
||||
return this.#map.has(el);
|
||||
}
|
||||
|
||||
delete(el) {
|
||||
if (!this.#map.has(el)) return false;
|
||||
const cnt = this.cnt(el);
|
||||
if (cnt === 1) return this.deleteAll(el);
|
||||
this.#map.set(el, cnt - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
deleteAll(el) {
|
||||
this.#map.delete(el);
|
||||
return true;
|
||||
}
|
||||
|
||||
cnt(el) {
|
||||
return this.#map.get(el) ?? 0;
|
||||
}
|
||||
|
||||
*[Symbol.iterator]() {
|
||||
for (const el of this.#map) {
|
||||
yield el;
|
||||
}
|
||||
}
|
||||
|
||||
entries() {
|
||||
return this;
|
||||
}
|
||||
|
||||
*values() {
|
||||
for (const [el, cnt] of this.#map) {
|
||||
yield el;
|
||||
}
|
||||
}
|
||||
|
||||
*keys() {
|
||||
for (const [el, cnt] of this.#map) {
|
||||
yield cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
78
node_modules/@gkucmierz/utils/src/Trie.mjs
generated
vendored
Normal file
78
node_modules/@gkucmierz/utils/src/Trie.mjs
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
|
||||
// stric = true - remove removes whole unused data structure
|
||||
// stric = false - quick remove (data structure can grow fast)
|
||||
export const Trie = (words = [], strict = true) => {
|
||||
const HAS = 0;
|
||||
const MAP = 1;
|
||||
const data = [false, new Map()];
|
||||
const add = word => {
|
||||
let node = data;
|
||||
for (let i = 0; i < word.length; ++i) {
|
||||
const char = word[i];
|
||||
if (!node[MAP]) node[MAP] = new Map();
|
||||
const child = node[MAP].get(char) ?? [false];
|
||||
node[MAP].set(char, child);
|
||||
node = child;
|
||||
}
|
||||
if (node[HAS]) return false;
|
||||
node[HAS] = true;
|
||||
return true;
|
||||
};
|
||||
const listNodes = word => {
|
||||
const nodes = [data];
|
||||
for (let i = 0; i < word.length; ++i) {
|
||||
const node = nodes.at(-1);
|
||||
const char = word[i];
|
||||
if (!node[MAP]?.has(char)) {
|
||||
nodes.push([false]);
|
||||
break;
|
||||
}
|
||||
nodes.push(node[MAP].get(char));
|
||||
}
|
||||
return nodes;
|
||||
};
|
||||
const findNode = word => {
|
||||
return listNodes(word).at(-1);
|
||||
};
|
||||
const remove = word => {
|
||||
const nodes = listNodes(word);
|
||||
const rev = nodes.reverse();
|
||||
const removed = rev.at(0)[HAS];
|
||||
rev.at(0)[HAS] = false;
|
||||
if (!strict) return removed;
|
||||
for (let i = 0; i < rev.length; ++i) {
|
||||
const node = rev[i];
|
||||
const first = i === 0;
|
||||
const noMap = !node[MAP];
|
||||
const size1 = node[MAP]?.size <= 1;
|
||||
if (first) {
|
||||
if (node[MAP]) break;
|
||||
} else {
|
||||
if (node[MAP]?.size <= 1) {
|
||||
delete node[MAP];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (node[HAS]) break;
|
||||
}
|
||||
return removed;
|
||||
};
|
||||
const has = word => findNode(word)[HAS];
|
||||
const get = begin => {
|
||||
const res = [];
|
||||
const loop = (node, str = '') => {
|
||||
if (!node) return;
|
||||
if (node[HAS]) res.push(begin + str);
|
||||
const map = node[MAP] || new Map();
|
||||
[...map].map(([char, node]) => loop(node, str + char));
|
||||
};
|
||||
loop(findNode(begin));
|
||||
return res;
|
||||
};
|
||||
words.map(word => add(word));
|
||||
return {
|
||||
add, has, get, remove,
|
||||
getData: () => data,
|
||||
};
|
||||
};
|
||||
33
node_modules/@gkucmierz/utils/src/base64.mjs
generated
vendored
Normal file
33
node_modules/@gkucmierz/utils/src/base64.mjs
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
|
||||
export const toBase64 = string => {
|
||||
const codeUnits = new Uint16Array(string.length);
|
||||
for (let i = 0; i < codeUnits.length; i++) {
|
||||
codeUnits[i] = string.charCodeAt(i);
|
||||
}
|
||||
return btoa(String.fromCharCode(...new Uint8Array(codeUnits.buffer)));
|
||||
};
|
||||
|
||||
export const fromBase64 = encoded => {
|
||||
const binary = atob(encoded);
|
||||
const bytes = new Uint8Array(binary.length);
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
bytes[i] = binary.charCodeAt(i);
|
||||
}
|
||||
return String.fromCharCode(...new Uint16Array(bytes.buffer));
|
||||
};
|
||||
|
||||
const toUrl = {
|
||||
'+': '-',
|
||||
'/': '_',
|
||||
};
|
||||
export const toBase64Url = string => {
|
||||
return toBase64(string).replace(/[\+\/]/g, c => toUrl[c]);
|
||||
};
|
||||
|
||||
const fromUrl = {
|
||||
'-': '+',
|
||||
'_': '/',
|
||||
};
|
||||
export const fromBase64Url = encoded => {
|
||||
return fromBase64(encoded.replace(/[\-\_]/g, c => fromUrl[c]));
|
||||
};
|
||||
54
node_modules/@gkucmierz/utils/src/bijective-numeration.mjs
generated
vendored
Normal file
54
node_modules/@gkucmierz/utils/src/bijective-numeration.mjs
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
|
||||
export const num2bijective = (num, alpha = '12') => {
|
||||
const len = alpha.length;
|
||||
let c = 0;
|
||||
let x = 1;
|
||||
while (num >= x) {
|
||||
c++;
|
||||
num -= x;
|
||||
x *= len;
|
||||
}
|
||||
const res = [];
|
||||
for (let i = 0; i < c; i++) {
|
||||
const rem = num % len;
|
||||
res.unshift(alpha.charAt(num % len));
|
||||
num = (num - rem) / len;
|
||||
}
|
||||
return res.join('');
|
||||
};
|
||||
|
||||
export const bijective2num = (str, alpha = '12') => {
|
||||
const map = new Map([...alpha].map((c, i) => [c, i]));
|
||||
let res = 0;
|
||||
const len = alpha.length;
|
||||
return [...str].reduce((res, c) => {
|
||||
return res * len + map.get(c) + 1;
|
||||
}, 0);
|
||||
};
|
||||
|
||||
export const num2bijectiveBI = (num, alpha = '12') => {
|
||||
const len = BigInt(alpha.length);
|
||||
let c = 0n;
|
||||
let x = 1n;
|
||||
while (num >= x) {
|
||||
c++;
|
||||
num -= x;
|
||||
x *= len;
|
||||
}
|
||||
const res = [];
|
||||
for (let i = 0n; i < c; i++) {
|
||||
const rem = num % len;
|
||||
res.unshift(alpha.charAt(Number(num % len)));
|
||||
num = (num - rem) / len;
|
||||
}
|
||||
return res.join('');
|
||||
};
|
||||
|
||||
export const bijective2numBI = (str, alpha = '12') => {
|
||||
const map = new Map([...alpha].map((c, i) => [c, BigInt(i)]));
|
||||
let res = 0n;
|
||||
const len = BigInt(alpha.length);
|
||||
return [...str].reduce((res, c) => {
|
||||
return res * len + map.get(c) + 1n;
|
||||
}, 0n);
|
||||
};
|
||||
101
node_modules/@gkucmierz/utils/src/binary-search.mjs
generated
vendored
Normal file
101
node_modules/@gkucmierz/utils/src/binary-search.mjs
generated
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
|
||||
// binary search array exact element
|
||||
// in sorted array
|
||||
export const binarySearchArr = (arr, target) => {
|
||||
let [a, b] = [0, arr.length];
|
||||
let lm;
|
||||
while (b - a > 0) {
|
||||
const mid = (a + b) / 2 | 0;
|
||||
const val = arr[mid];
|
||||
if (target < val) {
|
||||
b = mid;
|
||||
} else if (val < target) {
|
||||
a = mid;
|
||||
} else {
|
||||
return mid;
|
||||
}
|
||||
if (lm === mid) break;
|
||||
lm = mid;
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
// binary search array less or equal element
|
||||
export const binarySearchLE = (arr, target) => {
|
||||
let [a, b] = [0, arr.length];
|
||||
let lm;
|
||||
while (b - a > 0) {
|
||||
const mid = (a + b) / 2 | 0;
|
||||
const val = arr[mid];
|
||||
if (target < val) {
|
||||
b = mid;
|
||||
} else if (val <= target) {
|
||||
a = mid;
|
||||
}
|
||||
if (lm === mid) return mid;
|
||||
lm = mid;
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
// binary search array greater or equal element
|
||||
export const binarySearchGE = (arr, target) => {
|
||||
let [a, b] = [0, arr.length];
|
||||
let lm;
|
||||
while (b - a > 0) {
|
||||
const mid = (a + b) / 2 | 0;
|
||||
const val = arr[mid];
|
||||
if (target > val) {
|
||||
a = mid;
|
||||
} else if (val >= target) {
|
||||
b = mid;
|
||||
}
|
||||
if (lm === mid) return mid + 1;
|
||||
lm = mid;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
// binary search for range of elements in array inclusive
|
||||
export const binarySearchRangeIncl = (arr, target) => {
|
||||
return [
|
||||
binarySearchGE(arr, target),
|
||||
binarySearchLE(arr, target),
|
||||
];
|
||||
};
|
||||
|
||||
// binary search array less element
|
||||
const binarySearchL = (arr, target) => {
|
||||
let [a, b] = [0, arr.length];
|
||||
let lm;
|
||||
while (b - a > 0) {
|
||||
const mid = (a + b) / 2 | 0;
|
||||
const val = arr[mid];
|
||||
if (target <= val) {
|
||||
b = mid;
|
||||
} else if (val < target) {
|
||||
a = mid;
|
||||
}
|
||||
if (lm === mid) return mid;
|
||||
lm = mid;
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
// binary search array greater element
|
||||
const binarySearchG = (arr, target) => {
|
||||
let [a, b] = [0, arr.length];
|
||||
let lm;
|
||||
while (b - a > 0) {
|
||||
const mid = (a + b) / 2 | 0;
|
||||
const val = arr[mid];
|
||||
if (target >= val) {
|
||||
a = mid;
|
||||
} else if (val > target) {
|
||||
b = mid;
|
||||
}
|
||||
if (lm === mid) return mid + 1;
|
||||
lm = mid;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
18
node_modules/@gkucmierz/utils/src/copy-case.mjs
generated
vendored
Normal file
18
node_modules/@gkucmierz/utils/src/copy-case.mjs
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
/**
|
||||
* Copy the case of a string into another.
|
||||
* @method
|
||||
* @param {string} target String to change the case.
|
||||
* @param {string} source Source of case pattern.
|
||||
* @return {string} Converted string.
|
||||
*/
|
||||
export const copyCase = (word, from) => {
|
||||
const isLower = w => w.toLowerCase() === w;
|
||||
const isUpper = w => w.toUpperCase() === w;
|
||||
if (isLower(from)) return word.toLowerCase();
|
||||
if (isUpper(from)) return word.toUpperCase();
|
||||
if (isUpper(from[0]) && isLower(from.slice(1))) {
|
||||
return word[0].toUpperCase() + word.slice(1).toLowerCase();
|
||||
}
|
||||
return word;
|
||||
};
|
||||
11
node_modules/@gkucmierz/utils/src/egcd.mjs
generated
vendored
Normal file
11
node_modules/@gkucmierz/utils/src/egcd.mjs
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
export const egcd = (a, b) => {
|
||||
let [x, y] = [0, 1];
|
||||
let [u, v] = [1, 0];
|
||||
while (a !== 0) {
|
||||
const [q, r] = [b/a | 0, b%a];
|
||||
const [m, n] = [x - u * q, y - v * q];
|
||||
[b, a, x, y, u, v] = [a, r, u, v, m, n];
|
||||
}
|
||||
return [b, x, y];
|
||||
};
|
||||
42
node_modules/@gkucmierz/utils/src/factors.mjs
generated
vendored
Normal file
42
node_modules/@gkucmierz/utils/src/factors.mjs
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
|
||||
/**
|
||||
* Prime factorization
|
||||
* @function
|
||||
* @param {Number} number
|
||||
* @return {Number} result
|
||||
*/
|
||||
export const factors = n => {
|
||||
if (n < 2) return [];
|
||||
const res = [];
|
||||
let max = Math.floor(Math.sqrt(n));
|
||||
for (let i = 2; i <= max; ++i) {
|
||||
if (n % i === 0) {
|
||||
res.push(i);
|
||||
n /= i;
|
||||
max = Math.floor(Math.sqrt(n));
|
||||
i = (Math.min(...res) || 2) - 1;
|
||||
}
|
||||
}
|
||||
res.push(n);
|
||||
return res;
|
||||
};
|
||||
|
||||
/**
|
||||
* Prime factorization (BigInt version)
|
||||
* @function
|
||||
* @param {BigInt} number
|
||||
* @return {BigInt} result
|
||||
*/
|
||||
export const factorsBI = n => {
|
||||
if (n < 2n) return [];
|
||||
const res = [];
|
||||
for (let i = 2n; i * i <= n; ++i) {
|
||||
if (n % i === 0n) {
|
||||
res.push(i);
|
||||
n /= i;
|
||||
i = 1n;
|
||||
}
|
||||
}
|
||||
res.push(n);
|
||||
return res;
|
||||
};
|
||||
32
node_modules/@gkucmierz/utils/src/gcd.mjs
generated
vendored
Normal file
32
node_modules/@gkucmierz/utils/src/gcd.mjs
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
const getGCD = ZERO => {
|
||||
return (a, b) => {
|
||||
if (a < ZERO) a = -a;
|
||||
if (b < ZERO) b = -b;
|
||||
if (b > a) {
|
||||
[a, b] = [b, a];
|
||||
}
|
||||
while (true) {
|
||||
if (b === ZERO) return a;
|
||||
a %= b;
|
||||
if (a === ZERO) return b;
|
||||
b %= a;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate GCD - Greatest Common Divisor
|
||||
* @method
|
||||
* @param {Number} Natural number
|
||||
* @return {Number} GCD
|
||||
*/
|
||||
export const gcd = getGCD(0);
|
||||
|
||||
/**
|
||||
* Calculate GCD - Greatest Common Divisor (BigInt version)
|
||||
* @method
|
||||
* @param {BigInt} Natural BigInt number
|
||||
* @return {BigInt} GCD
|
||||
*/
|
||||
export const gcdBI = getGCD(0n);
|
||||
7
node_modules/@gkucmierz/utils/src/get-type.mjs
generated
vendored
Normal file
7
node_modules/@gkucmierz/utils/src/get-type.mjs
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
// better js typeof
|
||||
|
||||
export const getType = val => {
|
||||
const str = Object.prototype.toString.call(val);
|
||||
return str.slice(8, -1).toLowerCase();
|
||||
};
|
||||
14
node_modules/@gkucmierz/utils/src/gpn.mjs
generated
vendored
Normal file
14
node_modules/@gkucmierz/utils/src/gpn.mjs
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
// Generalized pentagonal numbers
|
||||
// https://oeis.org/A001318
|
||||
|
||||
const getGpn = (zero, one, two, three) => {
|
||||
const gk = k => k * (three * k - one) / two;
|
||||
return n => {
|
||||
const m = (n + one) / two | zero;
|
||||
return n % two === zero ? gk(-m) : gk(m);
|
||||
};
|
||||
};
|
||||
|
||||
export const gpn = getGpn(0, 1, 2, 3);
|
||||
export const gpnBI = getGpn(0n, 1n, 2n, 3n);
|
||||
46
node_modules/@gkucmierz/utils/src/heap.mjs
generated
vendored
Normal file
46
node_modules/@gkucmierz/utils/src/heap.mjs
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
|
||||
export const Heap = (valFn = n => n) => {
|
||||
const arr = [-1];
|
||||
|
||||
const up = idx => {
|
||||
while (idx > 1) {
|
||||
const ni = idx / 2 | 0;
|
||||
if (valFn(arr[idx]) < valFn(arr[ni])) {
|
||||
[arr[idx], arr[ni]] = [arr[ni], arr[idx]];
|
||||
}
|
||||
idx = ni;
|
||||
}
|
||||
return idx;
|
||||
};
|
||||
|
||||
return {
|
||||
add: el => up(arr.push(el) - 1),
|
||||
take: () => {
|
||||
const len = arr.length;
|
||||
if (len <= 1) return [][0];
|
||||
let idx = 1;
|
||||
const res = arr[idx];
|
||||
while (idx < len) {
|
||||
const ia = idx * 2;
|
||||
const ib = idx * 2 + 1;
|
||||
if (ia >= len) break;
|
||||
if (ib >= len || valFn(arr[ia]) < valFn(arr[ib])) {
|
||||
arr[idx] = arr[ia];
|
||||
idx = ia;
|
||||
} else {
|
||||
arr[idx] = arr[ib];
|
||||
idx = ib;
|
||||
}
|
||||
}
|
||||
if (idx === arr.length - 1) {
|
||||
arr.pop();
|
||||
} else {
|
||||
arr[idx] = arr.pop();
|
||||
up(idx);
|
||||
}
|
||||
return res;
|
||||
},
|
||||
size: () => arr.length - 1,
|
||||
data: () => arr.slice(1),
|
||||
};
|
||||
};
|
||||
13
node_modules/@gkucmierz/utils/src/herons-formula.mjs
generated
vendored
Normal file
13
node_modules/@gkucmierz/utils/src/herons-formula.mjs
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
import {
|
||||
squareRootBI,
|
||||
} from './square-root.mjs';
|
||||
|
||||
// calculate triangle area given 3 sides
|
||||
|
||||
const getHeronsFormula = (four, sq) => (a, b, c) => {
|
||||
return sq((a + b + c) * (-a + b + c) * (a - b + c) * (a + b - c)) / four;
|
||||
};
|
||||
|
||||
export const heronsFormula = getHeronsFormula(4, n => n ** 0.5);
|
||||
export const heronsFormulaBI = getHeronsFormula(4n, squareRootBI);
|
||||
14
node_modules/@gkucmierz/utils/src/lcm.mjs
generated
vendored
Normal file
14
node_modules/@gkucmierz/utils/src/lcm.mjs
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
import {
|
||||
gcd,
|
||||
gcdBI,
|
||||
} from './gcd.mjs';
|
||||
|
||||
// Least common multiple
|
||||
|
||||
const getLcm = gcd => {
|
||||
return (a, b) => a * b / gcd(a, b);
|
||||
}
|
||||
|
||||
export const lcm = getLcm(gcd);
|
||||
export const lcmBI = getLcm(gcdBI);
|
||||
31
node_modules/@gkucmierz/utils/src/list-node.mjs
generated
vendored
Normal file
31
node_modules/@gkucmierz/utils/src/list-node.mjs
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
|
||||
export class ListNode {
|
||||
constructor(val = 0, next = null) {
|
||||
this.val = val;
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
toArr() {
|
||||
const ret = [];
|
||||
let node = this;
|
||||
const set = new Set();
|
||||
while (node) {
|
||||
if (set.has(node)) throw Error('Cyclic reference detected');
|
||||
set.add(node);
|
||||
ret.push(node.val);
|
||||
node = node.next;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static fromArr(iter) {
|
||||
const head = new ListNode;
|
||||
let node = head;
|
||||
for (let val of iter) {
|
||||
node.next = new ListNode(val);
|
||||
node = node.next;
|
||||
}
|
||||
return head.next;
|
||||
}
|
||||
};
|
||||
17
node_modules/@gkucmierz/utils/src/matrix.mjs
generated
vendored
Normal file
17
node_modules/@gkucmierz/utils/src/matrix.mjs
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
|
||||
// represent matrix as array using Proxy
|
||||
// todo: iterator can be added
|
||||
|
||||
export const matrixAsArray = matrix => {
|
||||
const [h, w] = [matrix.length, matrix[0].length];
|
||||
return new Proxy([], {
|
||||
get(target, prop, receiver) {
|
||||
if (prop === 'length') return h * w;
|
||||
const idx = +prop;
|
||||
const col = idx % w;
|
||||
const row = (idx - col) / w;
|
||||
return matrix[row][col];
|
||||
}
|
||||
});
|
||||
};
|
||||
45
node_modules/@gkucmierz/utils/src/memoize.mjs
generated
vendored
Normal file
45
node_modules/@gkucmierz/utils/src/memoize.mjs
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
|
||||
/**
|
||||
* Memoize function, that builds tree structure for arguments
|
||||
* and compares arguments by reference
|
||||
* @method
|
||||
* @param {Function} Function to memoize
|
||||
* @return {Function} Memoized function
|
||||
*/
|
||||
export const memoize = fn => {
|
||||
const maps = [];
|
||||
|
||||
const getLeafMap = args => {
|
||||
if (!maps[args.length]) maps[args.length] = new Map();
|
||||
const map = maps[args.length];
|
||||
|
||||
const leaf = args.reduce((map, arg) => {
|
||||
if (map.has(arg)) return map.get(arg);
|
||||
const tmp = new Map();
|
||||
map.set(arg, tmp);
|
||||
return tmp;
|
||||
}, map);
|
||||
|
||||
return leaf;
|
||||
};
|
||||
|
||||
const zero = {
|
||||
called: false,
|
||||
ret: null,
|
||||
};
|
||||
|
||||
return function() {
|
||||
const args = [...arguments];
|
||||
if (args.length === 0) {
|
||||
if (zero.called) return zero.ret;
|
||||
zero.called = true;
|
||||
return zero.ret = fn();
|
||||
}
|
||||
const [firstArg, ...restArgs] = args;
|
||||
const map = getLeafMap(restArgs);
|
||||
if (map.has(firstArg)) return map.get(firstArg);
|
||||
const ret = fn(...args);
|
||||
map.set(firstArg, ret);
|
||||
return ret;
|
||||
};
|
||||
};
|
||||
32
node_modules/@gkucmierz/utils/src/mod.mjs
generated
vendored
Normal file
32
node_modules/@gkucmierz/utils/src/mod.mjs
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
const getMod = ZERO => {
|
||||
return (dividend, divisor) => {
|
||||
if ((dividend < ZERO) ^ (divisor < ZERO)) {
|
||||
const res = -dividend % divisor;
|
||||
return res === ZERO ? ZERO : divisor - res;
|
||||
}
|
||||
return dividend % divisor;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Python like modulo implementation.
|
||||
* It behaves different than JavaScript %
|
||||
* with negative values
|
||||
* @method
|
||||
* @param {Number} Dividend
|
||||
* @param {Number} Divisor
|
||||
* @return {Number} Modulus
|
||||
*/
|
||||
export const mod = getMod(0);
|
||||
|
||||
/**
|
||||
* Python like modulo implementation.
|
||||
* It behaves different than JavaScript %
|
||||
* with negative values
|
||||
* @method
|
||||
* @param {BigInt} Dividend
|
||||
* @param {BigInt} Divisor
|
||||
* @return {BigInt} Modulus
|
||||
*/
|
||||
export const modBI = getMod(0n);
|
||||
38
node_modules/@gkucmierz/utils/src/phi.mjs
generated
vendored
Normal file
38
node_modules/@gkucmierz/utils/src/phi.mjs
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
|
||||
import {
|
||||
gcd,
|
||||
gcdBI,
|
||||
} from './gcd.mjs';
|
||||
|
||||
import {
|
||||
factors,
|
||||
factorsBI,
|
||||
} from './factors.mjs';
|
||||
|
||||
// Euler's Totient Function
|
||||
|
||||
const getPhi = (ONE, TWO, gcd) => {
|
||||
return n => {
|
||||
let result = ONE;
|
||||
for (let i = TWO; i < n; ++i) {
|
||||
if (gcd(i, n) === ONE) {
|
||||
result++;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
// Eulers formula
|
||||
|
||||
const getPhiEuler = factors => {
|
||||
return n => {
|
||||
return [...new Set(factors(n))].reduce((res, f) => res - res / f, n);
|
||||
};
|
||||
};
|
||||
|
||||
export const phi = getPhiEuler(factors);
|
||||
export const phiBI = getPhiEuler(factorsBI);
|
||||
|
||||
// export const phi = getPhi(1, 2, gcd);
|
||||
// export const phiBI = getPhi(1n, 2n, gcdBI);
|
||||
39
node_modules/@gkucmierz/utils/src/pow-mod.mjs
generated
vendored
Normal file
39
node_modules/@gkucmierz/utils/src/pow-mod.mjs
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
// implementation of power function with modulus like native python pow
|
||||
|
||||
const getPowMod = (ZERO, ONE, TWO, floor) => {
|
||||
return (base, exponent, modulus = null) => {
|
||||
if (modulus === null) return base ** exponent;
|
||||
if (modulus === ONE) return ZERO;
|
||||
let result = ONE;
|
||||
base = base % modulus;
|
||||
while (exponent > ZERO) {
|
||||
if (exponent % TWO === ONE) {
|
||||
result = (result * base) % modulus;
|
||||
}
|
||||
exponent = floor(exponent / TWO);
|
||||
base = (base * base) % modulus;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Power like python implementation with optional modulus
|
||||
* @method
|
||||
* @param {Number} Base
|
||||
* @param {Number} Exponent
|
||||
* @param [Number] Modulus
|
||||
* @return {Number} Power
|
||||
*/
|
||||
export const powMod = getPowMod(0, 1, 2, n => Math.floor(n));
|
||||
|
||||
/**
|
||||
* Power like python implementation with optional modulus
|
||||
* @method
|
||||
* @param {BigInt} Base
|
||||
* @param {BigInt} Exponent
|
||||
* @param [BigInt] Modulus
|
||||
* @return {BigInt} Power
|
||||
*/
|
||||
export const powModBI = getPowMod(0n, 1n, 2n, n => n);
|
||||
27
node_modules/@gkucmierz/utils/src/range-array.mjs
generated
vendored
Normal file
27
node_modules/@gkucmierz/utils/src/range-array.mjs
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
// https://www.codewars.com/kata/57d83dfc950d842dcb00005b/train/javascript
|
||||
|
||||
export const range2array = ranges => {
|
||||
return ranges.reduce((arr, range) => {
|
||||
const min = range[0];
|
||||
const max = range[1] ?? min;
|
||||
return arr.push(
|
||||
...new Array(max - min + 1).fill(0).map((n ,i) => min + i)
|
||||
), arr;
|
||||
}, []);
|
||||
};
|
||||
|
||||
export const array2range = arr => {
|
||||
const ranges = [];
|
||||
let last = arr[0];
|
||||
let begin = last;
|
||||
for (let i = 1; i <= arr.length; ++i) {
|
||||
const n = arr[i];
|
||||
if (n !== last + 1) {
|
||||
ranges.push([begin, last]);
|
||||
begin = n;
|
||||
}
|
||||
last = n;
|
||||
}
|
||||
return ranges;
|
||||
};
|
||||
34
node_modules/@gkucmierz/utils/src/square-root.mjs
generated
vendored
Normal file
34
node_modules/@gkucmierz/utils/src/square-root.mjs
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
|
||||
/**
|
||||
* Native square root
|
||||
* @function
|
||||
* @param {Number} number - js double number
|
||||
* @return {Number} result
|
||||
*/
|
||||
export const squareRoot = n => n ** 0.5;
|
||||
|
||||
/**
|
||||
* Calculate square root using Newton's formula
|
||||
* @function
|
||||
* @param {BigInt} number - big integer number
|
||||
* @return {BigInt} result
|
||||
*/
|
||||
export const squareRootBI = n => {
|
||||
if (n === 0n) return 0n;
|
||||
if (n < 4n) return 1n;
|
||||
if (n < 9n) return 2n;
|
||||
if (n < 16n) return 3n;
|
||||
let res = BigInt(n.toString().substr(0, n.toString().length / 2));
|
||||
let last;
|
||||
while (true) {
|
||||
last = res;
|
||||
res = (res + n / res) / 2n;
|
||||
const p = res * res;
|
||||
if (p === n) return res;
|
||||
if (last === res) return res;
|
||||
const next = p + res * 2n - 1n;
|
||||
if (n > next) return res;
|
||||
}
|
||||
return res;
|
||||
};
|
||||
44
node_modules/@gkucmierz/utils/src/tonelli-shanks.mjs
generated
vendored
Normal file
44
node_modules/@gkucmierz/utils/src/tonelli-shanks.mjs
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
|
||||
import {
|
||||
powModBI,
|
||||
} from './pow-mod.mjs';
|
||||
|
||||
/* Takes as input an odd prime p and n < p and returns r
|
||||
* such that r * r = n [mod p]. */
|
||||
export const tonelliShanksBI = (n, p) => {
|
||||
let s = 0n;
|
||||
let q = p - 1n;
|
||||
while ((q & 1n) === 0n) {
|
||||
q /= 2n;
|
||||
++s;
|
||||
}
|
||||
if (s === 1n) {
|
||||
const r = powModBI(n, (p+1n) / 4n, p);
|
||||
if ((r * r) % p === n) return r;
|
||||
return 0n;
|
||||
}
|
||||
// Find the first quadratic non-residue z by brute-force search
|
||||
let z = 1n;
|
||||
while (powModBI(++z, (p-1n)/2n, p) !== p - 1n);
|
||||
let c = powModBI(z, q, p);
|
||||
let r = powModBI(n, (q+1n)/2n, p);
|
||||
let t = powModBI(n, q, p);
|
||||
let m = s;
|
||||
while (t !== 1n) {
|
||||
let tt = t;
|
||||
let i = 0n;
|
||||
while (tt !== 1n) {
|
||||
tt = (tt * tt) % p;
|
||||
++i;
|
||||
if (i === m) return 0n;
|
||||
}
|
||||
let b = powModBI(c, powModBI(2n, m-i-1n, p-1n), p);
|
||||
let b2 = (b * b) % p;
|
||||
r = (r * b) % p;
|
||||
t = (t * b2) % p;
|
||||
c = b2;
|
||||
m = i;
|
||||
}
|
||||
if ((r * r) % p === n) return r;
|
||||
return 0n;
|
||||
};
|
||||
Reference in New Issue
Block a user