Lol idek
This commit is contained in:
8 files changed
+269
-5
No files matched your search
+1
-1
@@ -9,7 +9,7 @@
|
||||
- Fixed range not working with a reversed range
|
||||
- Deprecated choose and shuffle, use the methods on the Random class in rng.ts instead!
|
||||
- EventStream: Moved EventStream from iterable.ts to async.ts
|
||||
- pinkyPromise: Moved pinkyPromise from iterable.ts to async.ts
|
||||
- pinkyPromise: Moqved pinkyPromise from iterable.ts to async.ts
|
||||
- rng.ts
|
||||
- Added RNG.chooseWithWeights
|
||||
- string.ts
|
||||
|
||||
+69
@@ -74,6 +74,75 @@ export function textNode(templ: string | TemplateStringsArray, ...values: unknow
|
||||
return document.createTextNode(string)
|
||||
}
|
||||
|
||||
/**
|
||||
* FLIP is a mnemonic device for effective JavaScript animations: First, Last, Invert, Play.
|
||||
* This helper class makes it easy to perform FLIP animations.
|
||||
*
|
||||
* https://aerotwist.com/blog/flip-your-animations/
|
||||
*
|
||||
* @author MindfulMinun
|
||||
* @since 2022-12-31
|
||||
*/
|
||||
class _FlipAnimator {
|
||||
el: Element
|
||||
#first: DOMRect | null = null
|
||||
|
||||
constructor(el: Element) {
|
||||
this.el = el
|
||||
this.#first = null
|
||||
}
|
||||
|
||||
/**
|
||||
* This method immediately performs a FLIP animation.
|
||||
* The caller must pass in a callback that describes the transition between the first and last states.
|
||||
*/
|
||||
async flip(cb: (this: Element, el: Element, rect: DOMRect) => Promise<void> | void, options: KeyframeAnimationOptions = {}) {
|
||||
// Get the current state of the element
|
||||
this.recordFirstState()
|
||||
|
||||
// Call the callback. The callback should change the element's DOMRect.
|
||||
await cb.call(this.el, this.el, this.#first!)
|
||||
|
||||
// Animate the element from the first state to the last state
|
||||
return this.animateFromFirst(options)
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures the initial DOMRect of the element.
|
||||
* The caller may also pass in a DOMRect to use instead of querying the DOM.
|
||||
*/
|
||||
recordFirstState(rect: DOMRect = this.el.getBoundingClientRect()) {
|
||||
this.#first = rect
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Using the captured first state, this method will animate the element
|
||||
* from the first state to the last state.
|
||||
* Then this method will clear the DOMRects.
|
||||
*/
|
||||
animateFromFirst(options: KeyframeAnimationOptions = {}) {
|
||||
if (!this.#first) throw new Error('No first state recorded.')
|
||||
const last = this.el.getBoundingClientRect()
|
||||
|
||||
const deltaX = this.#first.left - last.left
|
||||
const deltaY = this.#first.top - last.top
|
||||
const scaleX = this.#first.width / last.width
|
||||
const scaleY = this.#first.height / last.height
|
||||
|
||||
this.#first = null
|
||||
|
||||
return this.el.animate([
|
||||
{ transform: `translate(${deltaX}px, ${deltaY}px) scale(${scaleX}, ${scaleY})` },
|
||||
{ transform: 'none' }
|
||||
], {
|
||||
duration: 300,
|
||||
easing: 'ease-in-out',
|
||||
...options
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks the DOM recursively, calling the callback for each node.
|
||||
* @deprecated
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* HTML escape sequences for unsafe characters
|
||||
*/
|
||||
export const HTML_ESCAPES = {
|
||||
export const HTML_ESCAPES = {
|
||||
"&": "&",
|
||||
"<": "<",
|
||||
">": ">",
|
||||
@@ -91,6 +91,6 @@ export function templateNoop(
|
||||
* @author MindfulMinun
|
||||
* @since 2020-06-23
|
||||
*/
|
||||
export function xss(unsafe: string): string {
|
||||
export function xss(unsafe: string): string {
|
||||
return unsafe.replace(/[&<>"'\/]/g, key => HTML_ESCAPES[key as keyof typeof HTML_ESCAPES])
|
||||
}
|
||||
@@ -1 +1,14 @@
|
||||
# pear 🍐
|
||||
|
||||
|
||||
<!--
|
||||
Endgames:
|
||||
Matrix:
|
||||
Eigendecomposition, Singular Value Decomposition, LU Decomposition, QR Decomposition, Cholesky Decomposition
|
||||
Dynamic Programming:
|
||||
Edit distance, Longest Common Subsquence
|
||||
Graphs:
|
||||
Dijkstra's, Prim, Kruskal
|
||||
Bellman-Ford, Floyd-Warshall
|
||||
Ford-Fulkerson
|
||||
-->
|
||||
+1
-1
@@ -39,7 +39,7 @@ Deno.test('GraphSolver::DFS w/ g1', () => {
|
||||
)
|
||||
})
|
||||
|
||||
Deno.test('GraphSolver::bidi', () => {
|
||||
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')!)
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
import { fill } from "../../core/iterable.ts"
|
||||
import * as Colors from "https://deno.land/[email protected]/fmt/colors.ts"
|
||||
|
||||
class Matrix {
|
||||
/** The number of rows in this matrix. */
|
||||
m: number
|
||||
/** The number of columns in this matrix. */
|
||||
n: number
|
||||
/** The values stored in this matrix, in row-major order. */
|
||||
entries: number[]
|
||||
|
||||
constructor(m: number, n: number, entries: number[]) {
|
||||
const expectedLength = m * n
|
||||
if (entries.length !== expectedLength) {
|
||||
throw new Error(`Expected ${expectedLength} entries, got ${entries.length}`)
|
||||
}
|
||||
this.m = m
|
||||
this.n = n
|
||||
this.entries = entries
|
||||
}
|
||||
|
||||
/** Performs naive matrix multiplication. */
|
||||
rightMultiply(right: Matrix) {
|
||||
if (this.n !== right.m) {
|
||||
throw new Error(`Cannot multiply ${this.m}x${this.n} matrix by ${right.m}x${right.n} matrix.`)
|
||||
}
|
||||
const result = Matrix.null(this.m, right.n)
|
||||
for (let i = 0; i < this.m; i++) {
|
||||
for (let j = 0; j < right.n; j++) {
|
||||
let sum = 0
|
||||
for (let k = 0; k < this.n; k++) {
|
||||
sum += this.get(i, k) * right.get(k, j)
|
||||
}
|
||||
result.set(i, j, sum)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
leftMultiply(left: Matrix) {
|
||||
return left.rightMultiply(this)
|
||||
}
|
||||
|
||||
set(row: number, col: number, value: number) {
|
||||
const offset = this.#calculateOffset(row, col)
|
||||
this.entries[offset] = value
|
||||
}
|
||||
|
||||
get(row: number, col: number) {
|
||||
const offset = this.#calculateOffset(row, col)
|
||||
return this.entries[offset]
|
||||
}
|
||||
|
||||
toString() {
|
||||
const strs = this.entries.map(e => e.toString())
|
||||
const maxLen = Math.max(...strs.map(s => s.length))
|
||||
const padded = strs.map(s => s.padStart(maxLen, ' '))
|
||||
|
||||
let out = ""
|
||||
for (let i = 0; i < this.m; i++) {
|
||||
if (i != 0) out += '\n'
|
||||
out += Colors.gray(i === 0 ? '┌ ' : i === this.m - 1 ? '└ ' : '│ ')
|
||||
// out += Colors.gray('│ ')
|
||||
|
||||
for (let j = 0; j < this.n; j++) {
|
||||
const offset = this.#calculateOffset(i, j)
|
||||
const value = this.entries[offset]
|
||||
const txt = padded[offset]
|
||||
out += (value == 0 ? Colors.gray(txt) : txt) + ' '
|
||||
}
|
||||
out += Colors.gray(i === 0 ? '┐ ' : i === this.m - 1 ? '┘ ' : '│ ')
|
||||
// out += Colors.gray('│')
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
[Symbol.for("Deno.customInspect")]() {
|
||||
return this.toString()
|
||||
}
|
||||
|
||||
#calculateOffset(row: number, col: number) {
|
||||
if (!(0 <= row || row < this.m)) {
|
||||
throw new Error(`Row ${row} is out of bounds for ${this.m}x${this.n} matrix.`)
|
||||
}
|
||||
if (!(0 <= col || col < this.n)) {
|
||||
throw new Error(`Column ${col} is out of bounds for ${this.m}x${this.n} matrix.`)
|
||||
}
|
||||
return row * this.n + col
|
||||
}
|
||||
|
||||
copy() {
|
||||
return new Matrix(this.m, this.n, this.entries.slice())
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs Gaussian elimination on this matrix, transforming it into an upper triangular matrix.
|
||||
* Note that this method does NOT mutate the original matrix, instead returning a new one.
|
||||
* If the matrix is singular, null is returned.
|
||||
* @author MindfulMinun
|
||||
* @since 2023-01-06
|
||||
*/
|
||||
toUpperTriangular() {
|
||||
const A = this.copy()
|
||||
const m = A.m
|
||||
const n = A.n
|
||||
for (let i = 0; i < m; i++) {
|
||||
// Find the pivot row.
|
||||
let pivotRow = i
|
||||
for (let j = i + 1; j < m; j++) {
|
||||
if (Math.abs(A.get(j, i)) > Math.abs(A.get(pivotRow, i))) {
|
||||
pivotRow = j
|
||||
}
|
||||
}
|
||||
|
||||
// Swap the pivot row with the current row.
|
||||
for (let j = 0; j < n; j++) {
|
||||
const temp = A.get(i, j)
|
||||
A.set(i, j, A.get(pivotRow, j))
|
||||
A.set(pivotRow, j, temp)
|
||||
}
|
||||
|
||||
// Eliminate the current column.
|
||||
for (let j = i + 1; j < m; j++) {
|
||||
const factor = A.get(j, i) / A.get(i, i)
|
||||
if (!Number.isFinite(factor)) return null
|
||||
for (let k = i; k < n; k++) {
|
||||
A.set(j, k, A.get(j, k) - factor * A.get(i, k))
|
||||
}
|
||||
}
|
||||
}
|
||||
return A
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new matrix with the given dimensions and entries.
|
||||
* All entries are initialized to 0.
|
||||
*/
|
||||
static null(m: number, n: number) {
|
||||
const zeroes = Array.from(fill(0, m * n))
|
||||
return new Matrix(m, n, zeroes)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a square identity matrix with the given dimension.
|
||||
* An identity matrix is a square matrix with 1s on the diagonal and 0s everywhere else.
|
||||
*/
|
||||
static identity(n: number) {
|
||||
const I = Matrix.null(n, n)
|
||||
for (let i = 0; i < n; i++) {
|
||||
I.set(i, i, 1)
|
||||
}
|
||||
return I
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (import.meta.main) {
|
||||
// const A = new Matrix(3, 3, [
|
||||
// 2, -1, 0,
|
||||
// -1, 2, -1,
|
||||
// 0, -3, 4
|
||||
// ])
|
||||
const A = new Matrix(4, 4, [
|
||||
16, 2, 3, 13,
|
||||
5 , 11, 10, 8,
|
||||
9 , 7, 6, 12,
|
||||
4 , 14, 15, 1,
|
||||
])
|
||||
const x = new Matrix(3, 1, [0, 0, 1])
|
||||
// const A = Matrix.identity(10)
|
||||
|
||||
console.log(A)
|
||||
console.log(A.toUpperTriangular())
|
||||
// console.log(x)
|
||||
// const b = A.rightMultiply(x)
|
||||
// console.log(b)
|
||||
}
|
||||
@@ -51,6 +51,7 @@ export function* primes(): Generator<number, never, undefined> {
|
||||
}
|
||||
|
||||
function _isPrime(n: number) {
|
||||
if (n % 1 !== 0) return false
|
||||
if (n < 2) return false
|
||||
|
||||
if (Number.MAX_SAFE_INTEGER < n) throw Error("Number is too large to verify X(")
|
||||
@@ -70,11 +71,13 @@ function _isPrime(n: number) {
|
||||
* @since 2022-10-13
|
||||
*/
|
||||
export function isPrime(n: number): boolean {
|
||||
if (n % 1 !== 0) return false
|
||||
if (n < 2) return false
|
||||
|
||||
// To verify if a number is prime, we only need to check if it is divisible by
|
||||
// any of the primes less than or equal to its square root.
|
||||
|
||||
const sqrt = Math.ceil(Math.sqrt(n))
|
||||
|
||||
for (const prime of primes()) {
|
||||
if (n % prime === 0) return false
|
||||
if (sqrt < prime) break
|
||||
|
||||
@@ -28,6 +28,7 @@ export class Stack<T> implements Iterable<T> {
|
||||
return el
|
||||
}
|
||||
|
||||
/** Preview the topmost element of the stack without removing it. */
|
||||
peek(): T | undefined {
|
||||
if (this.length === 0) return undefined
|
||||
return this.#elements[this.#head - 1]
|
||||
@@ -73,6 +74,7 @@ export class Queue<T> implements Iterable<T> {
|
||||
return el
|
||||
}
|
||||
|
||||
/** Preview the next element in the queue without removing it. */
|
||||
peek(): T | undefined {
|
||||
if (this.length === 0) return undefined
|
||||
return this.#elements[this.#head]
|
||||
|
||||
Reference in new issue
Block a user