Initial commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
node_modules/
|
||||||
11
README.md
Normal file
11
README.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# test-kata-machine
|
||||||
|
|
||||||
|
Kata machine practice.
|
||||||
|
|
||||||
|
https://frontendmasters.com/courses/algorithms/
|
||||||
|
|
||||||
|
https://github.com/ThePrimeagen/kata-machine
|
||||||
|
|
||||||
|
1. `pnpm install`
|
||||||
|
|
||||||
|
2. `pnpm test`
|
||||||
19
package.json
Normal file
19
package.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "test-kata-machine",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"scripts": {
|
||||||
|
"test": "vitest",
|
||||||
|
"format": "prettier --write ./src"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"vite": "^7.0.5",
|
||||||
|
"vitest": "^3.2.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"prettier": "^3.6.2",
|
||||||
|
"ts-node": "^10.9.2",
|
||||||
|
"tsconfig-paths": "^4.2.0",
|
||||||
|
"tsconfig-paths-jest": "^0.0.1",
|
||||||
|
"typescript": "^5.8.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
1666
pnpm-lock.yaml
generated
Normal file
1666
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
8
prettier.config.ts
Normal file
8
prettier.config.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export default {
|
||||||
|
tabWidth: 4,
|
||||||
|
printWidth: 80,
|
||||||
|
proseWrap: "never",
|
||||||
|
trailingComma: "all",
|
||||||
|
singleQuote: false,
|
||||||
|
semi: true,
|
||||||
|
};
|
||||||
101
src/array-test.ts
Normal file
101
src/array-test.ts
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
const a: number[] = [];
|
||||||
|
|
||||||
|
function time(fn: () => void): number {
|
||||||
|
const now = Date.now();
|
||||||
|
fn();
|
||||||
|
return Date.now() - now;
|
||||||
|
}
|
||||||
|
|
||||||
|
function unshift(number: number) {
|
||||||
|
for (let i = 0; i < number; ++i) {
|
||||||
|
a.unshift(Math.random());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function shift(number: number) {
|
||||||
|
for (let i = 0; i < number; ++i) {
|
||||||
|
a.shift();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function push(number: number) {
|
||||||
|
for (let i = 0; i < number; ++i) {
|
||||||
|
a.push(Math.random());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function pop(number: number) {
|
||||||
|
for (let i = 0; i < number; ++i) {
|
||||||
|
a.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function get(idx: number) {
|
||||||
|
return function () {
|
||||||
|
return a[idx];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function push_arr(count: number) {
|
||||||
|
return function () {
|
||||||
|
push(count);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function pop_arr(count: number) {
|
||||||
|
return function () {
|
||||||
|
pop(count);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function unshift_arr(count: number) {
|
||||||
|
return function () {
|
||||||
|
unshift(count);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function shift_arr(count: number) {
|
||||||
|
return function () {
|
||||||
|
shift(count);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const tests = [10, 100, 1000, 10000, 100000, 1_000_000, 10_000_000];
|
||||||
|
console.log("Testing get");
|
||||||
|
tests.forEach((t) => {
|
||||||
|
a.length = 0;
|
||||||
|
push(t);
|
||||||
|
console.log(t, time(get(t - 1)));
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("push");
|
||||||
|
tests.forEach((t) => {
|
||||||
|
a.length = 0;
|
||||||
|
push(t);
|
||||||
|
|
||||||
|
console.log(t, time(push_arr(1000)));
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("pop");
|
||||||
|
tests.forEach((t) => {
|
||||||
|
a.length = 0;
|
||||||
|
push(t);
|
||||||
|
|
||||||
|
console.log(t, time(pop_arr(1000)));
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("unshift");
|
||||||
|
tests.forEach((t) => {
|
||||||
|
a.length = 0;
|
||||||
|
push(t);
|
||||||
|
|
||||||
|
console.log(t, time(unshift_arr(1000)));
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("shift");
|
||||||
|
tests.forEach((t) => {
|
||||||
|
a.length = 0;
|
||||||
|
push(t);
|
||||||
|
|
||||||
|
console.log(t, time(shift_arr(1000)));
|
||||||
|
});
|
||||||
7
src/day1/ArrayList.test.ts
Normal file
7
src/day1/ArrayList.test.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import ArrayList from "@code/ArrayList";
|
||||||
|
import { test_list } from "./ListTest";
|
||||||
|
|
||||||
|
test("array-list", function () {
|
||||||
|
const list = new ArrayList<number>(3);
|
||||||
|
test_list(list);
|
||||||
|
});
|
||||||
93
src/day1/ArrayList.ts
Normal file
93
src/day1/ArrayList.ts
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
export default class ArrayList<T> {
|
||||||
|
public length: number;
|
||||||
|
private array: Array<T>;
|
||||||
|
private capacity: number;
|
||||||
|
|
||||||
|
constructor(capacity: number = 5) {
|
||||||
|
this.capacity = capacity;
|
||||||
|
this.array = [];
|
||||||
|
this.array.length = this.capacity;
|
||||||
|
this.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private grow() {
|
||||||
|
const old = this.array;
|
||||||
|
this.capacity *= 2;
|
||||||
|
this.array = [];
|
||||||
|
this.array.length = this.capacity;
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
for (; i < this.length; ++i) {
|
||||||
|
this.array[i] = old[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShiftRight manages the size of the array and shifts everything
|
||||||
|
// from array[idx] one to the right. Creating free space at array[idx].
|
||||||
|
private shiftRight(idx: number) {
|
||||||
|
if (this.length == this.capacity) {
|
||||||
|
this.grow();
|
||||||
|
}
|
||||||
|
|
||||||
|
let i = this.length;
|
||||||
|
for (; i > idx; --i) {
|
||||||
|
this.array[i] = this.array[i - 1];
|
||||||
|
}
|
||||||
|
this.length++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShiftLeft manages the size of the array and shifts everything to the
|
||||||
|
// right of array[idx] one to the left. Overwriting array[idx].
|
||||||
|
private ShiftLeft(idx: number) {
|
||||||
|
this.length--;
|
||||||
|
let i = idx;
|
||||||
|
for (; i < this.length; ++i) {
|
||||||
|
this.array[i] = this.array[i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prepend(item: T): void {
|
||||||
|
this.shiftRight(0);
|
||||||
|
this.array[0] = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
insertAt(item: T, idx: number): void {
|
||||||
|
this.shiftRight(idx);
|
||||||
|
this.array[idx] = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
append(item: T): void {
|
||||||
|
if (this.length == this.capacity) {
|
||||||
|
this.grow();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.array[this.length] = item;
|
||||||
|
this.length++;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(item: T): T | undefined {
|
||||||
|
let i = 0;
|
||||||
|
for (; i < this.length; ++i) {
|
||||||
|
if (this.array[i] == item) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// item was not found
|
||||||
|
if (i == this.length) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.removeAt(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
get(idx: number): T | undefined {
|
||||||
|
return idx >= this.length ? undefined : this.array[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
removeAt(idx: number): T | undefined {
|
||||||
|
const item = this.get(idx);
|
||||||
|
this.ShiftLeft(idx);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/day1/BFSGraphList.test.ts
Normal file
8
src/day1/BFSGraphList.test.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import bfs from "@code/BFSGraphList";
|
||||||
|
import { list2 } from "./graph";
|
||||||
|
|
||||||
|
test("bfs - graph", function () {
|
||||||
|
expect(bfs(list2, 0, 6)).toEqual([0, 1, 4, 5, 6]);
|
||||||
|
|
||||||
|
expect(bfs(list2, 6, 0)).toEqual(null);
|
||||||
|
});
|
||||||
45
src/day1/BFSGraphList.ts
Normal file
45
src/day1/BFSGraphList.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
export default function bfs(
|
||||||
|
graph: WeightedAdjacencyList,
|
||||||
|
source: number,
|
||||||
|
needle: number,
|
||||||
|
): number[] | null {
|
||||||
|
const seen = new Array(graph.length).fill(false);
|
||||||
|
const prev = new Array(graph.length).fill(-1);
|
||||||
|
|
||||||
|
const queue: number[] = [source];
|
||||||
|
seen[source] = true;
|
||||||
|
|
||||||
|
while (queue.length > 0) {
|
||||||
|
const curr = queue.shift() as number;
|
||||||
|
|
||||||
|
if (curr === needle) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const edge of graph[curr]) {
|
||||||
|
const neighbor = edge.to;
|
||||||
|
|
||||||
|
if (seen[neighbor]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
seen[neighbor] = true;
|
||||||
|
prev[neighbor] = curr;
|
||||||
|
queue.push(neighbor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!seen[needle]) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const path: number[] = [];
|
||||||
|
let curr = needle;
|
||||||
|
|
||||||
|
while (curr !== -1) {
|
||||||
|
path.push(curr);
|
||||||
|
curr = prev[curr];
|
||||||
|
}
|
||||||
|
|
||||||
|
return path.reverse();
|
||||||
|
}
|
||||||
8
src/day1/BFSGraphMatrix.test.ts
Normal file
8
src/day1/BFSGraphMatrix.test.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import bfs from "@code/BFSGraphMatrix";
|
||||||
|
import { matrix2 } from "./graph";
|
||||||
|
|
||||||
|
test("bfs - graph matrix", function () {
|
||||||
|
expect(bfs(matrix2, 0, 6)).toEqual([0, 1, 4, 5, 6]);
|
||||||
|
|
||||||
|
expect(bfs(matrix2, 6, 0)).toEqual(null);
|
||||||
|
});
|
||||||
43
src/day1/BFSGraphMatrix.ts
Normal file
43
src/day1/BFSGraphMatrix.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
export default function bfs(
|
||||||
|
graph: number[][],
|
||||||
|
source: number,
|
||||||
|
needle: number,
|
||||||
|
): number[] | null {
|
||||||
|
const seen = new Array(graph.length).fill(false);
|
||||||
|
const prev = new Array(graph.length).fill(-1);
|
||||||
|
const q: number[] = [source];
|
||||||
|
seen[source] = true;
|
||||||
|
|
||||||
|
do {
|
||||||
|
const curr = q.shift() as number;
|
||||||
|
|
||||||
|
if (curr === needle) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const adjs = graph[curr];
|
||||||
|
for (let i = 0; i < graph.length; i++) {
|
||||||
|
if (adjs[i] === 0 || seen[i]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
seen[i] = true;
|
||||||
|
prev[i] = curr;
|
||||||
|
q.push(i);
|
||||||
|
}
|
||||||
|
} while (q.length);
|
||||||
|
|
||||||
|
if (prev[needle] === -1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let curr = needle;
|
||||||
|
const out: number[] = [];
|
||||||
|
|
||||||
|
while (prev[curr] !== -1) {
|
||||||
|
out.push(curr);
|
||||||
|
curr = prev[curr];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [source].concat(out.reverse());
|
||||||
|
}
|
||||||
8
src/day1/BTBFS.test.ts
Normal file
8
src/day1/BTBFS.test.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import bfs from "@code/BTBFS";
|
||||||
|
import { tree } from "./tree";
|
||||||
|
|
||||||
|
test("bt bfs", function () {
|
||||||
|
expect(bfs(tree, 45)).toEqual(true);
|
||||||
|
expect(bfs(tree, 7)).toEqual(true);
|
||||||
|
expect(bfs(tree, 69)).toEqual(false);
|
||||||
|
});
|
||||||
20
src/day1/BTBFS.ts
Normal file
20
src/day1/BTBFS.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
export default function bfs(head: BinaryNode<number>, needle: number): boolean {
|
||||||
|
const q: (BinaryNode<number> | null)[] = [head];
|
||||||
|
|
||||||
|
while (q.length) {
|
||||||
|
const curr = q.shift() as BinaryNode<number> | undefined | null;
|
||||||
|
if (!curr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// search
|
||||||
|
if (curr.value === needle) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
q.push(curr.left);
|
||||||
|
q.push(curr.right);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
6
src/day1/BTInOrder.test.ts
Normal file
6
src/day1/BTInOrder.test.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import bt_in_order from "@code/BTInOrder";
|
||||||
|
import { tree } from "./tree";
|
||||||
|
|
||||||
|
test("In order", function () {
|
||||||
|
expect(bt_in_order(tree)).toEqual([5, 7, 10, 15, 20, 29, 30, 45, 50, 100]);
|
||||||
|
});
|
||||||
17
src/day1/BTInOrder.ts
Normal file
17
src/day1/BTInOrder.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
function walk(curr: BinaryNode<number> | null, path: number[]): number[] {
|
||||||
|
if (!curr) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// recurse
|
||||||
|
walk(curr.left, path);
|
||||||
|
path.push(curr.value);
|
||||||
|
walk(curr.right, path);
|
||||||
|
|
||||||
|
// post
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function in_order_search(head: BinaryNode<number>): number[] {
|
||||||
|
return walk(head, []);
|
||||||
|
}
|
||||||
8
src/day1/BTPostOrder.test.ts
Normal file
8
src/day1/BTPostOrder.test.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import bt_post_order from "@code/BTPostOrder";
|
||||||
|
import { tree } from "./tree";
|
||||||
|
|
||||||
|
test("post order", function () {
|
||||||
|
expect(bt_post_order(tree)).toEqual([
|
||||||
|
7, 5, 15, 10, 29, 45, 30, 100, 50, 20,
|
||||||
|
]);
|
||||||
|
});
|
||||||
17
src/day1/BTPostOrder.ts
Normal file
17
src/day1/BTPostOrder.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
function walk(curr: BinaryNode<number> | null, path: number[]): number[] {
|
||||||
|
if (!curr) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// recurse
|
||||||
|
walk(curr.left, path);
|
||||||
|
walk(curr.right, path);
|
||||||
|
|
||||||
|
// post
|
||||||
|
path.push(curr.value);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function post_order_search(head: BinaryNode<number>): number[] {
|
||||||
|
return walk(head, []);
|
||||||
|
}
|
||||||
6
src/day1/BTPreOrder.test.ts
Normal file
6
src/day1/BTPreOrder.test.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import bt_pre_order from "@code/BTPreOrder";
|
||||||
|
import { tree } from "./tree";
|
||||||
|
|
||||||
|
test("Pre order", function () {
|
||||||
|
expect(bt_pre_order(tree)).toEqual([20, 10, 5, 7, 15, 50, 30, 29, 45, 100]);
|
||||||
|
});
|
||||||
19
src/day1/BTPreOrder.ts
Normal file
19
src/day1/BTPreOrder.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
function walk(curr: BinaryNode<number> | null, path: number[]): number[] {
|
||||||
|
if (!curr) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pre
|
||||||
|
path.push(curr.value);
|
||||||
|
|
||||||
|
// recurse
|
||||||
|
walk(curr.left, path);
|
||||||
|
walk(curr.right, path);
|
||||||
|
|
||||||
|
// post
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function pre_order_search(head: BinaryNode<number>): number[] {
|
||||||
|
return walk(head, []);
|
||||||
|
}
|
||||||
11
src/day1/BinarySearchList.test.ts
Normal file
11
src/day1/BinarySearchList.test.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import binary_fn from "@code/BinarySearchList";
|
||||||
|
|
||||||
|
test("binary search array", function () {
|
||||||
|
const foo = [1, 3, 4, 69, 71, 81, 90, 99, 420, 1337, 69420];
|
||||||
|
expect(binary_fn(foo, 69)).toEqual(true);
|
||||||
|
expect(binary_fn(foo, 1336)).toEqual(false);
|
||||||
|
expect(binary_fn(foo, 69420)).toEqual(true);
|
||||||
|
expect(binary_fn(foo, 69421)).toEqual(false);
|
||||||
|
expect(binary_fn(foo, 1)).toEqual(true);
|
||||||
|
expect(binary_fn(foo, 0)).toEqual(false);
|
||||||
|
});
|
||||||
19
src/day1/BinarySearchList.ts
Normal file
19
src/day1/BinarySearchList.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
export default function bs_list(haystack: number[], needle: number): boolean {
|
||||||
|
let lo = 0;
|
||||||
|
let hi = haystack.length;
|
||||||
|
|
||||||
|
while (lo < hi) {
|
||||||
|
const m = Math.floor(lo + (hi - lo) / 2);
|
||||||
|
const v = haystack[m];
|
||||||
|
|
||||||
|
if (v === needle) {
|
||||||
|
return true;
|
||||||
|
} else if (v > needle) {
|
||||||
|
hi = m;
|
||||||
|
} else {
|
||||||
|
lo = m + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
9
src/day1/BubbleSort.test.ts
Normal file
9
src/day1/BubbleSort.test.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import bubble_sort from "@code/BubbleSort";
|
||||||
|
|
||||||
|
test("bubble-sort", function () {
|
||||||
|
const arr = [9, 3, 7, 4, 69, 420, 42];
|
||||||
|
|
||||||
|
debugger;
|
||||||
|
bubble_sort(arr);
|
||||||
|
expect(arr).toEqual([3, 4, 7, 9, 42, 69, 420]);
|
||||||
|
});
|
||||||
11
src/day1/BubbleSort.ts
Normal file
11
src/day1/BubbleSort.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export default function bubble_sort(arr: number[]): void {
|
||||||
|
for (let i = 0; i < arr.length; i++) {
|
||||||
|
for (let j = 0; j < arr.length - 1 - i; j++) {
|
||||||
|
if (arr[j] > arr[j + 1]) {
|
||||||
|
const tmp = arr[j];
|
||||||
|
arr[j] = arr[j + 1];
|
||||||
|
arr[j + 1] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
src/day1/CompareBinaryTrees.test.ts
Normal file
7
src/day1/CompareBinaryTrees.test.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import compare from "@code/CompareBinaryTrees";
|
||||||
|
import { tree, tree2 } from "./tree";
|
||||||
|
|
||||||
|
test("Compare Binary Trees", function () {
|
||||||
|
expect(compare(tree, tree)).toEqual(true);
|
||||||
|
expect(compare(tree, tree2)).toEqual(false);
|
||||||
|
});
|
||||||
21
src/day1/CompareBinaryTrees.ts
Normal file
21
src/day1/CompareBinaryTrees.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
export default function compare(
|
||||||
|
a: BinaryNode<number> | null,
|
||||||
|
b: BinaryNode<number> | null,
|
||||||
|
): boolean {
|
||||||
|
// structual check
|
||||||
|
if (a === null && b === null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// structual check
|
||||||
|
if (a === null || b === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// value check
|
||||||
|
if (a?.value !== b?.value) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return compare(a.left, b.left) && compare(a.right, b.right);
|
||||||
|
}
|
||||||
8
src/day1/DFSGraphList.test.ts
Normal file
8
src/day1/DFSGraphList.test.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import dfs from "@code/DFSGraphList";
|
||||||
|
import { list2 } from "./graph";
|
||||||
|
|
||||||
|
test("dfs - graph", function () {
|
||||||
|
expect(dfs(list2, 0, 6)).toEqual([0, 1, 4, 5, 6]);
|
||||||
|
|
||||||
|
expect(dfs(list2, 6, 0)).toEqual(null);
|
||||||
|
});
|
||||||
50
src/day1/DFSGraphList.ts
Normal file
50
src/day1/DFSGraphList.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
function walk(
|
||||||
|
graph: WeightedAdjacencyList,
|
||||||
|
curr: number,
|
||||||
|
needle: number,
|
||||||
|
seen: boolean[],
|
||||||
|
path: number[],
|
||||||
|
): boolean {
|
||||||
|
if (seen[curr]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
seen[curr] = true;
|
||||||
|
|
||||||
|
// pre
|
||||||
|
path.push(curr);
|
||||||
|
if (curr === needle) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// recurse
|
||||||
|
const list = graph[curr];
|
||||||
|
for (let i = 0; i < list.length; i++) {
|
||||||
|
const edge = list[i];
|
||||||
|
|
||||||
|
if (walk(graph, edge.to, needle, seen, path)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// post
|
||||||
|
path.pop();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function dfs(
|
||||||
|
graph: WeightedAdjacencyList,
|
||||||
|
source: number,
|
||||||
|
needle: number,
|
||||||
|
): number[] | null {
|
||||||
|
const seen: boolean[] = new Array(graph.length).fill(false);
|
||||||
|
const path: number[] = [];
|
||||||
|
walk(graph, source, needle, seen, path);
|
||||||
|
|
||||||
|
if (path.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
8
src/day1/DFSOnBST.test.ts
Normal file
8
src/day1/DFSOnBST.test.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import dfs from "@code/DFSOnBST";
|
||||||
|
import { tree } from "./tree";
|
||||||
|
|
||||||
|
test("DFS on BST", function () {
|
||||||
|
expect(dfs(tree, 45)).toEqual(true);
|
||||||
|
expect(dfs(tree, 7)).toEqual(true);
|
||||||
|
expect(dfs(tree, 69)).toEqual(false);
|
||||||
|
});
|
||||||
19
src/day1/DFSOnBST.ts
Normal file
19
src/day1/DFSOnBST.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
function search(curr: BinaryNode<number> | null, needle: number): boolean {
|
||||||
|
if (!curr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curr.value === needle) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curr.value < needle) {
|
||||||
|
return search(curr.right, needle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return search(curr.left, needle);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function dfs(head: BinaryNode<number>, needle: number): boolean {
|
||||||
|
return search(head, needle);
|
||||||
|
}
|
||||||
9
src/day1/DijkstraList.test.ts
Normal file
9
src/day1/DijkstraList.test.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import dijkstra_list from "@code/DijkstraList";
|
||||||
|
import { list1 } from "./graph";
|
||||||
|
|
||||||
|
test("dijkstra via adj list", function () {
|
||||||
|
/// waht?
|
||||||
|
// what..
|
||||||
|
// what...
|
||||||
|
expect(dijkstra_list(0, 6, list1)).toEqual([0, 1, 4, 5, 6]);
|
||||||
|
});
|
||||||
61
src/day1/DijkstraList.ts
Normal file
61
src/day1/DijkstraList.ts
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
function hasUnvisited(seen: boolean[], dists: number[]): boolean {
|
||||||
|
return seen.some((s, i) => !s && dists[i] < Infinity);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLowestUnvisited(seen: boolean[], dists: number[]): number {
|
||||||
|
let idx = -1;
|
||||||
|
let lowestDistance = Infinity;
|
||||||
|
|
||||||
|
for (let i = 0; i < seen.length; i++) {
|
||||||
|
if (seen[i]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lowestDistance > dists[i]) {
|
||||||
|
lowestDistance = dists[i];
|
||||||
|
idx = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function dijkstra_list(
|
||||||
|
source: number,
|
||||||
|
sink: number,
|
||||||
|
arr: WeightedAdjacencyList,
|
||||||
|
): number[] {
|
||||||
|
const seen = new Array(arr.length).fill(false);
|
||||||
|
const prev = new Array(arr.length).fill(-1);
|
||||||
|
const dists = new Array(arr.length).fill(Infinity);
|
||||||
|
dists[source] = 0;
|
||||||
|
|
||||||
|
while (hasUnvisited(seen, dists)) {
|
||||||
|
const curr = getLowestUnvisited(seen, dists);
|
||||||
|
seen[curr] = true;
|
||||||
|
|
||||||
|
const adjs = arr[curr];
|
||||||
|
for (let i = 0; i < adjs.length; i++) {
|
||||||
|
const edge = adjs[i];
|
||||||
|
if (seen[edge.to]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dist = dists[curr] + edge.weight;
|
||||||
|
if (dist < dists[edge.to]) {
|
||||||
|
dists[edge.to] = dist;
|
||||||
|
prev[edge.to] = curr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let curr = sink;
|
||||||
|
const out: number[] = [];
|
||||||
|
|
||||||
|
while (prev[curr] !== -1) {
|
||||||
|
out.push(curr);
|
||||||
|
curr = prev[curr];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [source].concat(out.reverse());
|
||||||
|
}
|
||||||
7
src/day1/DoublyLinkedList.test.ts
Normal file
7
src/day1/DoublyLinkedList.test.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import LinkedList from "@code/DoublyLinkedList";
|
||||||
|
import { test_list } from "./ListTest";
|
||||||
|
|
||||||
|
test("DoublyLinkedList", function () {
|
||||||
|
const list = new LinkedList<number>();
|
||||||
|
test_list(list);
|
||||||
|
});
|
||||||
136
src/day1/DoublyLinkedList.ts
Normal file
136
src/day1/DoublyLinkedList.ts
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
class Node<T> {
|
||||||
|
public value: T;
|
||||||
|
public prev?: Node<T>;
|
||||||
|
public next?: Node<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class DoublyLinkedList<T> {
|
||||||
|
public length: number;
|
||||||
|
public head?: Node<T>;
|
||||||
|
public tail?: Node<T>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.length = 0;
|
||||||
|
this.head = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
prepend(item: T): void {
|
||||||
|
const node = { value: item } as Node<T>;
|
||||||
|
this.length++;
|
||||||
|
|
||||||
|
if (!this.head) {
|
||||||
|
this.head = node;
|
||||||
|
this.tail = node;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node.next = this.head;
|
||||||
|
this.head.prev = node;
|
||||||
|
this.head = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
insertAt(item: T, idx: number): void {
|
||||||
|
if (idx > this.length) {
|
||||||
|
throw new Error("oh no");
|
||||||
|
} else if (idx === this.length) {
|
||||||
|
this.append(item);
|
||||||
|
return;
|
||||||
|
} else if (idx === 0) {
|
||||||
|
this.prepend(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.length++;
|
||||||
|
const curr = this.getAt(idx) as Node<T>;
|
||||||
|
const node = { value: item } as Node<T>;
|
||||||
|
|
||||||
|
node.next = curr;
|
||||||
|
node.prev = curr.prev;
|
||||||
|
curr.prev = node;
|
||||||
|
|
||||||
|
if (node.prev) {
|
||||||
|
node.prev.next = node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
append(item: T): void {
|
||||||
|
const node = { value: item } as Node<T>;
|
||||||
|
this.length++;
|
||||||
|
|
||||||
|
if (!this.tail) {
|
||||||
|
this.head = node;
|
||||||
|
this.tail = node;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node.prev = this.tail;
|
||||||
|
this.tail.next = node;
|
||||||
|
this.tail = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(item: T): T | undefined {
|
||||||
|
let curr = this.head;
|
||||||
|
for (let i = 0; curr && i < this.length; i++) {
|
||||||
|
if (curr.value === item) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
curr = curr.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!curr) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.removeNode(curr);
|
||||||
|
}
|
||||||
|
|
||||||
|
get(idx: number): T | undefined {
|
||||||
|
return this.getAt(idx)?.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
removeAt(idx: number): T | undefined {
|
||||||
|
const node = this.getAt(idx);
|
||||||
|
|
||||||
|
if (!node) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return this.removeNode(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeNode(node: Node<T>): T | undefined {
|
||||||
|
this.length--;
|
||||||
|
|
||||||
|
if (this.length === 0) {
|
||||||
|
const out = this.head?.value;
|
||||||
|
this.head = undefined;
|
||||||
|
this.tail = undefined;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.prev) {
|
||||||
|
node.prev.next = node.next;
|
||||||
|
}
|
||||||
|
if (node.next) {
|
||||||
|
node.next.prev = node.prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node === this.head) {
|
||||||
|
this.head = node.next;
|
||||||
|
}
|
||||||
|
if (node === this.tail) {
|
||||||
|
this.tail = node.prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
node.prev = undefined;
|
||||||
|
node.next = undefined;
|
||||||
|
|
||||||
|
return node.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getAt(idx: number): Node<T> | undefined {
|
||||||
|
let curr = this.head;
|
||||||
|
for (let i = 0; curr && i < idx; i++) {
|
||||||
|
curr = curr.next;
|
||||||
|
}
|
||||||
|
return curr;
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/day1/InsertionSort.test.ts
Normal file
9
src/day1/InsertionSort.test.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import insertion_sort from "@code/InsertionSort";
|
||||||
|
|
||||||
|
test("insertion-sort", function () {
|
||||||
|
const arr = [9, 3, 7, 4, 69, 420, 42];
|
||||||
|
debugger;
|
||||||
|
// where is my debugger
|
||||||
|
insertion_sort(arr);
|
||||||
|
expect(arr).toEqual([3, 4, 7, 9, 42, 69, 420]);
|
||||||
|
});
|
||||||
13
src/day1/InsertionSort.ts
Normal file
13
src/day1/InsertionSort.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
export default function insertion_sort(arr: number[]): void {
|
||||||
|
for (let i = 1; i < arr.length; i++) {
|
||||||
|
const key = arr[i];
|
||||||
|
let j = i - 1;
|
||||||
|
|
||||||
|
while (j >= 0 && arr[j] > key) {
|
||||||
|
arr[j + 1] = arr[j];
|
||||||
|
j--;
|
||||||
|
}
|
||||||
|
|
||||||
|
arr[j + 1] = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
27
src/day1/LRU.test.ts
Normal file
27
src/day1/LRU.test.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import LRU from "@code/LRU";
|
||||||
|
|
||||||
|
test("LRU", function () {
|
||||||
|
const lru = new LRU<string, number>(3) as ILRU<string, number>;
|
||||||
|
|
||||||
|
expect(lru.get("foo")).toEqual(undefined);
|
||||||
|
lru.update("foo", 69);
|
||||||
|
expect(lru.get("foo")).toEqual(69);
|
||||||
|
|
||||||
|
lru.update("bar", 420);
|
||||||
|
expect(lru.get("bar")).toEqual(420);
|
||||||
|
|
||||||
|
lru.update("baz", 1337);
|
||||||
|
expect(lru.get("baz")).toEqual(1337);
|
||||||
|
|
||||||
|
lru.update("ball", 69420);
|
||||||
|
expect(lru.get("ball")).toEqual(69420);
|
||||||
|
expect(lru.get("foo")).toEqual(undefined);
|
||||||
|
expect(lru.get("bar")).toEqual(420);
|
||||||
|
lru.update("foo", 69);
|
||||||
|
expect(lru.get("bar")).toEqual(420);
|
||||||
|
expect(lru.get("foo")).toEqual(69);
|
||||||
|
|
||||||
|
// shouldn't of been deleted, but since bar was get'd, bar was added to the
|
||||||
|
// front of the list, so baz became the end
|
||||||
|
expect(lru.get("baz")).toEqual(undefined);
|
||||||
|
});
|
||||||
99
src/day1/LRU.ts
Normal file
99
src/day1/LRU.ts
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
function createNode<V>(value: V): Node<V> {
|
||||||
|
return { value };
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class LRU<K, V> {
|
||||||
|
private length: number;
|
||||||
|
private capacity: number;
|
||||||
|
private head?: Node<V>;
|
||||||
|
private tail?: Node<V>;
|
||||||
|
private lookup: Map<K, Node<V>>;
|
||||||
|
private reverseLookup: Map<Node<V>, K>;
|
||||||
|
|
||||||
|
constructor(capacity: number) {
|
||||||
|
this.length = 0;
|
||||||
|
this.capacity = capacity;
|
||||||
|
this.head = this.tail = undefined;
|
||||||
|
this.lookup = new Map<K, Node<V>>();
|
||||||
|
this.reverseLookup = new Map<Node<V>, K>();
|
||||||
|
}
|
||||||
|
|
||||||
|
update(key: K, value: V): void {
|
||||||
|
// check the cache for existence
|
||||||
|
let node = this.lookup.get(key);
|
||||||
|
if (!node) {
|
||||||
|
node = createNode(value);
|
||||||
|
this.length++;
|
||||||
|
this.prepend(node);
|
||||||
|
this.trimCache();
|
||||||
|
|
||||||
|
this.lookup.set(key, node);
|
||||||
|
this.reverseLookup.set(node, key);
|
||||||
|
} else {
|
||||||
|
this.detach(node);
|
||||||
|
this.prepend(node);
|
||||||
|
node.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get(key: K): V | undefined {
|
||||||
|
// check the cache for existence
|
||||||
|
const node = this.lookup.get(key);
|
||||||
|
if (!node) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the value we found and move it to the front
|
||||||
|
this.detach(node);
|
||||||
|
this.prepend(node);
|
||||||
|
|
||||||
|
// return out the value found
|
||||||
|
return node.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private detach(node: Node<V>): void {
|
||||||
|
if (node.prev) {
|
||||||
|
node.prev.next = node.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.next) {
|
||||||
|
node.next.prev = node.prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.head === node) {
|
||||||
|
this.head = this.head.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.tail === node) {
|
||||||
|
this.tail = this.tail.prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
node.next = undefined;
|
||||||
|
node.prev = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private prepend(node: Node<V>): void {
|
||||||
|
if (!this.head) {
|
||||||
|
this.head = this.tail = node;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node.next = this.head;
|
||||||
|
this.head.prev = node;
|
||||||
|
this.head = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
private trimCache(): void {
|
||||||
|
if (this.length <= this.capacity) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tail = this.tail as Node<V>;
|
||||||
|
this.detach(this.tail as Node<V>);
|
||||||
|
|
||||||
|
const key = this.reverseLookup.get(tail) as K;
|
||||||
|
this.lookup.delete(key);
|
||||||
|
this.reverseLookup.delete(tail);
|
||||||
|
this.length--;
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/day1/LinearSearchList.test.ts
Normal file
11
src/day1/LinearSearchList.test.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import linear_fn from "@code/LinearSearchList";
|
||||||
|
|
||||||
|
test("linear search array", function () {
|
||||||
|
const foo = [1, 3, 4, 69, 71, 81, 90, 99, 420, 1337, 69420];
|
||||||
|
expect(linear_fn(foo, 69)).toEqual(true);
|
||||||
|
expect(linear_fn(foo, 1336)).toEqual(false);
|
||||||
|
expect(linear_fn(foo, 69420)).toEqual(true);
|
||||||
|
expect(linear_fn(foo, 69421)).toEqual(false);
|
||||||
|
expect(linear_fn(foo, 1)).toEqual(true);
|
||||||
|
expect(linear_fn(foo, 0)).toEqual(false);
|
||||||
|
});
|
||||||
12
src/day1/LinearSearchList.ts
Normal file
12
src/day1/LinearSearchList.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
export default function linear_search(
|
||||||
|
haystack: number[],
|
||||||
|
needle: number,
|
||||||
|
): boolean {
|
||||||
|
for (let i = 0; i < haystack.length; i++) {
|
||||||
|
if (haystack[i] === needle) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
26
src/day1/ListTest.ts
Normal file
26
src/day1/ListTest.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
export function test_list(list: List<number>): void {
|
||||||
|
list.append(5);
|
||||||
|
list.append(7);
|
||||||
|
list.append(9);
|
||||||
|
|
||||||
|
expect(list.get(2)).toEqual(9);
|
||||||
|
expect(list.removeAt(1)).toEqual(7);
|
||||||
|
expect(list.length).toEqual(2);
|
||||||
|
|
||||||
|
list.append(11);
|
||||||
|
expect(list.removeAt(1)).toEqual(9);
|
||||||
|
expect(list.remove(9)).toEqual(undefined);
|
||||||
|
expect(list.removeAt(0)).toEqual(5);
|
||||||
|
expect(list.removeAt(0)).toEqual(11);
|
||||||
|
expect(list.length).toEqual(0);
|
||||||
|
|
||||||
|
list.prepend(5);
|
||||||
|
list.prepend(7);
|
||||||
|
list.prepend(9);
|
||||||
|
|
||||||
|
expect(list.get(2)).toEqual(5);
|
||||||
|
expect(list.get(0)).toEqual(9);
|
||||||
|
expect(list.remove(9)).toEqual(9);
|
||||||
|
expect(list.length).toEqual(2);
|
||||||
|
expect(list.get(0)).toEqual(7);
|
||||||
|
}
|
||||||
23
src/day1/Map.test.ts
Normal file
23
src/day1/Map.test.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import MyMap from "@code/Map";
|
||||||
|
|
||||||
|
test("Map", function () {
|
||||||
|
const map = new MyMap<string, number>();
|
||||||
|
map.set("foo", 55);
|
||||||
|
expect(map.size()).toEqual(1);
|
||||||
|
map.set("fool", 75);
|
||||||
|
expect(map.size()).toEqual(2);
|
||||||
|
map.set("foolish", 105);
|
||||||
|
expect(map.size()).toEqual(3);
|
||||||
|
map.set("bar", 69);
|
||||||
|
expect(map.size()).toEqual(4);
|
||||||
|
|
||||||
|
expect(map.get("bar")).toEqual(69);
|
||||||
|
expect(map.get("blaz")).toEqual(undefined);
|
||||||
|
|
||||||
|
map.delete("barblabr");
|
||||||
|
expect(map.size()).toEqual(4);
|
||||||
|
|
||||||
|
map.delete("bar");
|
||||||
|
expect(map.size()).toEqual(3);
|
||||||
|
expect(map.get("bar")).toEqual(undefined);
|
||||||
|
});
|
||||||
34
src/day1/Map.ts
Normal file
34
src/day1/Map.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
export default class Map<T extends string | number, V> {
|
||||||
|
private store: { [key: string]: V };
|
||||||
|
private count: number;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.store = {};
|
||||||
|
this.count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
get(key: T): V | undefined {
|
||||||
|
return this.store.hasOwnProperty(key) ? this.store[key] : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
set(key: T, value: V): void {
|
||||||
|
if (!this.store.hasOwnProperty(key)) {
|
||||||
|
this.count++;
|
||||||
|
}
|
||||||
|
this.store[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(key: T): V | undefined {
|
||||||
|
if (this.store.hasOwnProperty(key)) {
|
||||||
|
const value = this.store[key];
|
||||||
|
delete this.store[key];
|
||||||
|
this.count--;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
size(): number {
|
||||||
|
return this.count;
|
||||||
|
}
|
||||||
|
}
|
||||||
44
src/day1/MazeSolver.test.ts
Normal file
44
src/day1/MazeSolver.test.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import maze_solver from "@code/MazeSolver";
|
||||||
|
|
||||||
|
test("maze solver", function () {
|
||||||
|
const maze = [
|
||||||
|
"xxxxxxxxxx x",
|
||||||
|
"x x x",
|
||||||
|
"x x x",
|
||||||
|
"x xxxxxxxx x",
|
||||||
|
"x x",
|
||||||
|
"x xxxxxxxxxx",
|
||||||
|
];
|
||||||
|
|
||||||
|
const mazeResult = [
|
||||||
|
{ x: 10, y: 0 },
|
||||||
|
{ x: 10, y: 1 },
|
||||||
|
{ x: 10, y: 2 },
|
||||||
|
{ x: 10, y: 3 },
|
||||||
|
{ x: 10, y: 4 },
|
||||||
|
{ x: 9, y: 4 },
|
||||||
|
{ x: 8, y: 4 },
|
||||||
|
{ x: 7, y: 4 },
|
||||||
|
{ x: 6, y: 4 },
|
||||||
|
{ x: 5, y: 4 },
|
||||||
|
{ x: 4, y: 4 },
|
||||||
|
{ x: 3, y: 4 },
|
||||||
|
{ x: 2, y: 4 },
|
||||||
|
{ x: 1, y: 4 },
|
||||||
|
{ x: 1, y: 5 },
|
||||||
|
];
|
||||||
|
|
||||||
|
// there is only one path through
|
||||||
|
const result = maze_solver(maze, "x", { x: 10, y: 0 }, { x: 1, y: 5 });
|
||||||
|
expect(drawPath(maze, result)).toEqual(drawPath(maze, mazeResult));
|
||||||
|
});
|
||||||
|
|
||||||
|
function drawPath(data: string[], path: Point[]) {
|
||||||
|
const data2 = data.map((row) => row.split(""));
|
||||||
|
path.forEach((p) => {
|
||||||
|
if (data2[p.y] && data2[p.y][p.x]) {
|
||||||
|
data2[p.y][p.x] = "*";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return data2.map((d) => d.join(""));
|
||||||
|
}
|
||||||
57
src/day1/MazeSolver.ts
Normal file
57
src/day1/MazeSolver.ts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
export default function solve(
|
||||||
|
maze: string[],
|
||||||
|
wall: string,
|
||||||
|
start: Point,
|
||||||
|
end: Point,
|
||||||
|
): Point[] {
|
||||||
|
const numRows = maze.length;
|
||||||
|
const numCols = maze[0].length;
|
||||||
|
const visited = new Set<string>();
|
||||||
|
const queue: { point: Point; path: Point[] }[] = [];
|
||||||
|
|
||||||
|
function isValid(x: number, y: number): boolean {
|
||||||
|
return (
|
||||||
|
x >= 0 &&
|
||||||
|
x < numCols &&
|
||||||
|
y >= 0 &&
|
||||||
|
y < numRows &&
|
||||||
|
maze[y][x] !== wall
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = (p: Point) => `${p.x},${p.y}`;
|
||||||
|
|
||||||
|
queue.push({ point: start, path: [start] });
|
||||||
|
visited.add(key(start));
|
||||||
|
|
||||||
|
const directions = [
|
||||||
|
// up
|
||||||
|
{ x: 0, y: -1 },
|
||||||
|
// right
|
||||||
|
{ x: 1, y: 0 },
|
||||||
|
// down
|
||||||
|
{ x: 0, y: 1 },
|
||||||
|
// left
|
||||||
|
{ x: -1, y: 0 },
|
||||||
|
];
|
||||||
|
|
||||||
|
while (queue.length > 0) {
|
||||||
|
const { point, path } = queue.shift()!;
|
||||||
|
if (point.x === end.x && point.y === end.y) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const dir of directions) {
|
||||||
|
const next = { x: point.x + dir.x, y: point.y + dir.y };
|
||||||
|
const nextKey = key(next);
|
||||||
|
|
||||||
|
if (isValid(next.x, next.y) && !visited.has(nextKey)) {
|
||||||
|
visited.add(nextKey);
|
||||||
|
queue.push({ point: next, path: [...path, next] });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No path found
|
||||||
|
return [];
|
||||||
|
}
|
||||||
7
src/day1/MergeSort.test.ts
Normal file
7
src/day1/MergeSort.test.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import merge_sort from "@code/MergeSort";
|
||||||
|
|
||||||
|
test("merge-sort", function () {
|
||||||
|
const arr = [9, 3, 7, 4, 69, 420, 42];
|
||||||
|
merge_sort(arr);
|
||||||
|
expect(arr).toEqual([3, 4, 7, 9, 42, 69, 420]);
|
||||||
|
});
|
||||||
36
src/day1/MergeSort.ts
Normal file
36
src/day1/MergeSort.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
function mergeSortHelper(arr: number[], start: number, end: number): void {
|
||||||
|
if (start >= end) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mid = Math.floor((start + end) / 2);
|
||||||
|
|
||||||
|
mergeSortHelper(arr, start, mid);
|
||||||
|
mergeSortHelper(arr, mid + 1, end);
|
||||||
|
|
||||||
|
merge(arr, start, mid, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
function merge(arr: number[], start: number, mid: number, end: number): void {
|
||||||
|
const left = arr.slice(start, mid + 1);
|
||||||
|
const right = arr.slice(mid + 1, end + 1);
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
let j = 0;
|
||||||
|
let k = start;
|
||||||
|
|
||||||
|
while (i < left.length && j < right.length) {
|
||||||
|
arr[k++] = left[i] <= right[j] ? left[i++] : right[j++];
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i < left.length) {
|
||||||
|
arr[k++] = left[i++];
|
||||||
|
}
|
||||||
|
while (j < right.length) {
|
||||||
|
arr[k++] = right[j++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function merge_sort(arr: number[]): void {
|
||||||
|
mergeSortHelper(arr, 0, arr.length - 1);
|
||||||
|
}
|
||||||
28
src/day1/MinHeap.test.ts
Normal file
28
src/day1/MinHeap.test.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import MinHeap from "@code/MinHeap";
|
||||||
|
|
||||||
|
test("min heap", function () {
|
||||||
|
const heap = new MinHeap();
|
||||||
|
|
||||||
|
expect(heap.length).toEqual(0);
|
||||||
|
|
||||||
|
heap.insert(5);
|
||||||
|
heap.insert(3);
|
||||||
|
heap.insert(69);
|
||||||
|
heap.insert(420);
|
||||||
|
heap.insert(4);
|
||||||
|
heap.insert(1);
|
||||||
|
heap.insert(8);
|
||||||
|
heap.insert(7);
|
||||||
|
|
||||||
|
expect(heap.length).toEqual(8);
|
||||||
|
expect(heap.delete()).toEqual(1);
|
||||||
|
expect(heap.delete()).toEqual(3);
|
||||||
|
expect(heap.delete()).toEqual(4);
|
||||||
|
expect(heap.delete()).toEqual(5);
|
||||||
|
expect(heap.length).toEqual(4);
|
||||||
|
expect(heap.delete()).toEqual(7);
|
||||||
|
expect(heap.delete()).toEqual(8);
|
||||||
|
expect(heap.delete()).toEqual(69);
|
||||||
|
expect(heap.delete()).toEqual(420);
|
||||||
|
expect(heap.length).toEqual(0);
|
||||||
|
});
|
||||||
89
src/day1/MinHeap.ts
Normal file
89
src/day1/MinHeap.ts
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
export default class MinHeap {
|
||||||
|
public length: number;
|
||||||
|
private data: number[];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.data = [];
|
||||||
|
this.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
insert(value: number): void {
|
||||||
|
this.data[this.length] = value;
|
||||||
|
this.heapifyUp(this.length);
|
||||||
|
this.length++;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(): number {
|
||||||
|
if (this.length === 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const out = this.data[0];
|
||||||
|
this.length--;
|
||||||
|
|
||||||
|
if (this.length === 0) {
|
||||||
|
this.data = [];
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.data[0] = this.data[this.length];
|
||||||
|
this.heapifyDown(0);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
private heapifyDown(idx: number): void {
|
||||||
|
const lIdx = this.leftChild(idx);
|
||||||
|
const rIdx = this.rightChild(idx);
|
||||||
|
|
||||||
|
if (idx >= this.length || lIdx >= this.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lV = this.data[lIdx];
|
||||||
|
const rV = this.data[rIdx];
|
||||||
|
const v = this.data[idx];
|
||||||
|
|
||||||
|
if (lV > rV && v > rV) {
|
||||||
|
this.data[idx] = rV;
|
||||||
|
this.data[rIdx] = v;
|
||||||
|
this.heapifyDown(rIdx);
|
||||||
|
} else if (rV > lV && v > lV) {
|
||||||
|
this.data[idx] = lV;
|
||||||
|
this.data[lIdx] = v;
|
||||||
|
this.heapifyDown(lIdx);
|
||||||
|
} else if (lV == rV && v > rV) {
|
||||||
|
this.data[idx] = rV;
|
||||||
|
this.data[rIdx] = v;
|
||||||
|
this.heapifyDown(rIdx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private heapifyUp(idx: number): void {
|
||||||
|
if (idx === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const p = this.parent(idx);
|
||||||
|
const parentV = this.data[p];
|
||||||
|
const v = this.data[idx];
|
||||||
|
|
||||||
|
if (parentV > v) {
|
||||||
|
this.data[idx] = parentV;
|
||||||
|
this.data[p] = v;
|
||||||
|
this.heapifyUp(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private parent(idx: number): number {
|
||||||
|
return Math.floor((idx - 1) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private leftChild(idx: number): number {
|
||||||
|
return idx * 2 + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private rightChild(idx: number): number {
|
||||||
|
return idx * 2 + 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
58
src/day1/PrimsAlgorithm.ts
Normal file
58
src/day1/PrimsAlgorithm.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
export default function prims(
|
||||||
|
list: WeightedAdjacencyList,
|
||||||
|
): WeightedAdjacencyList | null {
|
||||||
|
const n = list.length;
|
||||||
|
if (n === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const inMST = new Array(n).fill(false);
|
||||||
|
const mst: WeightedAdjacencyList = Array.from({ length: n }, () => []);
|
||||||
|
|
||||||
|
const minEdge: { to: number; from: number; weight: number }[] = new Array(
|
||||||
|
n,
|
||||||
|
).fill(null as any);
|
||||||
|
minEdge[0] = { to: 0, from: -1, weight: 0 };
|
||||||
|
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
let u = -1;
|
||||||
|
|
||||||
|
for (let v = 0; v < n; v++) {
|
||||||
|
if (
|
||||||
|
!inMST[v] &&
|
||||||
|
(u === -1 ||
|
||||||
|
(minEdge[v] && minEdge[v].weight < minEdge[u].weight))
|
||||||
|
) {
|
||||||
|
u = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (u === -1 || minEdge[u] === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
inMST[u] = true;
|
||||||
|
|
||||||
|
const edge = minEdge[u];
|
||||||
|
if (edge.from !== -1) {
|
||||||
|
mst[edge.from].push({ to: u, weight: edge.weight });
|
||||||
|
mst[u].push({ to: edge.from, weight: edge.weight });
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const neighbor of list[u]) {
|
||||||
|
if (
|
||||||
|
!inMST[neighbor.to] &&
|
||||||
|
(!minEdge[neighbor.to] ||
|
||||||
|
neighbor.weight < minEdge[neighbor.to].weight)
|
||||||
|
) {
|
||||||
|
minEdge[neighbor.to] = {
|
||||||
|
to: neighbor.to,
|
||||||
|
from: u,
|
||||||
|
weight: neighbor.weight,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mst;
|
||||||
|
}
|
||||||
30
src/day1/PrimsList.test.ts
Normal file
30
src/day1/PrimsList.test.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import prims from "@code/PrimsAlgorithm";
|
||||||
|
import { list1 } from "./graph";
|
||||||
|
|
||||||
|
test("PrimsAlgorithm", function () {
|
||||||
|
// there is only one right answer for this graph
|
||||||
|
expect(prims(list1)).toEqual([
|
||||||
|
[
|
||||||
|
{ to: 2, weight: 1 },
|
||||||
|
{ to: 1, weight: 3 },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{ to: 0, weight: 3 },
|
||||||
|
{ to: 4, weight: 1 },
|
||||||
|
],
|
||||||
|
[{ to: 0, weight: 1 }],
|
||||||
|
[{ to: 6, weight: 1 }],
|
||||||
|
[
|
||||||
|
{ to: 1, weight: 1 },
|
||||||
|
{ to: 5, weight: 2 },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{ to: 4, weight: 2 },
|
||||||
|
{ to: 6, weight: 1 },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{ to: 5, weight: 1 },
|
||||||
|
{ to: 3, weight: 1 },
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
});
|
||||||
31
src/day1/Queue.test.ts
Normal file
31
src/day1/Queue.test.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import Queue from "@code/Queue";
|
||||||
|
|
||||||
|
test("queue", function () {
|
||||||
|
const list = new Queue<number>();
|
||||||
|
|
||||||
|
list.enqueue(5);
|
||||||
|
list.enqueue(7);
|
||||||
|
list.enqueue(9);
|
||||||
|
|
||||||
|
expect(list.deque()).toEqual(5);
|
||||||
|
expect(list.length).toEqual(2);
|
||||||
|
|
||||||
|
// this must be wrong..?
|
||||||
|
debugger;
|
||||||
|
|
||||||
|
// i hate using debuggers
|
||||||
|
list.enqueue(11);
|
||||||
|
debugger;
|
||||||
|
expect(list.deque()).toEqual(7);
|
||||||
|
expect(list.deque()).toEqual(9);
|
||||||
|
expect(list.peek()).toEqual(11);
|
||||||
|
expect(list.deque()).toEqual(11);
|
||||||
|
expect(list.deque()).toEqual(undefined);
|
||||||
|
expect(list.length).toEqual(0);
|
||||||
|
|
||||||
|
// just wanted to make sure that I could not blow up myself when i remove
|
||||||
|
// everything
|
||||||
|
list.enqueue(69);
|
||||||
|
expect(list.peek()).toEqual(69);
|
||||||
|
expect(list.length).toEqual(1);
|
||||||
|
});
|
||||||
50
src/day1/Queue.ts
Normal file
50
src/day1/Queue.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
type Node<T> = {
|
||||||
|
value: T;
|
||||||
|
next?: Node<T>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class Queue<T> {
|
||||||
|
public length: number;
|
||||||
|
private head?: Node<T>;
|
||||||
|
private tail?: Node<T>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.head = undefined;
|
||||||
|
this.tail = undefined;
|
||||||
|
this.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
enqueue(item: T): void {
|
||||||
|
const node = { value: item } as Node<T>;
|
||||||
|
this.length++;
|
||||||
|
if (!this.tail) {
|
||||||
|
this.head = node;
|
||||||
|
this.tail = node;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.tail.next = node;
|
||||||
|
this.tail = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
deque(): T | undefined {
|
||||||
|
if (!this.head) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.length--;
|
||||||
|
const head = this.head;
|
||||||
|
this.head = this.head.next;
|
||||||
|
head.next = undefined;
|
||||||
|
|
||||||
|
if (this.length === 0) {
|
||||||
|
this.tail = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return head.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
peek(): T | undefined {
|
||||||
|
return this.head?.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/day1/QuickSort.test.ts
Normal file
9
src/day1/QuickSort.test.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import quick_sort from "@code/QuickSort";
|
||||||
|
|
||||||
|
test("quick-sort", function () {
|
||||||
|
const arr = [9, 3, 7, 4, 69, 420, 42];
|
||||||
|
|
||||||
|
debugger;
|
||||||
|
quick_sort(arr);
|
||||||
|
expect(arr).toEqual([3, 4, 7, 9, 42, 69, 420]);
|
||||||
|
});
|
||||||
34
src/day1/QuickSort.ts
Normal file
34
src/day1/QuickSort.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
function qs(arr: number[], lo: number, hi: number): void {
|
||||||
|
if (lo >= hi) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pivotIdx = partition(arr, lo, hi);
|
||||||
|
|
||||||
|
qs(arr, lo, pivotIdx - 1);
|
||||||
|
qs(arr, pivotIdx + 1, hi);
|
||||||
|
}
|
||||||
|
|
||||||
|
function partition(arr: number[], lo: number, hi: number): number {
|
||||||
|
const pivot = arr[hi];
|
||||||
|
let idx = lo - 1;
|
||||||
|
|
||||||
|
for (let i = lo; i < hi; i++) {
|
||||||
|
if (arr[i] <= pivot) {
|
||||||
|
idx++;
|
||||||
|
const tmp = arr[i];
|
||||||
|
arr[i] = arr[idx];
|
||||||
|
arr[idx] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
idx++;
|
||||||
|
arr[hi] = arr[idx];
|
||||||
|
arr[idx] = pivot;
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function quick_sort(arr: number[]): void {
|
||||||
|
qs(arr, 0, arr.length - 1);
|
||||||
|
}
|
||||||
22
src/day1/RingBuffer.test.ts
Normal file
22
src/day1/RingBuffer.test.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import RingBuffer from "@code/RingBuffer";
|
||||||
|
|
||||||
|
test("RingBuffer", function () {
|
||||||
|
const buffer = new RingBuffer<number>();
|
||||||
|
|
||||||
|
buffer.push(5);
|
||||||
|
expect(buffer.pop()).toEqual(5);
|
||||||
|
expect(buffer.pop()).toEqual(undefined);
|
||||||
|
|
||||||
|
buffer.push(42);
|
||||||
|
buffer.push(9);
|
||||||
|
expect(buffer.pop()).toEqual(42);
|
||||||
|
expect(buffer.pop()).toEqual(9);
|
||||||
|
expect(buffer.pop()).toEqual(undefined);
|
||||||
|
|
||||||
|
buffer.push(42);
|
||||||
|
buffer.push(9);
|
||||||
|
buffer.push(12);
|
||||||
|
expect(buffer.get(2)).toEqual(12);
|
||||||
|
expect(buffer.get(1)).toEqual(9);
|
||||||
|
expect(buffer.get(0)).toEqual(42);
|
||||||
|
});
|
||||||
59
src/day1/RingBuffer.ts
Normal file
59
src/day1/RingBuffer.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
export default class RingBuffer<T> {
|
||||||
|
private items: T[] = [];
|
||||||
|
private start: number = 0;
|
||||||
|
private end: number = 0;
|
||||||
|
private count: number = 0;
|
||||||
|
|
||||||
|
constructor(initialCapacity: number = 4) {
|
||||||
|
this.items = new Array<T>(initialCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get length(): number {
|
||||||
|
return this.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
push(item: T): void {
|
||||||
|
if (this.count === this.items.length) {
|
||||||
|
this.resize();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.items[this.end] = item;
|
||||||
|
this.end = (this.end + 1) % this.items.length;
|
||||||
|
this.count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
pop(): T | undefined {
|
||||||
|
if (this.count === 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const item = this.items[this.start];
|
||||||
|
this.items[this.start] = undefined as any;
|
||||||
|
this.start = (this.start + 1) % this.items.length;
|
||||||
|
this.count--;
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
get(idx: number): T | undefined {
|
||||||
|
if (idx < 0 || idx >= this.count) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const realIndex = (this.start + idx) % this.items.length;
|
||||||
|
return this.items[realIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
private resize(): void {
|
||||||
|
const newCapacity = this.items.length * 2 || 4;
|
||||||
|
const newItems = new Array<T>(newCapacity);
|
||||||
|
|
||||||
|
for (let i = 0; i < this.count; i++) {
|
||||||
|
newItems[i] = this.get(i)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.items = newItems;
|
||||||
|
this.start = 0;
|
||||||
|
this.end = this.count;
|
||||||
|
}
|
||||||
|
}
|
||||||
7
src/day1/SinglyLinkedList.test.ts
Normal file
7
src/day1/SinglyLinkedList.test.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import SinglyLinkedList from "@code/SinglyLinkedList";
|
||||||
|
import { test_list } from "./ListTest";
|
||||||
|
|
||||||
|
test("linked-list", function () {
|
||||||
|
const list = new SinglyLinkedList<number>();
|
||||||
|
test_list(list);
|
||||||
|
});
|
||||||
138
src/day1/SinglyLinkedList.ts
Normal file
138
src/day1/SinglyLinkedList.ts
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
class Node<T> {
|
||||||
|
public value: T;
|
||||||
|
public next?: Node<T>;
|
||||||
|
|
||||||
|
constructor(t: T) {
|
||||||
|
this.value = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class SinglyLinkedList<T> {
|
||||||
|
public length: number;
|
||||||
|
public head?: Node<T>;
|
||||||
|
public tail?: Node<T>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.length = 0;
|
||||||
|
this.head = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
prepend(item: T): void {
|
||||||
|
let node = new Node<T>(item);
|
||||||
|
if (this.head != null) {
|
||||||
|
node.next = this.head;
|
||||||
|
}
|
||||||
|
this.head = node;
|
||||||
|
this.length++;
|
||||||
|
}
|
||||||
|
|
||||||
|
insertAt(item: T, idx: number): void {
|
||||||
|
let current_node = this.head;
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
while (current_node?.next != null && i < idx) {
|
||||||
|
current_node = current_node.next;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_node?.next != null) {
|
||||||
|
let node = new Node<T>(item);
|
||||||
|
node.next = current_node.next;
|
||||||
|
current_node.next = node;
|
||||||
|
this.length++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
append(item: T): void {
|
||||||
|
if (this.length == 0) {
|
||||||
|
let node = new Node<T>(item);
|
||||||
|
this.head = node;
|
||||||
|
this.length++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let current_node = this.head;
|
||||||
|
|
||||||
|
while (current_node?.next != null) {
|
||||||
|
current_node = current_node.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_node != null) {
|
||||||
|
let node = new Node<T>(item);
|
||||||
|
current_node.next = node;
|
||||||
|
this.length++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(item: T): T | undefined {
|
||||||
|
let current_node = this.head;
|
||||||
|
let prev_node = this.head;
|
||||||
|
let node_to_remove = null;
|
||||||
|
|
||||||
|
while (current_node != null) {
|
||||||
|
if (current_node.value === item) {
|
||||||
|
node_to_remove = current_node;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prev_node = current_node;
|
||||||
|
current_node = current_node.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node_to_remove == this.head) {
|
||||||
|
this.head = node_to_remove.next;
|
||||||
|
this.length--;
|
||||||
|
} else if (prev_node?.next != null) {
|
||||||
|
prev_node.next = node_to_remove?.next;
|
||||||
|
this.length--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return current_node?.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
get(idx: number): T | undefined {
|
||||||
|
let current_node = this.head;
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
while (current_node != null && i < idx) {
|
||||||
|
current_node = current_node.next;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return current_node?.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
removeAt(idx: number): T | undefined {
|
||||||
|
let current_node = this.head;
|
||||||
|
|
||||||
|
if (idx == 0 && current_node != null) {
|
||||||
|
this.head = current_node.next;
|
||||||
|
this.length--;
|
||||||
|
return current_node.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
while (current_node?.next != null && i < idx - 1) {
|
||||||
|
current_node = current_node.next;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_node?.next != null) {
|
||||||
|
let node_to_remove = current_node.next;
|
||||||
|
current_node.next = node_to_remove.next;
|
||||||
|
this.length--;
|
||||||
|
return node_to_remove.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug() {
|
||||||
|
let current_node = this.head;
|
||||||
|
let result = "";
|
||||||
|
while (current_node != null) {
|
||||||
|
result += ` ${current_node.value},`;
|
||||||
|
current_node = current_node.next;
|
||||||
|
}
|
||||||
|
console.log(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/day1/Stack.test.ts
Normal file
25
src/day1/Stack.test.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import Stack from "@code/Stack";
|
||||||
|
|
||||||
|
test("stack", function () {
|
||||||
|
const list = new Stack<number>();
|
||||||
|
|
||||||
|
list.push(5);
|
||||||
|
list.push(7);
|
||||||
|
list.push(9);
|
||||||
|
|
||||||
|
expect(list.pop()).toEqual(9);
|
||||||
|
expect(list.length).toEqual(2);
|
||||||
|
|
||||||
|
list.push(11);
|
||||||
|
expect(list.pop()).toEqual(11);
|
||||||
|
expect(list.pop()).toEqual(7);
|
||||||
|
expect(list.peek()).toEqual(5);
|
||||||
|
expect(list.pop()).toEqual(5);
|
||||||
|
expect(list.pop()).toEqual(undefined);
|
||||||
|
|
||||||
|
// just wanted to make sure that I could not blow up myself when i remove
|
||||||
|
// everything
|
||||||
|
list.push(69);
|
||||||
|
expect(list.peek()).toEqual(69);
|
||||||
|
expect(list.length).toEqual(1);
|
||||||
|
});
|
||||||
43
src/day1/Stack.ts
Normal file
43
src/day1/Stack.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
type Node<T> = {
|
||||||
|
value: T;
|
||||||
|
prev?: Node<T>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class Stack<T> {
|
||||||
|
public length: number;
|
||||||
|
private head?: Node<T>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.head = undefined;
|
||||||
|
this.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
push(item: T): void {
|
||||||
|
const node = { value: item } as Node<T>;
|
||||||
|
this.length++;
|
||||||
|
if (!this.head) {
|
||||||
|
this.head = node;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node.prev = this.head;
|
||||||
|
this.head = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
pop(): T | undefined {
|
||||||
|
this.length = Math.max(0, this.length - 1);
|
||||||
|
if (this.length === 0) {
|
||||||
|
const head = this.head;
|
||||||
|
this.head = undefined;
|
||||||
|
return head?.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const head = this.head as Node<T>;
|
||||||
|
this.head = head.prev;
|
||||||
|
return head?.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
peek(): T | undefined {
|
||||||
|
return this.head?.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/day1/Trie.test.ts
Normal file
15
src/day1/Trie.test.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import Trie from "@code/Trie";
|
||||||
|
|
||||||
|
test("Trie", function () {
|
||||||
|
const trie = new Trie();
|
||||||
|
trie.insert("foo");
|
||||||
|
trie.insert("fool");
|
||||||
|
trie.insert("foolish");
|
||||||
|
trie.insert("bar");
|
||||||
|
|
||||||
|
expect(trie.find("fo").sort()).toEqual(["foo", "fool", "foolish"]);
|
||||||
|
|
||||||
|
trie.delete("fool");
|
||||||
|
|
||||||
|
expect(trie.find("fo").sort()).toEqual(["foo", "foolish"]);
|
||||||
|
});
|
||||||
86
src/day1/Trie.ts
Normal file
86
src/day1/Trie.ts
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
type TrieNode = {
|
||||||
|
children: TrieNode[];
|
||||||
|
isValue: boolean;
|
||||||
|
value?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Creates a new TrieNode with defaults
|
||||||
|
function createTrieNode() {
|
||||||
|
return {
|
||||||
|
children: [],
|
||||||
|
isValue: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Char code for 'a'.
|
||||||
|
const start = "a".charCodeAt(0);
|
||||||
|
|
||||||
|
// Returns the distance from 'a' which can be used to index into an array.
|
||||||
|
function getIdx(item: string, idx: number): number {
|
||||||
|
return item.toLowerCase().charCodeAt(idx) - start;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Trie {
|
||||||
|
private head: TrieNode;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.head = createTrieNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
insert(item: string): void {
|
||||||
|
let current: TrieNode = this.head;
|
||||||
|
for (let i = 0; i < item.length; ++i) {
|
||||||
|
const letter = getIdx(item, i);
|
||||||
|
if (!current.children[letter]) {
|
||||||
|
current.children[letter] = createTrieNode();
|
||||||
|
}
|
||||||
|
current = current.children[letter];
|
||||||
|
}
|
||||||
|
|
||||||
|
current.isValue = true;
|
||||||
|
current.value = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(item: string): void {
|
||||||
|
let current: TrieNode = this.head;
|
||||||
|
for (let i = 0; current && i < item.length; ++i) {
|
||||||
|
current = current.children[getIdx(item, i)];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
current.value = undefined;
|
||||||
|
current.isValue = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
find(partial: string): string[] {
|
||||||
|
let current = this.head;
|
||||||
|
for (let i = 0; i < partial.length; ++i) {
|
||||||
|
current = current.children[getIdx(partial, i)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.findRecursively(current, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finds all the possible words to complete node.
|
||||||
|
private findRecursively(
|
||||||
|
node: TrieNode | undefined,
|
||||||
|
out: string[],
|
||||||
|
): string[] {
|
||||||
|
if (!node) {
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.isValue) {
|
||||||
|
out.push(node.value as string);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < node.children.length; ++i) {
|
||||||
|
this.findRecursively(node.children[i], out);
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/day1/TwoCrystalBalls.test.ts
Normal file
13
src/day1/TwoCrystalBalls.test.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import two_crystal_balls from "@code/TwoCrystalBalls";
|
||||||
|
|
||||||
|
test("two crystal balls", function () {
|
||||||
|
let idx = Math.floor(Math.random() * 10000);
|
||||||
|
const data = new Array(10000).fill(false);
|
||||||
|
|
||||||
|
for (let i = idx; i < 10000; ++i) {
|
||||||
|
data[i] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(two_crystal_balls(data)).toEqual(idx);
|
||||||
|
expect(two_crystal_balls(new Array(821).fill(false))).toEqual(-1);
|
||||||
|
});
|
||||||
20
src/day1/TwoCrystalBalls.ts
Normal file
20
src/day1/TwoCrystalBalls.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
export default function two_crystal_balls(breaks: boolean[]): number {
|
||||||
|
const jmpAmount = Math.floor(Math.sqrt(breaks.length));
|
||||||
|
|
||||||
|
let i = jmpAmount;
|
||||||
|
for (; i < breaks.length; i += jmpAmount) {
|
||||||
|
if (breaks[i]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i -= jmpAmount;
|
||||||
|
|
||||||
|
for (let j = 0; j < jmpAmount && i < breaks.length; j++, i++) {
|
||||||
|
if (breaks[i]) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
80
src/day1/graph.ts
Normal file
80
src/day1/graph.ts
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
export const list1: WeightedAdjacencyList = [];
|
||||||
|
|
||||||
|
// (1) --- (4) ---- (5)
|
||||||
|
// / | | /|
|
||||||
|
// (0) | ------|------- |
|
||||||
|
// \ |/ | |
|
||||||
|
// (2) --- (3) ---- (6)
|
||||||
|
list1[0] = [
|
||||||
|
{ to: 1, weight: 3 },
|
||||||
|
{ to: 2, weight: 1 },
|
||||||
|
];
|
||||||
|
list1[1] = [
|
||||||
|
{ to: 0, weight: 3 },
|
||||||
|
{ to: 2, weight: 4 },
|
||||||
|
{ to: 4, weight: 1 },
|
||||||
|
];
|
||||||
|
list1[2] = [
|
||||||
|
{ to: 1, weight: 4 },
|
||||||
|
{ to: 3, weight: 7 },
|
||||||
|
{ to: 0, weight: 1 },
|
||||||
|
];
|
||||||
|
list1[3] = [
|
||||||
|
{ to: 2, weight: 7 },
|
||||||
|
{ to: 4, weight: 5 },
|
||||||
|
{ to: 6, weight: 1 },
|
||||||
|
];
|
||||||
|
list1[4] = [
|
||||||
|
{ to: 1, weight: 1 },
|
||||||
|
{ to: 3, weight: 5 },
|
||||||
|
{ to: 5, weight: 2 },
|
||||||
|
];
|
||||||
|
list1[5] = [
|
||||||
|
{ to: 6, weight: 1 },
|
||||||
|
{ to: 4, weight: 2 },
|
||||||
|
{ to: 2, weight: 18 },
|
||||||
|
];
|
||||||
|
list1[6] = [
|
||||||
|
{ to: 3, weight: 1 },
|
||||||
|
{ to: 5, weight: 1 },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const list2: WeightedAdjacencyList = [];
|
||||||
|
|
||||||
|
// >(1)<--->(4) ---->(5)
|
||||||
|
// / | /|
|
||||||
|
// (0) ------|------- |
|
||||||
|
// \ v v v
|
||||||
|
// >(2) --> (3) <----(6)
|
||||||
|
list2[0] = [
|
||||||
|
{ to: 1, weight: 3 },
|
||||||
|
{ to: 2, weight: 1 },
|
||||||
|
];
|
||||||
|
list2[1] = [{ to: 4, weight: 1 }];
|
||||||
|
list2[2] = [{ to: 3, weight: 7 }];
|
||||||
|
list2[3] = [];
|
||||||
|
list2[4] = [
|
||||||
|
{ to: 1, weight: 1 },
|
||||||
|
{ to: 3, weight: 5 },
|
||||||
|
{ to: 5, weight: 2 },
|
||||||
|
];
|
||||||
|
list2[5] = [
|
||||||
|
{ to: 2, weight: 18 },
|
||||||
|
{ to: 6, weight: 1 },
|
||||||
|
];
|
||||||
|
list2[6] = [{ to: 3, weight: 1 }];
|
||||||
|
|
||||||
|
// >(1)<--->(4) ---->(5)
|
||||||
|
// / | /|
|
||||||
|
// (0) ------|------- |
|
||||||
|
// \ v v v
|
||||||
|
// >(2) --> (3) <----(6)
|
||||||
|
export const matrix2: WeightedAdjacencyMatrix = [
|
||||||
|
[0, 3, 1, 0, 0, 0, 0], // 0
|
||||||
|
[0, 0, 0, 0, 1, 0, 0],
|
||||||
|
[0, 0, 7, 0, 0, 0, 0],
|
||||||
|
[0, 0, 0, 0, 0, 0, 0],
|
||||||
|
[0, 1, 0, 5, 0, 2, 0],
|
||||||
|
[0, 0, 18, 0, 0, 0, 1],
|
||||||
|
[0, 0, 0, 1, 0, 0, 1],
|
||||||
|
];
|
||||||
87
src/day1/tree.ts
Normal file
87
src/day1/tree.ts
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
export const tree: BinaryNode<number> = {
|
||||||
|
value: 20,
|
||||||
|
right: {
|
||||||
|
value: 50,
|
||||||
|
right: {
|
||||||
|
value: 100,
|
||||||
|
right: null,
|
||||||
|
left: null,
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
value: 30,
|
||||||
|
right: {
|
||||||
|
value: 45,
|
||||||
|
right: null,
|
||||||
|
left: null,
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
value: 29,
|
||||||
|
right: null,
|
||||||
|
left: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
value: 10,
|
||||||
|
right: {
|
||||||
|
value: 15,
|
||||||
|
right: null,
|
||||||
|
left: null,
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
value: 5,
|
||||||
|
right: {
|
||||||
|
value: 7,
|
||||||
|
right: null,
|
||||||
|
left: null,
|
||||||
|
},
|
||||||
|
left: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const tree2: BinaryNode<number> = {
|
||||||
|
value: 20,
|
||||||
|
right: {
|
||||||
|
value: 50,
|
||||||
|
right: null,
|
||||||
|
left: {
|
||||||
|
value: 30,
|
||||||
|
right: {
|
||||||
|
value: 45,
|
||||||
|
right: {
|
||||||
|
value: 49,
|
||||||
|
left: null,
|
||||||
|
right: null,
|
||||||
|
},
|
||||||
|
left: null,
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
value: 29,
|
||||||
|
right: null,
|
||||||
|
left: {
|
||||||
|
value: 21,
|
||||||
|
right: null,
|
||||||
|
left: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
value: 10,
|
||||||
|
right: {
|
||||||
|
value: 15,
|
||||||
|
right: null,
|
||||||
|
left: null,
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
value: 5,
|
||||||
|
right: {
|
||||||
|
value: 7,
|
||||||
|
right: null,
|
||||||
|
left: null,
|
||||||
|
},
|
||||||
|
left: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
52
src/global.d.ts
vendored
Normal file
52
src/global.d.ts
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
declare type Point = {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
declare type ListNode<T> = {
|
||||||
|
value: T;
|
||||||
|
next?: ListNode<T>;
|
||||||
|
prev?: ListNode<T>;
|
||||||
|
};
|
||||||
|
|
||||||
|
declare interface List<T> {
|
||||||
|
get length(): number;
|
||||||
|
removeAt(index: number): T | undefined;
|
||||||
|
remove(item: T): T | undefined;
|
||||||
|
get(index: number): T | undefined;
|
||||||
|
prepend(item: T): void;
|
||||||
|
append(item: T): void;
|
||||||
|
insertAt(item: T, idx: number): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare type CompleteGraphEdge = { from: number; to: number; weight: number };
|
||||||
|
declare type GraphEdge = { to: number; weight: number };
|
||||||
|
declare type WeightedAdjacencyList = GraphEdge[][];
|
||||||
|
// A number means weight
|
||||||
|
declare type WeightedAdjacencyMatrix = number[][];
|
||||||
|
|
||||||
|
declare type AdjacencyList = number[][];
|
||||||
|
// A 1 means connected
|
||||||
|
declare type AdjacencyMatrix = number[][];
|
||||||
|
|
||||||
|
declare type BinaryNode<T> = {
|
||||||
|
value: T;
|
||||||
|
left: BinaryNode<T> | null;
|
||||||
|
right: BinaryNode<T> | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
declare type GeneralNode<T> = {
|
||||||
|
value: T;
|
||||||
|
children: GeneralNode<T>[];
|
||||||
|
};
|
||||||
|
|
||||||
|
declare interface ILRU<K, V> {
|
||||||
|
update(key: K, value: V): void;
|
||||||
|
get(key: K): V | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare type BinaryNode<T> = {
|
||||||
|
value: T;
|
||||||
|
left: BinaryNode<T> | null;
|
||||||
|
right: BinaryNode<T> | null;
|
||||||
|
};
|
||||||
19
tsconfig.json
Normal file
19
tsconfig.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "dist",
|
||||||
|
"allowJs": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"target": "esnext",
|
||||||
|
"module": "commonjs",
|
||||||
|
"baseUrl": "src",
|
||||||
|
"paths": {
|
||||||
|
"@code/*": ["day1/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": ["./src/**/*"],
|
||||||
|
"exclude": ["node_modules"]
|
||||||
|
}
|
||||||
15
vitest.config.ts
Normal file
15
vitest.config.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { defineConfig } from "vitest/config";
|
||||||
|
import path from "path";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
"@code": path.resolve(__dirname, "src/day1"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
globals: true,
|
||||||
|
environment: "node",
|
||||||
|
include: ["src/**/*.test.{ts,js}"],
|
||||||
|
},
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user