This commit is contained in:
mindfulminun committed 2024-07-20 15:30:48 -05:00
1 parent 9cf0bf415b
commit 71323fc7fd
25 files changed
+186 -94

No files matched your search

+3
View File
@@ -0,0 +1,3 @@
{
"discord.enabled": false
}
+4 -4
View File
@@ -46,7 +46,7 @@ export class EventStream<T> implements AsyncIterable<T> {
this.#promise = new Promise(r => this.#resolve = r)
}
async*[Symbol.asyncIterator]() {
async*[Symbol.asyncIterator](): AsyncGenerator<Awaited<T>, void, undefined> {
while (!this.#done) {
await this.#promise
yield* this.#events
@@ -74,7 +74,7 @@ export class EventStream<T> implements AsyncIterable<T> {
* const click = stream.once(ev => ev.type === 'click')
* @since 2021-12-22
*/
once(predicate: (value: T) => boolean) {
once(predicate: (value: T) => boolean): Promise<Awaited<T> | undefined> {
return once(this, predicate)
}
@@ -93,7 +93,7 @@ export class EventStream<T> implements AsyncIterable<T> {
* @author MindfulMinun
* @since 2024-06-02
*/
each(callback: (value: T) => void) {
each(callback: (value: T) => void): Promise<void> {
return each(this, callback)
}
}
@@ -107,7 +107,7 @@ export class EventStream<T> implements AsyncIterable<T> {
* const click = once(stream, ev => ev.type === 'click')
* @since 2021-12-22
*/
export async function once<T>(source: AsyncIterable<T>, predicate: (value: T) => boolean) {
export async function once<T>(source: AsyncIterable<T>, predicate: (value: T) => boolean): Promise<T | undefined> {
for await (const value of source) {
if (predicate(value)) return value
}
+1 -1
View File
@@ -1,4 +1,4 @@
/// <reference lib="dom" />
// <reference lib="dom" />
import { templateNoop, HTML_ESCAPES, xss } from "./string.ts"
export { HTML_ESCAPES }
+5 -2
View File
@@ -61,7 +61,7 @@ export function* range(a: number, b?: number, c?: number) {
* @author MindfulMinun
* @since 2022-07-07
*/
export function* limit<T>(count: number, iterable: Iterable<T>) {
export function* limit<T>(count: number, iterable: Iterable<T>): Generator<T, void, unknown> {
let i = 0
for (const value of iterable) {
if (i < count) {
@@ -77,7 +77,10 @@ export function* limit<T>(count: number, iterable: Iterable<T>) {
* @author MindfulMinun
* @since 2022-07-07
*/
export async function* limitAsync<T>(count: number, iterable: AsyncIterable<T>) {
export async function* limitAsync<T>(
count: number,
iterable: AsyncIterable<T>
): AsyncGenerator<Awaited<T>, void, unknown> {
let i = 0
for await (const value of iterable) {
if (i < count) {
+5 -7
View File
@@ -3,10 +3,8 @@
* @author MindfulMinun <https://benjic.xyz>
* @license MIT
*/
console.error("Hey there, past me! Please don't import `mod.ts`, instead import specific files!")
// export * from "./array.ts"
// export * from "./helpers.ts"
// export * from "./math.ts"
// export * from "./dom.ts"
export * as async from './async.ts'
export * as dom from './dom.ts'
export * as rng from './rng.ts'
export * as shell from './shell.ts'
export * as string from './string.ts'
+9 -9
View File
@@ -24,7 +24,7 @@ export abstract class RNG implements Iterable<number> {
* @author MindfulMinun
* @since 2022-07-16
*/
*[Symbol.iterator]() {
*[Symbol.iterator](): Generator<number, void, unknown> {
while (true) yield this.float()
}
@@ -34,7 +34,7 @@ export abstract class RNG implements Iterable<number> {
* @author MindfulMinun
* @since 2022-07-16
*/
float() {
float(): number {
return this.nextValue()
}
@@ -55,7 +55,7 @@ export abstract class RNG implements Iterable<number> {
* @author MindfulMinun
* @since 2022-07-16
*/
choose<T>(arr: T[]) {
choose<T>(arr: T[]): T {
return arr[Math.floor(this.float() * arr.length)]
}
@@ -65,7 +65,7 @@ export abstract class RNG implements Iterable<number> {
* @author MindfulMinun
* @since 2022-07-16
*/
shuffle<T>(arr: T[]) {
shuffle<T>(arr: T[]): T[] {
let i, j
for (i = arr.length - 1; i > 0; i--) {
j = Math.floor(this.float() * (i + 1))
@@ -89,7 +89,7 @@ export abstract class RNG implements Iterable<number> {
* @author MindfulMinun
* @since 2022-07-16
*/
chooseWithWeights<T>(items: T[], weights: number[]) {
chooseWithWeights<T>(items: T[], weights: number[]): T {
if (items.length != weights.length) throw Error(`Expected items and weights to have the same number of elements, but items has ${items.length} elements, and weights has ${weights.length}.`)
const sumOfWeights = weights.reduce((acc, v) => acc + v)
@@ -113,7 +113,7 @@ export abstract class RNG implements Iterable<number> {
* @since 2022-07-08
*/
export class Random extends RNG {
nextValue() { return Math.random() }
nextValue(): number { return Math.random() }
}
/**
@@ -125,18 +125,18 @@ export class Mulberry32 extends RNG {
#seed!: number
originalSeed!: number
constructor(seed = Date.now()) {
constructor(seed: number = Date.now()) {
super()
this.resetSeed(seed)
}
/** Resets the seed */
resetSeed(seed = this.#seed) {
resetSeed(seed: number = this.#seed) {
this.originalSeed = seed
this.#seed = seed
}
nextValue() {
nextValue(): number {
// Mulberry32
let a = this.#seed
a |= 0
+9 -9
View File
@@ -38,24 +38,24 @@ export class Troopa implements PromiseLike<Deno.CommandOutput> {
* @author MindfulMinun
* @since 2023-12-26
*/
start() { return this.process }
start(): Deno.ChildProcess { return this.process }
get process() {
get process(): Deno.ChildProcess {
if (this.#process) return this.#process
this.#process = this.cmd.spawn()
return this.#process
}
get stdin() { return this.process.stdin }
get stdout() { return this.process.stdout }
get stderr() { return this.process.stderr }
get stdin(): WritableStream<Uint8Array> { return this.process.stdin }
get stdout(): ReadableStream<Uint8Array> { return this.process.stdout }
get stderr(): ReadableStream<Uint8Array> { return this.process.stderr }
response(src: 'stdout' | 'stderr' = 'stdout') {
response(src: 'stdout' | 'stderr' = 'stdout'): Response {
const source = this.process[src]
return new Response(source)
}
async code() {
async code(): Promise<number> {
return (await this).code
}
@@ -87,7 +87,7 @@ export class Troopa implements PromiseLike<Deno.CommandOutput> {
return this
}
async close() {
async close(): Promise<this> {
await this.writer.close()
return this
}
@@ -119,7 +119,7 @@ export class Troopa implements PromiseLike<Deno.CommandOutput> {
* Factory facade to easily interact and run shell scripts
* @since 2023-11-25
*/
export default function koopa(opts: Partial<ShellSpawnerOpts> = {}) {
export default function koopa(opts: Partial<ShellSpawnerOpts> = {}): ShellSpawner<Troopa> {
const actualOpts: ShellSpawnerOpts = {
shell: 'bash',
shellArgs: cmd => ['-c', `${opts.prefix || 'set -euo pipefail'}; ${cmd}`],
+24
View File
@@ -0,0 +1,24 @@
{
"name": "@mindfulminun/pear",
"version": "1.5.0",
"compilerOptions": {
"lib": ["dom.iterable", "esnext", "dom", "deno.ns"]
},
"exports": {
"./core": "./core/mod.ts",
"./core/async": "./core/async.ts",
// "./core/dom": "./core/dom.ts",
"./core/iterable": "./core/iterable.ts",
"./core/rng": "./core/rng.ts",
"./core/shell": "./core/shell.ts",
"./core/string": "./core/string.ts",
// "./tools": "./tools/",
"./tools/graph": "./tools/graph/mod.ts",
"./tools/graph-solver": "./tools/graph/graph-solver.ts",
"./tools/matrix": "./tools/math/matrix.ts",
"./tools/primes": "./tools/math/primes.ts",
"./tools/structures": "./tools/structures/mod.ts"
},
"imports": { "@std/fmt": "jsr:@std/fmt@^0.225.6" }
}
Generated
+32
View File
@@ -0,0 +1,32 @@
{
"version": "3",
"packages": {
"specifiers": {
"jsr:@std/fmt@^0.225.6": "jsr:@std/[email protected]"
},
"jsr": {
"@std/[email protected]": {
"integrity": "aba6aea27f66813cecfd9484e074a9e9845782ab0685c030e453a8a70b37afc8"
}
}
},
"redirects": {
"https://deno.land/std/testing/asserts.ts": "https://deno.land/[email protected]/testing/asserts.ts"
},
"remote": {
"https://deno.land/[email protected]/fmt/colors.ts": "30455035d6d728394781c10755351742dd731e3db6771b1843f9b9e490104d37",
"https://deno.land/[email protected]/testing/_diff.ts": "029a00560b0d534bc0046f1bce4bd36b3b41ada3f2a3178c85686eb2ff5f1413",
"https://deno.land/[email protected]/testing/_format.ts": "0d8dc79eab15b67cdc532826213bbe05bccfd276ca473a50a3fc7bbfb7260642",
"https://deno.land/[email protected]/testing/asserts.ts": "3eea146ece74b36d4add6243c19c302e47b2b0201fbeceeeb243b06b6b410af7",
"https://deno.land/[email protected]/fmt/colors.ts": "ff7dc9c9f33a72bd48bc24b21bbc1b4545d8494a431f17894dbc5fe92a938fc4",
"https://deno.land/[email protected]/fmt/colors.ts": "9e36a716611dcd2e4865adea9c4bec916b5c60caad4cdcdc630d4974e6bb8bd4",
"https://deno.land/[email protected]/testing/_diff.ts": "a23e7fc2b4d8daa3e158fa06856bedf5334ce2a2831e8bf9e509717f455adb2c",
"https://deno.land/[email protected]/testing/_format.ts": "cd11136e1797791045e639e9f0f4640d5b4166148796cad37e6ef75f7d7f3832",
"https://deno.land/[email protected]/testing/asserts.ts": "1e340c589853e82e0807629ba31a43c84ebdcdeca910c4a9705715dfdb0f5ce8"
},
"workspace": {
"dependencies": [
"jsr:@std/fmt@^0.225.6"
]
}
}
+1
View File
@@ -0,0 +1 @@
// TODO: write me!
@@ -1,6 +1,6 @@
import {
fill, range, limit
} from "../core/iterable.ts"
} from "../../core/iterable.ts"
import { assertEquals, assert } from "https://deno.land/[email protected]/testing/asserts.ts"
@@ -1,8 +1,8 @@
import { g1, g2, g3 } from '../tools/graph/_graph-samples.ts'
import { GraphSolver } from '../tools/graph/graph-solver.ts'
import { g1, g2, g3 } from '../../tools/graph/_graph-samples.ts'
import { GraphSolver } from '../../tools/graph/graph-solver.ts'
import { assertEquals } from "https://deno.land/std/testing/asserts.ts"
import { Path } from "../tools/graph/graph.ts"
import { dedent } from "../core/string.ts"
import { Path } from "../../tools/graph/mod.ts"
import { dedent } from "../../core/string.ts"
// TODO: Add more tests!
@@ -43,7 +43,10 @@ Deno.test('GraphSolver::DFS w/ g1', () => {
Deno.test('GraphSolver::bidi Path', () => {
const G = g3()
const solver = new GraphSolver(G)
const path = solver.bidi(G.vertices.get('A')!, G.vertices.get('E')!)
const path = solver.bidi({
source: G.vertices.get('A')!,
sink: G.vertices.get('E')!
})
assertPathsEqual(
path,
@@ -1,7 +1,7 @@
import { range } from "../core/iterable.ts";
import { Queue } from "../tools/structures/Queue.ts"
import { Stack } from "../tools/structures/Stack.ts"
import { BinaryHeap } from "../tools/structures/Heap.ts"
import { range } from "../../core/iterable.ts";
import { Queue } from "../../tools/structures/Queue.ts"
import { Stack } from "../../tools/structures/Stack.ts"
import { BinaryHeap } from "../../tools/structures/Heap.ts"
import { assertEquals } from "https://deno.land/[email protected]/testing/asserts.ts"
+3
View File
@@ -1 +1,4 @@
Implement Dijkstra's, Prim and Kruskal's, Topological sort, maybe like Ford-Fulkerson, maybe Christofides
export * as YAML from "https://esm.sh/yaml@2.3.4"
Use YAML format for storing graphs! Use references or something!
+1 -1
View File
@@ -1,4 +1,4 @@
import { Graph } from './graph.ts'
import { Graph } from './mod.ts'
// Box drawing characters!
// ┌ ┬ ┐ ─│
+19 -9
View File
@@ -1,4 +1,4 @@
import { Graph, Vertex, VertexType, Edge, EdgeType, Path, PathType } from "./graph.ts"
import { Graph, Vertex, VertexType, Edge, EdgeType, Path, PathType } from "./mod.ts"
import { Queue } from "../structures/Queue.ts"
import { Stack } from "../structures/Stack.ts"
import { BinaryHeap } from "../structures/Heap.ts"
@@ -89,20 +89,24 @@ export class GraphSolver<vData, eData> {
* @author MindfulMinun
* @since 2022-11-14
*/
bidi(left: Vertex<vData, eData>, right: Vertex<vData, eData>): Path<vData, eData> | null {
const qL = new Queue([left])
const qR = new Queue([right])
bidi({ source, sink, skipEdge }: {
source: Vertex<vData, eData>
sink: Vertex<vData, eData>
skipEdge?: <vData, eData>(e: Edge<vData, eData>, v: Vertex<vData, eData>, g: Graph<vData, eData>) => boolean
}): Path<vData, eData> | null {
const qL = new Queue([source])
const qR = new Queue([sink])
// Map a vertex to the path that led to it. Note that paths from the right
// will be reversed so they can be concatenated with the paths from the left.
const backL = new Map<Vertex<vData, eData>, Path<vData, eData>>()
const backR = new Map<Vertex<vData, eData>, Path<vData, eData>>()
backL.set(left, this.G.createPath(left))
backR.set(right, this.G.createPath(right))
backL.set(source, this.G.createPath(source))
backR.set(sink, this.G.createPath(sink))
const seenL = new Set<Vertex<vData, eData>>([left])
const seenR = new Set<Vertex<vData, eData>>([right])
const seenL = new Set<Vertex<vData, eData>>([source])
const seenR = new Set<Vertex<vData, eData>>([sink])
while (qL.length && qR.length) {
const l = qL.pop()!
@@ -113,6 +117,7 @@ export class GraphSolver<vData, eData> {
for (const E of l.adjacentEdges) {
if (E.directed && l !== E.u) continue
const w = E.not(l)
if (skipEdge?.(E, l, this.G) || false) continue
if (!seenL.has(w)) {
seenL.add(w)
const path = backL.get(l)!.copy()
@@ -129,6 +134,7 @@ export class GraphSolver<vData, eData> {
// Edge u -> v
if (E.directed && r !== E.v) continue
const w = E.not(r)
if (skipEdge?.(E, w, this.G) || false) continue
if (!seenR.has(w)) {
seenR.add(w)
const path = backR.get(r)!.copy()
@@ -166,7 +172,7 @@ export class GraphSolver<vData, eData> {
* @author MindfulMinun
* @since 2023-03-30
*/
kruskalWithSort() {
kruskalWithSort(): Set<Edge<vData, eData>> {
this.sortEdgesByWeight()
return this.kruskalPresorted()
}
@@ -228,4 +234,8 @@ export class GraphSolver<vData, eData> {
.map(e => [e.id, e] as const)
this.G.edges = new Map(edges)
}
floydWarshall() {
}
}
+21 -15
View File
@@ -1,4 +1,4 @@
import * as Colors from "https://deno.land/[email protected]/fmt/colors.ts"
import * as Colors from "@std/fmt/colors"
type UUID = string
@@ -60,7 +60,7 @@ export class Graph<vData, eData> {
this.vertices.delete(V.id)
}
createEdge(u: Vertex<vData, eData>, v: Vertex<vData, eData>, data: eData, opts: Partial<EdgeOpts> = {}) {
createEdge(u: Vertex<vData, eData>, v: Vertex<vData, eData>, data: eData, opts: Partial<EdgeOpts> = {}): Edge<vData, eData> {
const options: EdgeOpts = {
directed: this.directed,
id: crypto.randomUUID(),
@@ -81,14 +81,15 @@ export class Graph<vData, eData> {
}
createPath(start: Vertex<vData, eData>) {
createPath(start: Vertex<vData, eData>): Path<vData, eData> {
return new Path<vData, eData>(this, start)
}
// FIXME: return type
toJSON(
vertexReplacer: (this: Graph<vData, eData>, data: vData) => unknown = data => data,
edgeReplacer: (this: Graph<vData, eData>, data: eData) => unknown = data => data
) {
): unknown {
return {
"@graph": Graph.signature,
v: Array.from(this.vertices.values()).map(v => v.toJSON(vertexReplacer)),
@@ -100,7 +101,7 @@ export class Graph<vData, eData> {
json: unknown,
vertexReviver: (this: Graph<vData, eData>, json: unknown) => vData = data => data as vData,
edgeReviver: (this: Graph<vData, eData>, json: unknown) => eData = data => data as eData
) {
): Graph<vData, eData> {
const G = new Graph<vData, eData>()
if (!json || typeof json !== 'object') throw Error("Failed to parse: Unexpected object!")
@@ -172,15 +173,18 @@ export class Vertex<vData, eData> {
*/
delete() { this.graph.deleteVertex(this) }
toJSON(replacer: (this: Graph<vData, eData>, data: vData) => unknown = data => data) {
// FIXME: return type as tuple
toJSON(
replacer: (this: Graph<vData, eData>, data: vData) => unknown = data => data
): [unknown, unknown] {
return [this.id, replacer.call(this.graph, this.data)]
}
toString() {
toString(): string {
return Colors.cyan(`<${this.id.slice(0, 8)}>: ${this.data}`)
}
[Symbol.for("Deno.customInspect")]() {
[Symbol.for("Deno.customInspect")](): string {
return this.toString()
}
}
@@ -225,14 +229,16 @@ export class Edge<vData, eData> {
}
/** Given one vertex, get the opposite vertex of this edge */
not(v: typeof this.u | typeof this.v) {
not(v: typeof this.u | typeof this.v): Vertex<vData, eData> {
return this.v !== v ? this.v : this.u
}
delete() { this.graph.deleteEdge(this) }
toJSON(replacer: (this: Graph<vData, eData>, data: eData) => unknown = data => data) {
// tuple!
// FIXME: Type me as a tuple!
toJSON(
replacer: (this: Graph<vData, eData>, data: eData) => unknown = data => data
): [unknown, unknown, unknown, unknown, unknown] {
return [
this.id,
this.u.id,
@@ -242,11 +248,11 @@ export class Edge<vData, eData> {
]
}
toString() {
toString(): string {
return Colors.magenta(`<${this.id.slice(0, 8)}>: ${this.u} ${!this.directed ? '<' : ''}--> ${this.v}`)
}
[Symbol.for("Deno.customInspect")]() {
[Symbol.for("Deno.customInspect")](): string {
return this.toString()
}
}
@@ -276,7 +282,7 @@ export class Path<vData, eData> {
}
/** The vertices belonging to this path */
get vertices() {
get vertices(): Iterable<Vertex<vData, eData>> {
if (this.#vertices) return this.#vertices
const vertices: Vertex<vData, eData>[] = []
@@ -294,7 +300,7 @@ export class Path<vData, eData> {
return this.#vertices
}
copy() {
copy(): Path<vData, eData> {
const path = new Path<vData, eData>(this.graph, this.start ?? undefined)
path.edges = this.edges.slice()
path.#vertices = this.#vertices?.slice() ?? null
+14 -11
View File
@@ -1,6 +1,6 @@
import { fill } from "../../core/iterable.ts"
import * as Colors from "https://deno.land/[email protected]/fmt/colors.ts"
import { Memo } from "../structures.ts"
import * as Colors from "@std/fmt/colors"
import { Memo } from "../structures/Memo.ts"
const memodDeterminant = new Memo({
@@ -26,17 +26,17 @@ export class Matrix<M extends number = number, N extends number = number> {
this.entries = entries
}
set(row: number, col: number, value: number) {
set(row: number, col: number, value: number): void {
const offset = this.#calculateOffset(row, col)
this.entries[offset] = value
}
get(row: number, col: number) {
get(row: number, col: number): number {
const offset = this.#calculateOffset(row, col)
return this.entries[offset]
}
copy() {
copy(): Matrix<M, N> {
return new Matrix(this.m, this.n, this.entries.slice())
}
@@ -44,7 +44,9 @@ export class Matrix<M extends number = number, N extends number = number> {
* Performs naive matrix multiplication.
* @thorws If the dimensions of the matrices are incompatible.
*/
rightMultiply<P extends number, Q extends number>(right: Matrix<P, Q>) {
rightMultiply<P extends number, Q extends number>(
right: Matrix<P, Q>
): N & P extends never ? never : Matrix<M, Q> {
if (this.n as number !== right.m as number) {
throw new Error(`Cannot multiply ${this.m}x${this.n} matrix by ${right.m}x${right.n} matrix.`)
}
@@ -89,7 +91,8 @@ export class Matrix<M extends number = number, N extends number = number> {
/**
* Returns the submatrix obtained by removing the given row and column.
*/
laplaceExpansion(row: number, col: number) {
// FIXME: Type this correctly
laplaceExpansion(row: number, col: number): Matrix {
const matrix = Matrix.null(this.m - 1, this.n - 1)
matrix.entries = this.entries.filter((_, i) => {
const r = Math.floor(i / this.n)
@@ -106,7 +109,7 @@ export class Matrix<M extends number = number, N extends number = number> {
* @author MindfulMinun
* @since 2023-01-06
*/
toUpperTriangular() {
toUpperTriangular(): Matrix<M, N> | null {
const A = this.copy()
const { m, n } = A
for (let i = 0; i < m; i++) {
@@ -171,7 +174,7 @@ export class Matrix<M extends number = number, N extends number = number> {
}
}
toString() {
toString(): string {
let out = ''
out += 'Matrix<' + this.m + ', ' + this.n + '>['
out += this.entries.map(e => e.toString()).join(', ')
@@ -179,7 +182,7 @@ export class Matrix<M extends number = number, N extends number = number> {
return out
}
[Symbol.for("Deno.customInspect")]() {
[Symbol.for("Deno.customInspect")](): string {
const strs = this.entries.map(e => e.toString())
const maxLengths = Array.from(fill(0, this.n))
@@ -215,7 +218,7 @@ export class Matrix<M extends number = number, N extends number = number> {
* Creates a new matrix with the given numbers and entries.
* All entries are initialized to 0.
*/
static null<M extends number, N extends number>(m: M, n: N) {
static null<M extends number, N extends number>(m: M, n: N): Matrix<M, N> {
const zeroes = Array.from(fill(0, m * n))
return new Matrix(m, n, zeroes)
}
-4
View File
@@ -1,4 +0,0 @@
console.error("Hey there, past me! Please don't import `structures.ts`, instead import the specific structure you need.")
export * from './structures/Queue.ts'
export * from './structures/Stack.ts'
+2 -2
View File
@@ -24,7 +24,7 @@ export class BinaryHeap<T> implements Iterable<T> {
for (const el of initials) this.push(el)
}
*[Symbol.iterator]() {
*[Symbol.iterator](): Generator<NonNullable<T>, void, unknown> {
while (this.length !== 0) yield this.pop()!
}
@@ -112,5 +112,5 @@ export class BinaryHeap<T> implements Iterable<T> {
}
/** The number of elements in the heap */
get length() { return this.#elements.length }
get length(): number { return this.#elements.length }
}
+2 -2
View File
@@ -69,11 +69,11 @@ export class Memo<A extends unknown[], R extends unknown> {
return result
}
get ratio() {
get ratio(): number {
return this.hits / (this.hits + this.misses)
}
get fn() {
get fn(): (...args: A) => R {
return this.#memoHandler.bind(this)
}
}
+4 -2
View File
@@ -37,9 +37,11 @@ export class Queue<T> implements Iterable<T> {
}
/** The number of elements remaining in the queue */
get length() { return this.#tail - this.#head }
get length(): number {
return this.#tail - this.#head
}
*[Symbol.iterator]() {
*[Symbol.iterator](): Generator<NonNullable<T>, void, unknown> {
while (this.length !== 0) yield this.pop()!
}
}
+2 -2
View File
@@ -35,9 +35,9 @@ export class Stack<T> implements Iterable<T> {
}
/** The number of elements remaining in the stack */
get length() { return this.#head }
get length(): number { return this.#head }
*[Symbol.iterator]() {
*[Symbol.iterator](): Generator<NonNullable<T>, void, unknown> {
while (this.length !== 0) yield this.pop()!
}
}
+6 -4
View File
@@ -25,26 +25,28 @@ export class StateMachine<State extends string | number | symbol = 0, InputAlpha
this.reset()
}
runWithInput(elements: Iterable<InputAlphabet>) {
runWithInput(elements: Iterable<InputAlphabet>): this {
for (const element of elements) {
this.transitionWith(element)
}
return this
}
transitionWith(input: InputAlphabet) {
transitionWith(input: InputAlphabet): this {
const fn = this.#transitionTable[this.currentState]
if (!fn) throw new Error(`No transition function for state ${String(this.currentState)}`)
fn.call(this, input, this)
return this
}
goto(state: State) {
goto(state: State): this {
this.currentState = state
return this
}
accepts(state = this.currentState) { return this.#acceptStates.has(state) }
accepts(state = this.currentState): boolean {
return this.#acceptStates.has(state)
}
reset() {
this.currentState = this.#initialState
+6
View File
@@ -0,0 +1,6 @@
export * as DisjointSet from './DisjointSet.ts'
export * as Heap from './Heap.ts'
export * as Memo from './Memo.ts'
export * as Queue from './Queue.ts'
export * as Stack from './Stack.ts'
export * as StateMachine from './StateMachine.ts'