# Cerceis Library · `cerceis-lib`

> A quality-of-life utility library written in TypeScript.  
> Tree-shakeable · Dual CJS/ESM · Fully typed · Zero runtime dependencies

**Author:** Cerceis

---

## Installation

```bash
npm i cerceis-lib@latest
```

---

## Usage

```ts
// Named import from the main entry (tree-shakeable)
import { Generate } from "cerceis-lib";
const id = Generate.objectId();

// Subpath import — only bundles what you need
import { GA } from "cerceis-lib/genetic";
```

```js
// CommonJS
const { Generate } = require("cerceis-lib");
```

---

## Module Catalog

> Most functions are documented with JSDoc — hover over them in your IDE for full details.

---

### `Constant`
Database of named value lists.

| Property | Description |
|---|---|
| `gemStones` | List of gem stone names |
| `colors` | List of color names |

---

### `Delay`
Async sleep helper.

```ts
await Delay(500); // wait 500 ms
```

---

### `FromArray`
Collection of array utilities.

| Method | Description |
|---|---|
| `getRandom` | Pick a random element |
| `getLargest` | Get the N largest elements |
| `getSmallest` | Get the N smallest elements |
| `getIntersect` | Intersection of two arrays |
| `shuffle` | Shuffle in place |
| `thanosSnap` | Randomly remove half the elements |
| `toObject` | Convert array to object |
| `log` | Pretty-print an array (supports index range) |

---

### `FromNum`
Collection of number utilities.

| Method | Description |
|---|---|
| `roll(n)` | Returns `true` with `n`% probability |
| `diceRoll(n).D(sides)` | Roll N dice with given sides |
| `minMaxScale` | Normalise to 0–1 |
| `unminMaxScale` | Reverse min-max normalisation |
| `sum` | Sum an array of numbers |
| `mean` | Arithmetic mean |
| `softMax` | Softmax probability distribution |
| `sigmoid` | Sigmoid activation |
| `relu` | ReLU activation |
| `softPlus` | Soft-plus activation |
| `toNearest` | Round to nearest N |
| `toRomanNumeral` | Convert to Roman numeral string |
| `toShortReadable` | e.g. `1500000` → `"1.5m"` |

---

### `FromObject`
Collection of object utilities.

| Method | Description |
|---|---|
| `ObjectToArray` | Convert object to array of entries |
| `flatten` | Flatten a nested object |
| `getDeepest` | Get the deepest entries |
| `sumAll` | Sum all numeric values |
| `min` / `max` | Find min/max value |

---

### `FromString`
Collection of string utilities.

| Method | Description |
|---|---|
| `copyToClipboard` | Copy to clipboard |
| `replaceFirst(n, s)` | Replace first N characters |
| `replaceLast(n, s)` | Replace last N characters |
| `parseCookies` | Parse HTTP cookie string into object |
| `deepClean` | Strip all non-alphanumeric characters |
| `count(word)` | Count occurrences of a substring |

---

### `FromTime` / `cDate`
Date and time utilities.

| Method | Description |
|---|---|
| `format` | Format a Date as `"YYYY-MM-DD HH:mm:ss"` |
| `toMs` / `toSeconds` / `toMinutes` / `toHours` | Time-unit conversions |
| `toDateTimeShortLocale` | Short human-readable date string |
| `jpnDayMap` | Integer → Japanese day label |
| `cDate(date).addMonth(n)` | Advance a date by N months |

---

### `FromVector` / `createVector`
2D/3D vector math.

```ts
const v = createVector(3, 4);
v.mag();       // 5
v.normalize();
v.add(other);
```

| Method | `add` `sub` `mult` `div` `mag` `magSq` `normalize` `limit` `setMag` `heading` `dist` `copy` `toVector2` `toVector3` |
|---|---|

---

### `Gacha`
Weighted random selection system.

```ts
const g = new Gacha();
g.addEntries("Common",  70);
g.addEntries("Rare",    25);
g.addEntries("Legendary", 5);
g.getRandom(); // "Common", "Rare", or "Legendary"
```

---

### `Generate`
Data generation helpers.

| Method | Description |
|---|---|
| `objectId()` | MongoDB-style object ID |
| `alphanum(n)` | Random alphanumeric string |
| `alphabate(n)` | Random alphabetic string |
| `int(min, max)` | Random integer in range |
| `random(min, max)` | Random float in range |
| `array(type, n)` | Array of generated values |
| `currentDate()` | `"YYYY-MM-DD"` |
| `currentTime()` | `"HH:mm:ss"` |
| `currentDateTime()` | `"YYYY-MM-DD HH:mm:ss"` |
| `listOfDateOfDays(day, n)` | List of dates for a given weekday |

---

### `Is`
Type-guard helpers.

```ts
Is.string("hello")   // true
Is.number(42)        // true
Is.array([])         // true
```

---

### `KMeans` / `KMeansND`
K-means clustering (1D and N-dimensional).

```ts
// 1-D
const clusters = KMeans(3, [1, 2, 10, 11, 50, 51]);

// N-D (e.g. customer segmentation)
const segments = KMeansND(3, customers, (c) => [c.recency, c.spend]);
```

---

### `Logger`
Colourful, structured `console.log` wrapper.

---

### `Obfuscator`
Simple string obfuscation / deobfuscation.

---

### `Sha256`
Pure-TypeScript SHA-256 implementation.

---

### `Validator`
Form input validation with locale support (`en`, `ja`).

---

### `GA` — Genetic Algorithm
> **Import:** `import { GA } from "cerceis-lib/genetic"`  
> or include via the main entry: `import { GA } from "cerceis-lib"`

A scaffold toolkit for building genetic algorithms. Fully generic — the gene type `G` can be **any value**: numbers, booleans, strings, or arbitrary objects with any fields you define.

#### Core workflow

```ts
import { GA } from "cerceis-lib/genetic";

// 1. Define your gene factory (returns one random gene)
const factory = () => Math.round(Math.random()) as 0 | 1;

// 2. Create a random population
const pop = GA.evaluate(
    GA.createPopulation(50, 20, factory),
    (genes) => genes.reduce((a, b) => a + b, 0), // count set bits
);

// 3. Evolve
const result = GA.run({
    population: pop,
    fitnessFn: (genes) => genes.reduce((a, b) => a + b, 0),
    generations: 100,
    mutationRate: 0.02,
    geneFactory: factory,
    onGeneration: (best, gen) => console.log(`Gen ${gen}: ${best.fitness}`),
});

console.log(result.best.genes, result.best.fitness);
```

#### Custom object genes

```ts
type Gene = { weight: number; active: boolean; label: string };

const pop = GA.createPopulation<Gene>(50, 10, () => ({
    weight: Math.random(),
    active: Math.random() < 0.5,
    label: `node-${Math.floor(Math.random() * 100)}`,
}));

const evaluated = GA.evaluate(pop, (genes) =>
    genes.filter((g) => g.active).reduce((s, g) => s + g.weight, 0),
);
```

#### Population helpers

| Function | Description |
|---|---|
| `GA.createPopulation(size, length, factory)` | Create a population of random individuals |
| `GA.evaluate(pop, fitnessFn)` | Score every individual; returns a new array |
| `GA.sort(pop, order?)` | Sort by fitness (`'desc'` = best first, default) |
| `GA.best(pop, n?)` | Return the top-n fittest individuals |

#### Selection operators

| Function | Description |
|---|---|
| `GA.selection.tournament(pop, size?)` | Best of `size` random picks (default 3) |
| `GA.selection.roulette(pop)` | Fitness-proportionate probability |
| `GA.selection.rank(pop)` | Rank-based — reduces premature convergence |

#### Crossover operators

| Function | Description |
|---|---|
| `GA.crossover.singlePoint(p1, p2)` | Split at one random cut, swap tails |
| `GA.crossover.twoPoint(p1, p2)` | Swap the segment between two cuts |
| `GA.crossover.uniform(p1, p2, rate?)` | Gene-by-gene random mix (default 0.5) |

#### Mutation operators

| Function | Encoding | Description |
|---|---|---|
| `GA.mutation.bitFlip(ind, rate)` | Binary / boolean | Flip each gene with probability `rate` |
| `GA.mutation.swap(ind, rate)` | Permutation | Swap two random positions |
| `GA.mutation.inversion(ind, rate)` | Permutation | Reverse a random sub-sequence |
| `GA.mutation.randomReset(ind, rate, factory)` | Any | Replace each gene with a new random value |

#### `GA.run` options

```ts
GA.run({
    population,       // pre-evaluated population
    fitnessFn,        // (genes: G[]) => number  (higher = better)
    generations,      // number of generations to run
    mutationRate,     // default 0.01
    geneFactory,      // required for randomReset; also used as default mutation
    selection,        // 'tournament' | 'roulette' | 'rank'  (default 'tournament')
    tournamentSize,   // default 3
    crossover,        // 'single-point' | 'two-point' | 'uniform'  (default 'single-point')
    elitismRate,      // fraction carried unchanged each gen  (default 0.1)
    onGeneration,     // (best, generationIndex) => void
})
```

Returns `{ best, finalPopulation, history }` where `history` is the best fitness per generation.

---

## Changelog

| Version | Date | Description |
|---|---|---|
| `2.5.0` | 2026-04-12 | Added `GA` genetic algorithm module |
| `2.4.0` | 2025-05-08 | Modernised build (tsup), vitest tests, subpath exports, locale rename |
| `2.2.3` | 2023-01-11 | Added `FromNum.toShortReadable` |
| `2.2.2` | 2023-01-06 | Added `Constant` |
| `2.2.0` | 2023-01-05 | Added `FromVector` |
| `2.1.0` | 2022-10-05 | New math functions, fixed `Delay` memory leak |
| `2.0.1` | 2022-08-16 | Major restructure |
| `1.5.70` | 2022-08-09 | Added `FromObject` |
| `1.5.62` | 2022-06-09 | Added `Num` |
| `1.5.30` | 2022-03-14 | Added `Is` |
| `1.5.0` | 2022-02-16 | Added `Delay`, CJS + MJS dual output |
| `1.3.0` | 2021-12-28 | Added JSDoc, merged modules into `Generate` / `FromArray` |
| `1.2.0` | 2021-12-23 | Added `KMeans`, `StringPadding` |
| `1.1.0` | 2021-12-17 | Added `Logger`, `CopyToClipboard` |
