Refactor: Implement SmartCube renderer, improve UI styling, and fix gaps

This commit is contained in:
2026-02-22 04:35:59 +00:00
parent 57abfd6b80
commit b5ddc21662
4168 changed files with 763782 additions and 1008 deletions

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

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

File diff suppressed because it is too large Load Diff

27
node_modules/@gkucmierz/utils/package.json generated vendored Normal file
View 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"
}
}

View 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
View 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
View 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
View 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('');
});
});

View 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);
}
});
});

View 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
View 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
View 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
View 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
View 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
View 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
View 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');
});
});

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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);
});
});

View 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]);
});
});

View 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);
}
});
});

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

View 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
View 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
View 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
View 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]));
};

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
};