Refactor (1)
This commit is contained in:
12
packages/utils/src/array.ts
Normal file
12
packages/utils/src/array.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export const sample = <T>(arr: readonly T[]): T =>
|
||||
arr[Math.floor(Math.random() * arr.length)] as T;
|
||||
|
||||
export function sampleMany<T>(arr: T[], n: number = arr.length): T[] {
|
||||
if (n > arr.length) return sampleMany(arr, arr.length);
|
||||
const copy = [...arr];
|
||||
for (let i = 0; i < n; i++) {
|
||||
const j = i + Math.floor(Math.random() * (copy.length - i));
|
||||
[copy[i], copy[j]] = [copy[j] as T, copy[i] as T];
|
||||
}
|
||||
return copy.slice(0, n);
|
||||
}
|
||||
40
packages/utils/src/headless.ts
Normal file
40
packages/utils/src/headless.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
export {};
|
||||
|
||||
declare global {
|
||||
interface String {
|
||||
startsWith<S extends string>(searchString: S): this is `${S}${string}`;
|
||||
endsWith<S extends string>(searchString: S): this is `${string}${S}`;
|
||||
includes<S extends string>(
|
||||
searchString: S,
|
||||
position?: number,
|
||||
): this is `${string}${S}${string}`;
|
||||
}
|
||||
|
||||
type LiteralUnionLike<T> = T extends string
|
||||
? T extends ""
|
||||
? T
|
||||
: T extends `${T}${T}`
|
||||
? never
|
||||
: T
|
||||
: T extends number
|
||||
? `${T}0` extends `${number}`
|
||||
? T
|
||||
: never
|
||||
: T extends null | undefined
|
||||
? T
|
||||
: never;
|
||||
|
||||
interface Array<T> {
|
||||
includes(
|
||||
searchElement: T extends LiteralUnionLike<T> ? unknown : never,
|
||||
fromIndex?: number,
|
||||
): searchElement is T extends LiteralUnionLike<T> ? T : never;
|
||||
}
|
||||
|
||||
interface ReadonlyArray<T> {
|
||||
includes(
|
||||
searchElement: T extends LiteralUnionLike<T> ? unknown : never,
|
||||
fromIndex?: number,
|
||||
): searchElement is T extends LiteralUnionLike<T> ? T : never;
|
||||
}
|
||||
}
|
||||
54
packages/utils/src/multiset.ts
Normal file
54
packages/utils/src/multiset.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
export class MultiSet<T> extends Map<T, number> {
|
||||
constructor(iterable?: Iterable<readonly [T, number]>) {
|
||||
super();
|
||||
if (iterable) {
|
||||
for (const [item, count] of iterable) {
|
||||
this.add(item, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified item to the multiset.
|
||||
* If the item already exists, its count is incremented.
|
||||
*
|
||||
* @param item The element to add.
|
||||
* @param count The number of times to add the element (default is 1).
|
||||
* @returns The current instance for chaining.
|
||||
*/
|
||||
add(item: T, count = 1): this {
|
||||
const currentCount = this.get(item) ?? 0;
|
||||
this.set(item, currentCount + count);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes one or more instances of the specified item.
|
||||
*
|
||||
* @param item The element to remove.
|
||||
* @param count The number of times to remove the element (default is 1).
|
||||
* @returns True if the element was present, false otherwise.
|
||||
*/
|
||||
remove(item: T, count = 1): boolean {
|
||||
const currentCount = this.get(item);
|
||||
if (currentCount === undefined) {
|
||||
return false;
|
||||
}
|
||||
if (currentCount <= count) {
|
||||
this.delete(item);
|
||||
} else {
|
||||
this.set(item, currentCount - count);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the count of the specified item.
|
||||
*
|
||||
* @param item The element whose count is to be retrieved.
|
||||
* @returns The number of occurrences of the element.
|
||||
*/
|
||||
count(item: T): number {
|
||||
return this.get(item) ?? 0;
|
||||
}
|
||||
}
|
||||
28
packages/utils/src/vector.ts
Normal file
28
packages/utils/src/vector.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
export type Vector = {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
|
||||
export type Radian = number;
|
||||
|
||||
export const degree = (value: number) => ((value / 180) * Math.PI) as Radian;
|
||||
|
||||
export const sub = (v1: Vector, v2: Vector) =>
|
||||
({
|
||||
x: v1.x - v2.x,
|
||||
y: v1.y - v2.y,
|
||||
}) as Vector;
|
||||
|
||||
export const add = (v1: Vector, v2: Vector) =>
|
||||
({
|
||||
x: v1.x + v2.x,
|
||||
y: v1.y + v2.y,
|
||||
}) as Vector;
|
||||
|
||||
export const theta = ({ x, y }: Vector) => Math.atan2(y, x) as Radian;
|
||||
|
||||
export const rotate = ({ x, y }: Vector, rad: Radian) =>
|
||||
({
|
||||
x: x * Math.cos(rad) - y * Math.sin(rad),
|
||||
y: x * Math.sin(rad) + y * Math.cos(rad),
|
||||
}) as Vector;
|
||||
Reference in New Issue
Block a user