❄️ Tinsel AoC DSL

Standard Library (std/*) Reference

The Tinsel Standard Library is implemented in pure Tinsel source files (stdlib/*.tin) embedded directly into the standalone Go binary via embed.FS. Every module can be imported using either its canonical "std/<name>" path or shorthand "<name>":

tinsel
import "std/math" as math
from "std/search" import dijkstra, bfs, union_find
from "std/grid" import parse_grid, forward, turn_right

Module Directory

Module Source File Primary Exports & Types
std/grid stdlib/grid.tin grid type, parse_grid, new, cardinal_dirs, forward, turn_right, turn_left, flood_fill
std/intervals stdlib/intervals.tin rangeset type, range_set, overlap, split, remap
std/search stdlib/search.tin dijkstra, astar, bfs, dfs, toposort, union_find / dsu
std/orbit stdlib/orbit.tin orbit / cycle for O(1) modulo cycle fast-forwarding
std/math stdlib/math.tin gcd, lcm, crt, ext_gcd, mod_inv, mod_pow, shoelace, picks_theorem, cramer_2x2
std/iter stdlib/iter.tin Lazy Iter streams, iter, count_from, repeat_val, combinators & consumers
std/itertools stdlib/itertools.tin windows, chunked, zip, frequencies, permutations, combinations, product
std/collections stdlib/collections.tin defaultdict (DefaultDict), counter (Counter)
std/set stdlib/set.tin set hash set with .add(), .has(), .union(), .intersect(), .diff(), .is_subset()
std/deque stdlib/deque.tin deque amortized O(1) double-ended queue
std/heap stdlib/heap.tin heap / priority_queue binary min-heap with .push(), .pop(), .peek(), .len(), and optional comparator
std/memo stdlib/memo.tin memoize(fn) automatic recursive function caching
std/vec stdlib/vec.tin N-dimensional coordinate vectors, adj_ortho, adj_all, manhattan, euclid_sq
std/io & std/parse stdlib/io.tin, stdlib/parse.tin File readers, parse_ints, parse_grid, scan_pattern, parse_template
Prototype & Prelude Modules stdlib/array.tin, string.tin, int.tin, option.tin, prelude.tin Backing implementations for built-in receiver methods and global prelude functions

1. std/grid

2D character grid engine, directional heading arithmetic, and coordinate geometry (stdlib/grid.tin).

Constructors & Module Functions

  • parse_grid(text: string) -> grid / parse(text: string) -> grid: Parses a multi-line string into a row-major 2D character grid (also available as "text".grid()).
  • new(w: int, h: int, fill_char = '.') -> grid: Allocates a w \times h grid initialized with fill_char.
  • make_grid(w: int, h: int, data: array) -> grid: Wraps a flat row-major array of length w * h into a grid.
  • cardinal_dirs / dirs: The 4 cardinal direction vectors in clockwise order: [vec2(1, 0), vec2(0, 1), vec2(-1, 0), vec2(0, -1)] (0: East, 1: South, 2: West, 3: North).
  • turn_right(dir: int) -> int: (dir + 1) % 4 (clockwise 90°).
  • turn_left(dir: int) -> int: (dir + 3) % 4 (counter-clockwise 90°).
  • opposite(dir: int) -> int: (dir + 2) % 4 (180° reversal).
  • forward(pos: vec2, dir: int) -> vec2: pos + cardinal_dirs[dir].
  • manhattan(p1, p2) -> int: Manhattan distance p1 <-> p2.

grid Properties, Operators & Instance Methods

Important

On a grid instance g, .width (.w) and .height (.h) are integer fields, not methods (g.width, g.height).

  • Fields: g.width / g.w (columns), g.height / g.h (rows).
  • Operators:
    • g[pos]: Reads character at vec2 coordinate pos (nil if out of bounds).
    • g[pos] = ch: Mutates cell at pos in-place.
    • pos in g / pos !in g: Checks if 0 <= pos.x < g.width && 0 <= pos.y < g.height.
  • Methods:
    • g.get(pos) -> char | nil, g.set(pos, ch) -> grid, g.in_bounds(pos) -> bool.
    • g.find(ch) -> vec2 | nil: First coordinate matching ch in row-major order.
    • g.find_all(ch) -> [vec2]: All coordinates matching ch.
    • g.count(ch) -> int: Total occurrences of ch.
    • g.adj4(pos) -> [vec2] / g.neighbors4(pos): Cardinal neighbors strictly inside grid bounds.
    • g.adj8(pos) -> [vec2] / g.neighbors8(pos): 8-way neighbors strictly inside grid bounds.
    • g.cells() -> [[vec2, char]]: Array of [pos, ch] pairs in row-major order.
    • g.rows() -> [string], g.cols() -> [string]: Rows or columns as strings.
    • g.rotate_cw() -> grid, g.rotate_ccw() -> grid, g.flip_h() -> grid, g.flip_v() -> grid, g.transpose() -> grid, g.clone() -> grid.
    • g.flood_fill(start: vec2, can_visit?: (pos, ch) -> bool) -> [vec2]: 4-way connected component starting at start (defaults to matching g[start]).
tinsel
import "std/grid" as grid

let g = grid.parse_grid("S..\n.#.\n..E")
assert(g.width == 3 && g.height == 3)
assert(g.find('E') == vec2(2, 2))
assert(g.adj4(vec2(0, 0)) == [vec2(1, 0), vec2(0, 1)])

2. std/intervals

Interval algebra and normalized disjoint RangeSet transformations (stdlib/intervals.tin).

Module Functions

  • range_set(ranges?: [range]) -> rangeset: Constructs a normalized rangeset by sorting and merging overlapping or adjacent half-open intervals.
  • overlap(r1: range, r2: range) -> range | nil: Intersection of r1 and r2, or nil if disjoint.
  • split(src: range, cutter: range) -> [range | nil]: Trisects src against cutter into [prefix, overlap, suffix].
  • remap(rs: rangeset, rules: [[dest, src, len]]) -> rangeset: Applies piecewise interval translation rules to rs.

rangeset Instance Methods & Operators

  • x in rs / rs.contains(x) -> bool: Checks if integer x falls inside any interval of rs.
  • rs.len() / rs.count() / rs.size() -> int: Total integer points covered across all disjoint intervals.
  • rs.min() -> int | nil / rs.max() -> int | nil: Smallest or largest integer coordinate covered by rs.
  • rs.ranges() -> [range]: Underlying sorted array of disjoint range values.
  • rs.add(r: range) -> rangeset: Inserts r and re-normalizes.
  • rs.union(other: rangeset) -> rangeset, rs.intersect(other: rangeset) -> rangeset, rs.diff(other: rangeset) -> rangeset.
  • rs.remap(rules: [[dest, src, len]]) -> rangeset: Trisects and shifts intervals matching any [dest, src, len] rule while passing unmatched sub-intervals through unchanged.
tinsel
from "std/intervals" import range_set

let rs = range_set([10..20, 15..30]).remap([[100, 18, 5]])
assert(rs.len() == 20 && rs.min() == 10 && (102 in rs))

3. std/search

Declarative state-space pathfinding, topological sorting, and Disjoint-Set Union (stdlib/search.tin).

All four search routines accept an options map and return SearchResult(found: bool, cost: int, path: [state]):

  • dijkstra({ start, step, goal?, cost? }) -> SearchResult: Weighted shortest path using a binary min-heap. step(state) may return [next_state, edge_cost] pairs or plain next_state values (with cost 1 or cost(curr, next)).
  • astar({ start, step, goal, h, cost? }) -> SearchResult: Heuristic A^* search minimizing g(s) + h(s).
  • bfs({ start, step, goal? }) -> SearchResult: Unweighted breadth-first search using an O(1) queue.
  • dfs({ start, step, goal? }) -> SearchResult: Depth-first search traversal.
  • search(kind: string, opts: map) -> SearchResult: Dispatches "dijkstra", "astar", "bfs", or "dfs".

toposort(graph_or_edges, less?) -> [any] | nil

Kahn's topological sort over an edge list [[u, v], ...] or adjacency map { u: [v1, v2] }. Returns nil if a cycle exists. Pass an optional comparator less: (a, b) -> bool for priority-queue tie-breaking.

union_find(initial_items?) -> UnionFind / dsu(initial_items?)

Disjoint-Set Union with path compression and union-by-size:

  • .add(x) -> any, .find(x) -> any, .union(x, y) -> bool, .connected(x, y) -> bool, .size(x) -> int, .count() -> int, .groups() -> map.
tinsel
from "std/search" import bfs, toposort, union_find

let res = bfs({ start: 1, goal: 16, step: x -> [x * 2, x + 1] })
assert(res.found && res.cost == 4)
assert(toposort([["A", "B"], ["B", "C"]]) == ["A", "B", "C"])

4. std/orbit

Periodicity detection and O(1) modulo fast-forwarding (stdlib/orbit.tin).

orbit({ initial, steps, step, hash? }) -> any / cycle(...)

Advances state = step(state) while recording each seen state (or hash(state)) and its step index. As soon as a state repeats at step t matching earlier step t_0 (period P = t - t_0), orbit fast-forwards the remaining steps via (N - t) \bmod P and returns the exact state at step steps.

tinsel
from "std/orbit" import orbit

let ans = orbit({ initial: 2, steps: 1_000_000_000_000, step: x -> (x * 5 + 1) % 29 })
assert(type_of(ans) == "int")

5. std/math

Number theory, modular arithmetic, linear algebra, and computational geometry (stdlib/math.tin).

Function / Constant Signature Description
PI, E float \pi \approx 3.141592653589793, e \approx 2.718281828459045
gcd(a, b) / lcm(a, b) (int, int) -> int Greatest common divisor and least common multiple
ext_gcd(a, b) (int, int) -> [gcd, x, y] Extended Euclidean algorithm (a x + b y = \gcd(a, b))
euclid_mod(a, m) (int, int) -> int Non-negative modulo ((a % m) + m) % m
mod_pow(base, exp, m) (int, int, int) -> int Modular exponentiation base^{exp} \pmod m
mod_inv(a, m) (int, int) -> int | nil Modular multiplicative inverse a^{-1} \pmod m (nil if not coprime)
crt(rems, mods) ([int], [int]) -> int | nil Chinese Remainder Theorem solver for x \equiv r_i \pmod{m_i}
pow(base, exp) (num, num) -> int | float Binary integer exponentiation (or float power when float/negative exp)
sign(n) / clamp(x, lo, hi) (num) -> int, (num, num, num) -> num Signum (-1, 0, 1) and interval clamping
shoelace(pts) ([vec2 | [int]]) -> int Twice the polygon area (2A) via the Shoelace formula
picks_theorem(double_area, perim) (int, int) -> PickResult Returns PickResult(interior, total, boundary) lattice points via Pick's Theorem
cramer_2x2(eq1, eq2) ([a1, b1, c1], [a2, b2, c2]) -> [x, y] | nil Exact integer solver for 2 \times 2 linear systems via Cramer's Rule

6. std/iter

Lazy pull-based stream iterators (stdlib/iter.tin).

  • Constructors: iter(x) / x.iter(), count_from(start, step = 1), repeat_val(val), Iter(next_fn).
  • Lazy Combinators (-> Iter): .map(f), .filter(pred), .take(n), .skip(n) / .drop(n), .take_while(pred), .drop_while(pred), .enumerate(), .zip(other), .chain(other).
  • Terminal Consumers: .collect() / .to_array(), .fold(init, f), .sum(), .product(), .count() / .len(), .min(), .max(), .find(pred), .any(pred), .all(pred).

7. std/itertools

Combinatorics and sequence windowing (stdlib/itertools.tin).

  • windows(arr, size) -> [array]: Overlapping sliding windows of length size.
  • chunked(arr, size) -> [array]: Non-overlapping chunks of up to size elements.
  • zip(arr1, arr2) -> [[a, b]]: Pairs elements from two arrays.
  • frequencies(arr) -> map / counter(arr) -> map: Returns { item: count } frequency map.
  • unique(arr) -> array / distinct(arr) -> array: Deduplicates while preserving order.
  • product(arr1, arr2) -> [[a, b]]: Cartesian product of two arrays.
  • permutations(arr, r = arr.len()) -> [array]: All length-r permutations.
  • combinations(arr, r) -> [array]: All length-r combinations without replacement.

8. std/collections

Struct-backed auto-vivifying maps and frequency counters (stdlib/collections.tin).

  • defaultdict(factory) -> DefaultDict: Auto-initializes missing keys using factory (a default value like 0 or [], or a zero-arg closure). Supports d[k], d[k] = v, k in d, len(d), .get(k), .set(k, v), .inc(k, delta = 1), .push(k, item), .keys(), .values(), .entries(), .map().
  • counter(items?) -> Counter: Counts element frequencies in an array or string. Supports c[k], k in c, len(c), .get(k), .inc(k, delta = 1), .most_common(n?), .total(), .keys(), .values(), .entries().

9. std/set

Hash set algebra (stdlib/set.tin).

  • set(items?: array) -> set: Creates a hash set supporting x in s, x !in s, s.len(), s.has(x), s.add(x), s.delete(x), s.to_array(), s.union(s2), s.intersect(s2), s.diff(s2), and s.is_subset(s2).

10. std/deque

Amortized O(1) double-ended queue implemented with dual opposing stacks (stdlib/deque.tin).

  • deque(items?: array) -> deque: Supports .push_back(x) / .push(x), .push_front(x), .pop_front() / .pop(), .pop_back(), .peek_front(), .peek_back(), .len(), .is_empty(), .to_array().

11. std/heap

Binary min-heap priority queue supporting both struct instances and mutable arrays (stdlib/heap.tin).

  • heap(items?: array, less?: (a, b) -> bool) -> heap / priority_queue(...): Constructs a min-heap struct supporting .push(item), .pop(), .peek(), .len(), .is_empty(), and .to_array().
  • push(heap, item: any, less?: (a, b) -> bool): Inserts item in O(\log n).
  • pop(heap, less?: (a, b) -> bool) -> any: Removes and returns minimum element in O(\log n).
  • peek(heap) -> any: Returns minimum element in O(1) (nil if empty).
  • len(heap) -> int / is_empty(heap) -> bool: Number of elements in heap.

12. std/memo

  • memoize(fn: closure) -> closure (stdlib/memo.tin): Wraps a 1-argument or multi-argument function closure with a structural hash cache table.

13. std/vec

Generic N-dimensional coordinate vector operations (stdlib/vec.tin) operating on [int] coordinate arrays of any dimension N:

  • add(v1, v2), sub(v1, v2), scale(v, k), dot(v1, v2), manhattan(v1, v2), euclid_sq(v1, v2), zero(dim), unit(dim, axis).
  • adj_ortho(v: [int]) -> [[int]]: Generates the 2N orthogonal neighbors.
  • adj_all(v: [int]) -> [[int]]: Generates all 3^N - 1 surrounding neighbors (8 in 2D, 26 in 3D, 80 in 4D).

14. std/io and std/parse

  • std/io (stdlib/io.tin): Exports read_file, read_lines, read_sections, read_paragraphs, write_file, append_file, file_exists, env, print, println.
  • std/parse (stdlib/parse.tin): Exports ints / parse_ints, grid / parse_grid, parse_sections / parse_paragraphs, scan_pattern / scan, parse_template, matches_template.

15. Prototype and Prelude Modules

The remaining five files in stdlib/ power Tinsel's global prelude and built-in receiver methods (see Built-in Functions & Receiver Methods Reference for full signatures):

  • std/prelude (stdlib/prelude.tin): Global functions len, lines, sum, iter, min, max, abs, map, assert, read_lines, read_sections, to_hex/hex, to_bin/bin, scan_pattern/scan.
  • std/array (stdlib/array.tin): Prototype methods on array (can also be imported for |> pipelines: from "std/array" import filter, sort_by).
  • std/string (stdlib/string.tin): Prototype methods on string.
  • std/int (stdlib/int.tin): Prototype methods on int and bigint.
  • std/option (stdlib/option.tin): Prototype methods and combinators on option (Some / None).