Watch
1
0
Fork
You've already forked kata-machine
0

Initial commit

This commit is contained in:
Chris 2025-12-16 20:39:11 +00:00
commit 8ae9352aa1
70 changed files with 3898 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
node_modules/

11
README.md Normal file
View file

@ -0,0 +1,11 @@
# kata-machine
Kata machine practice.
https://frontendmasters.com/courses/algorithms/
https://github.com/ThePrimeagen/kata-machine
1. `pnpm install`
2. `pnpm run test`

20
package.json Normal file
View file

@ -0,0 +1,20 @@
{
"name": "test-kata-machine",
"version": "0.0.1",
"scripts": {
"check": "tsc --noEmit",
"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

File diff suppressed because it is too large Load diff

8
prettier.config.ts Normal file
View 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
View 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)));
});

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

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

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

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

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

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

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

Some files were not shown because too many files have changed in this diff Show more