grilops
Version:
A Grid Logic Puzzle Solver library, using Typescript and z3.
1,177 lines (1,114 loc) • 47.4 kB
TypeScript
import { AnySort } from 'z3-solver';
import { Arith } from 'z3-solver';
import { Bool } from 'z3-solver';
import { Context } from 'z3-solver';
import { Expr } from 'z3-solver';
import { Optimize } from 'z3-solver';
import { Solver } from 'z3-solver';
import { Z3LowLevel } from 'z3-solver';
export declare function combinations<T>(choices: T[], length: number): Generator<T[]>;
export declare type Constructor<T extends abstract new (...args: any) => any> = new (...args: ConstructorParameters<T>) => T;
/**
* Returns a count of cells along a sightline through a grid.
* @param context The context in which to construct the constraints.
* @param symbolGrid The grid to check against.
* @param start The location of the cell where the sightline should begin.
* This is the first cell checked.
* @param direction The direction to advance to reach the next cell in the
* sightline.
* @param count A function that accepts a symbol as an argument and returns the
* integer value to add to the count when this symbol is encountered. By
* default, each symbol will count with a value of one.
* @param stop A function that accepts a symbol as an argument and returns True
* if we should stop following the sightline when this symbol is
* encountered. By default, the sightline will continue to the edge of the
* grid.
* @returns An `Arith` for the count of cells along the sightline through the
* grid.
*/
export declare function countCells<Name extends string>(context: GrilopsContext<Name>, symbolGrid: SymbolGrid<Name>, start: Point, direction: Direction, count?: (c: Arith<Name>) => Arith<Name>, stop?: (c: Arith<Name>) => Bool<Name>): Arith<Name>;
export declare function createDefualtMap<T>(base: KeyedMapConstructor<T>): DefaultKeyedMapConstructor<T>;
export declare function createDefualtMap(base: MapConstructor): DefaultMapConstructor;
export declare function createStringMap<T, Key extends string>(toString: (item: T) => Key, fromString: (key: Key) => T): KeyedMapConstructor<T>;
export declare function createStringSet<T, Key extends string>(toString: (item: T) => Key, fromString: (key: Key) => T): KeyedSetConstructor<T>;
export declare const DefaultDirectionMap: DefaultKeyedMapConstructor<Direction>;
export declare interface DefaultKeyedMapConstructor<T> extends DefaultMapConstructor, KeyedMapConstructor<T> {
new <V>(defaultFunc: () => V, entries?: readonly (readonly [T, V])[] | null): DefaultMap<T, V>;
readonly prototype: DefaultMap<T, any>;
}
export declare interface DefaultMap<K, V> extends Map<K, V> {
get(key: K): V;
}
export declare interface DefaultMapConstructor {
new <K, V>(defaultFunc: () => V, entries?: readonly (readonly [K, V])[] | null): DefaultMap<K, V>;
readonly prototype: DefaultMap<any, any>;
}
export declare const DefaultPointMap: DefaultKeyedMapConstructor<Point>;
export declare const DefaultVectorMap: DefaultKeyedMapConstructor<Vector>;
/**
* A named direction vector that offsets by one space in the grid.
*/
export declare class Direction {
/**
* The name of the direction.
*/
name: DirectionKey;
/**
* The vector of the direction.
*/
vector: Vector;
constructor(name: DirectionKey, vector: Vector);
toString(): DirectionString;
static fromString(s: DirectionString): Direction;
}
export declare type DirectionKey = 'N' | 'S' | 'E' | 'W' | 'NE' | 'NW' | 'SE' | 'SW';
export declare const DirectionMap: KeyedMapConstructor<Direction>;
export declare const DirectionSet: KeyedSetConstructor<Direction>;
export declare type DirectionString = `D(${DirectionKey},${VectorString})`;
/**
* A quadtree for caching and aggregating z3 expressions.
*
* This class builds a quadtree data structure from a list of points, and
* provides the ability to lazily construct and cache z3 expressions that
* reference these points.
*/
export declare class ExpressionQuadTree<Name extends string, ExprKey extends string | number | symbol> {
readonly ctx: GrilopsContext<Name>;
private _exprs;
private _exprFuncs;
private _point;
private _yMin;
private _yMax;
private _xMin;
private _xMax;
private _yMid;
private _xMid;
private _tl;
private _tr;
private _bl;
private _br;
private _quads;
constructor(context: GrilopsContext<Name>, points: Point[], exprFuncs?: ExprFuncMap<Name, ExprKey> | undefined);
/**
* Returns true if the given point is within this tree node's bounds.
*/
coversPoint(p: Point): boolean;
/**
* Registers an expression constructor, to be called for each point.
*/
addExpr(key: ExprKey, exprFunc: (point: Point) => Bool<Name>): void;
/**
* Returns expressions for all points covered by this tree node.
*/
getExprs(key: ExprKey): Bool<Name>[];
/**
* Returns the expression for the given point.
*/
getPointExpr(key: ExprKey, p: Point): Bool<Name>;
/**
* Returns the conjunction of all expressions, excluding given points.
*/
getOtherPointsExpr(key: ExprKey, points: Point[]): Bool<Name> | undefined;
}
export declare type ExprFuncMap<Name extends string, ExprKey> = Map<ExprKey, (point: Point) => Bool<Name>>;
/**
* A set of points forming a flat-topped hexagonal lattice.
*
* All points must lie on a hexagonal lattice in which each hexagon has
* a flat top. We use the doubled coordinates scheme described at
* https://www.redblobgames.com/grids/hexagons/. That is, y describes
* the row and x describes the column, so hexagons that are vertically
* adjacent have their y coordinates differ by 2.
*/
export declare class FlatToppedHexagonalLattice extends HexagonalLattice {
static DIRECTIONS: {
N: Direction;
S: Direction;
NE: Direction;
NW: Direction;
SE: Direction;
SW: Direction;
};
edgeSharingDirections(): Direction[];
transformationFunctions(allowRotations: boolean, allowReflections: boolean): ((vector: Vector) => Vector)[];
getInsideOutsideCheckDirections(): [Direction, Direction[]];
}
declare namespace geometry {
export {
getRectangleLattice,
getSquareLattice,
VectorString,
Vector,
VectorMap,
VectorSet,
DefaultVectorMap,
DirectionKey,
DirectionString,
Direction,
DirectionMap,
DirectionSet,
DefaultDirectionMap,
PointString,
Point,
PointMap,
PointSet,
DefaultPointMap,
HookFunction,
Neighbor,
Lattice,
RectangularLattice,
HexagonalLattice,
FlatToppedHexagonalLattice,
PointyToppedHexagonalLattice
}
}
/**
* Returns a lattice of all points in a rectangle of the given dimensions.
* @param height Height of the lattice.
* @param width Width of the lattice.
* @returns The lattice.
*/
export declare function getRectangleLattice(height: number, width: number): RectangularLattice;
/**
* Returns a lattice of all points in a square of the given height.
* @param height Height of the lattice.
* @returns The lattice.
*/
export declare function getSquareLattice(height: number): RectangularLattice;
export declare function grilops<Name extends string>(context: GrilopsContext<Name>): {
PathSymbolSet: typeof paths.PathSymbolSet;
PathConstrainer: typeof paths.PathConstrainer;
RegionConstrainer: new <const Core extends Solver<Name> | Optimize<Name> = Solver<Name> | Optimize<Name>>(lattice: geometry.Lattice, solver: Core | undefined, complete?: boolean | undefined, rectangular?: boolean | undefined, minRegionSize?: number | undefined, maxRegionSize?: number | undefined) => RegionConstrainer<Name, Core>;
Shape: new <Payload extends Expr<Name, AnySort<Name>, unknown>>(offsets: Offset<Name, Payload>[]) => Shape<Name, Payload>;
ShapeConstrainer: new <Payload_1 extends Expr<Name, AnySort<Name>, unknown>, const Core_1 extends Solver<Name> | Optimize<Name> = Solver<Name> | Optimize<Name>>(lattice: geometry.Lattice, shapes: Shape<Name, Payload_1>[], solver: Core_1 | undefined, complete: boolean, allowRotations: boolean, allowReflections: boolean, allowCopies: boolean) => ShapeConstrainer<Name, Payload_1, Core_1>;
reduceCells: <Accumulator extends Arith<Name>>(symbolGrid: SymbolGrid<Name, Solver<Name> | Optimize<Name>>, start: geometry.Point, direction: geometry.Direction, initializer: Accumulator, accumulate: (a: Accumulator, c: Arith<Name>, p: geometry.Point) => Accumulator, stop?: (a: Accumulator, c: Arith<Name>, p: geometry.Point) => Bool<Name>) => Accumulator;
countCells: (symbolGrid: SymbolGrid<Name, Solver<Name> | Optimize<Name>>, start: geometry.Point, direction: geometry.Direction, count?: (c: Arith<Name>) => Arith<Name>, stop?: (c: Arith<Name>) => Bool<Name>) => Arith<Name>;
makeLetterRangeSymbolSet(minLetter: string, maxLetter: string): symbols.SymbolSet;
makeNumberRangeSymbolSet(minNumber: number, maxNumber: number): symbols.SymbolSet;
Symbol: typeof symbols.Symbol;
SymbolSet: typeof symbols.SymbolSet;
ExpressionQuadTree: new <ExprKey extends string | number | symbol>(points: geometry.Point[], exprFuncs?: ExprFuncMap<Name, ExprKey> | undefined) => ExpressionQuadTree<Name, ExprKey>;
SymbolGrid: new <Core_2 extends Solver<Name> | Optimize<Name> = Solver<Name>>(lattice: geometry.Lattice, symbolSet: symbols.SymbolSet, solver?: Core_2 | undefined) => SymbolGrid<Name, Core_2>;
getRectangleLattice(height: number, width: number): geometry.RectangularLattice;
getSquareLattice(height: number): geometry.RectangularLattice;
Vector: typeof geometry.Vector;
VectorMap: KeyedMapConstructor<geometry.Vector>;
VectorSet: KeyedSetConstructor<geometry.Vector>;
DefaultVectorMap: DefaultKeyedMapConstructor<geometry.Vector>;
Direction: typeof geometry.Direction;
DirectionMap: KeyedMapConstructor<geometry.Direction>;
DirectionSet: KeyedSetConstructor<geometry.Direction>;
DefaultDirectionMap: DefaultKeyedMapConstructor<geometry.Direction>;
Point: typeof geometry.Point;
PointMap: KeyedMapConstructor<geometry.Point>;
PointSet: KeyedSetConstructor<geometry.Point>;
DefaultPointMap: DefaultKeyedMapConstructor<geometry.Point>;
Neighbor: typeof geometry.Neighbor;
Lattice: typeof geometry.Lattice;
RectangularLattice: typeof geometry.RectangularLattice;
HexagonalLattice: typeof geometry.HexagonalLattice;
FlatToppedHexagonalLattice: typeof geometry.FlatToppedHexagonalLattice;
PointyToppedHexagonalLattice: typeof geometry.PointyToppedHexagonalLattice;
};
export declare interface GrilopsContext<Name extends string> {
z3: Z3LowLevel['Z3'];
context: Context<Name>;
}
export declare abstract class HexagonalLattice extends Lattice {
private _points;
private _pointIndices;
private static _DIRECTION_LABELS;
/**
* A set of points forming a hexagonal lattice.
*
* This abstract class implements functions identical between
* FlatToppedHexagonalLattice and PointyToppedHexagonalLattice.
*
* We use the doubled coordinates scheme described at
* https://www.redblobgames.com/grids/hexagons/. That is, y describes
* the row and x describes the column, so x + y is always even.
*/
constructor(points: Point[]);
get points(): Point[];
pointToIndex(point: Point): number | undefined;
vertexSharingDirections(): Direction[];
labelForDirection(direction: Direction): string;
labelForDirectionPair(dir1: Direction, dir2: Direction): string;
}
export declare type HookFunction = (point: Point) => string | undefined;
export declare interface KeyedMapConstructor<T> extends MapConstructor {
new (): Map<T, any>;
new <V>(entries?: readonly (readonly [T, V])[] | null): Map<T, V>;
readonly prototype: Map<T, any>;
readonly [KeyedMapContructorSymbol]?: undefined;
}
declare const KeyedMapContructorSymbol: unique symbol;
export declare interface KeyedSetConstructor<T> {
new (values?: readonly T[] | null): Set<T>;
readonly prototype: Set<any>;
}
/**
* A base class for defining the structure of a grid.
*/
export declare abstract class Lattice {
private _vectorDirection;
constructor();
/**
* The points in the lattice, sorted.
*/
abstract get points(): Point[];
/**
* Returns the index of a point in the lattice's ordered list.
* @param point The `Point` to get the index of.
* @returns The index of the point in the ordered list, or None if the point
* is not in the list.
*/
abstract pointToIndex(point: Point): number | undefined;
/**
* A list of edge-sharing directions.
* @returns A list of `Direction`s, each including the name of an edge-sharing
* direction and the vector representing that direction. Edge sharing (also
* known as orthogonal adjacency) is the relationship between grid cells
* that share an edge.
*/
abstract edgeSharingDirections(): Direction[];
/**
* A list of vertex-sharing directions.
* @returns A list of `Direction`s, each including the name of a
* vertex-sharing direction and the vector representing that
* direction. Vertex sharing (also known as touching adjacency) is the
* relationship between grid cells that share a vertex.
*/
abstract vertexSharingDirections(): Direction[];
/**
* Given a direction, return the opposite direction.
* @param direction The given `Direction`.
* @returns The `Direction` opposite the given direction.
*/
oppositeDirection(direction: Direction): Direction;
/**
* Returns a list of points that share an edge with the given cell.
* @param point The point of the given cell.
* @returns A list of `Point`s in the lattice that correspond to cells that
* share an edge with the given cell.
*/
edgeSharingPoints(point: Point): Point[];
/**
* Returns a list of points that share a vertex with the given cell.
* @param point The point of the given cell.
* @returns A list of `Point`s in the lattice corresponding to cells that
* share a vertex with the given cell.
*/
vertexSharingPoints(point: Point): Point[];
/**
* Returns a list of neighbors in the given directions of the given cell.
* @param cellMap A dictionary mapping points in the lattice to z3 constants.
* @param p Point of the given cell.
* @param directions The given list of directions to find neighbors with.
* @returns A list of `Neighbor`s corresponding to the cells that are in the
* given directions from the given cell.
*/
private static _getNeighbors;
/**
* Returns a list of neighbors sharing an edge with the given cell.
* @param cellMap A dictionary mapping points in the lattice to z3 constants.
* @param p Point of the given cell.
* @returns A list of `Neighbor`s corresponding to the cells that share an
* edge with the given cell.
*/
edgeSharingNeighbors<Name extends string>(cellMap: Map<Point, Arith<Name>>, p: Point): Neighbor<Name>[];
/**
* Returns a list of neighbors sharing a vertex with the given cell.
* @param cellMap A dictionary mapping points in the lattice to z3 constants.
* @param p Point of the given cell.
* @returns A list of `Neighbor`s corresponding to the cells that share a
* vertex with the given cell.
*/
vertexSharingNeighbors<Name extends string>(cellMap: Map<Point, Arith<Name>>, p: Point): Neighbor<Name>[];
/**
* Returns the label for a direction.
* @param direction The direction to label.
* @returns A label representing the direction.
* @throws An error if there's no character defined for the direction.
*/
abstract labelForDirection(direction: Direction): string;
/**
* Returns the label for a pair of edge-sharing directions.
* @param dir1 The first direction.
* @param dir2 The second direction.
* @returns A label representing both directions.
* @throws An error if there's no character defined for the direction pair.
*/
abstract labelForDirectionPair(dir1: Direction, dir2: Direction): string;
/**
* Returns a list of `Vector` transformations.
*
* Each returned transformation is a function that transforms a
* `Vector` into a `Vector`. The returned list always contains at least
* one transformation: the identity function. The transformations
* returned are all transformations satisfying the given constraints.
*
* @param allowRotations Whether rotation is an allowed transformation.
* @param allowReflections Whether reflection is an allowed transformation.
* @returns A list of `Vector` transformation functions.
*/
abstract transformationFunctions(allowRotations: boolean, allowReflections: boolean): ((vector: Vector) => Vector)[];
/**
* Returns directions for use in a loop inside-outside check.
*
* The first direction returned is the direction to look, and the
* remaining directions are the directions to check for crossings.
*
* For instance, on a rectangular grid, a valid return value would
* be (north, [west]). This means that if you look north and count how many
* west-going lines you cross, you can tell from its parity if you're inside
* or outside the loop.
*
* @returns A tuple, the first component of which indicates the direction to
* look, and the second component of which indicates what types of crossings
* to count.
*/
abstract getInsideOutsideCheckDirections(): [Direction, Direction[]];
/**
* Prints something for each of the given points.
* @param hookFunction A function implementing per-location display
* behavior. It will be called for each `Point` in the lattice. If the
* returned string has embedded newlines, it will be treated as a multi-line
* element. For best results, all elements should have the same number of
* lines as each other and as blank (below).
* @param ps The `Point`s to print something for.
* @param blank What to print for `Point`s not in the lattice, or for when
* the hook function returns None. Defaults to one space. If it has
* embedded newlines, it will be treated as a multi-line element.
*/
private _pointsToString;
/**
* Prints something for each space in the lattice.
*
* Printing is done from top to bottom and left to right.
*
* @param hookFunction A function implementing per-location display
* behavior. It will be called for each `Point` in the lattice. If the
* returned string has embedded newlines, it will be treated as a multi-line
* element. For best results, all elements should have the same number of
* lines as each other and as blank (below).
* @param blank What to print for `Point`s not in the lattice, or for when
* the hook function returns None. Defaults to one space. If it has
* embedded newlines, it will be treated as a multi-line element.
*/
toString(hookFunction: HookFunction, blank?: string): string;
}
/**
* Returns a `SymbolSet` consisting of consecutive letters.
* @param minLetter The lowest letter to include in the set.
* @param maxLetter The highest letter to include in the set.
* @returns A `SymbolSet` consisting of consecutive letters.
*/
export declare function makeLetterRangeSymbolSet(minLetter: string, maxLetter: string): SymbolSet;
/**
* Returns a `SymbolSet` consisting of consecutive numbers.
*
* The names of the symbols will be prefixed with S to be consistent with the
* Python implementation.
*
* @param minNumber The lowest number to include in the set.
* @param maxNumber The highest number to include in the set.
* @returns A `SymbolSet` consisting of consecutive numbers.
*/
export declare function makeNumberRangeSymbolSet(minNumber: number, maxNumber: number): SymbolSet;
/**
* Properties of a cell that is a neighbor of another.
*/
export declare class Neighbor<Name extends string> {
/**
* The location of the cell.
*/
location: Point;
/**
* The direction from the original cell.
*/
direction: Direction;
/**
* The symbol constant of the cell.
*/
symbol: Arith<Name>;
constructor(location: Point, direction: Direction, symbol: Arith<Name>);
}
export declare type Offset<Name extends string, Payload extends Expr<Name>> = Vector | [Vector, Payload?];
/**
* Creates constraints for ensuring symbols form connected paths.
*/
export declare class PathConstrainer<Name extends string> {
private static _instanceIndex;
private readonly _symbolGrid;
private readonly _complete;
private readonly _allowTerminatedPaths;
private readonly _allowLoops;
private readonly _pathInstanceGrid;
private readonly _pathOrderGrid;
private _numPaths;
/**
* @param symbolGrid The grid to constrain.
* @param complete If true, every cell must be part of a path. Defaults to
* false.
* @param allowTerminatedPaths If true, finds paths that are terminated
* (not loops). Defaults to true.
* @param allowLoops If true, finds paths that are loops. Defaults to true.
*/
constructor(symbolGrid: SymbolGrid<Name>, complete?: boolean, allowTerminatedPaths?: boolean, allowLoops?: boolean);
private _addPathEdgeConstraints;
private _addPathInstanceGridConstraints;
private _allDirectionPairs;
private _addPathOrderGridConstraints;
private _addAllowTerminatedPathsConstraints;
/**
* A constant representing the number of distinct paths found.
*/
get numPaths(): Arith<Name>;
/**
* Constants of path instance identification.
*
* Each separate path will have a distinct instance number. The instance number
* is -1 if the cell does not contain a path segment or terminal.
*/
get pathInstanceGrid(): Map<Point, Arith<Name>>;
/**
* Constants of path traversal orders.
*
* Each segment or terminal of a path will have a distinct order number. The
* order number is -1 if the cell does not contain a path segment or terminal.
*/
get pathOrderGrid(): Map<Point, Arith<Name>>;
/**
* Prints the path instance and order for each path cell.
*
* Should be called only after the solver has been checked.
*/
pathNumberingToString(): string;
}
declare namespace paths {
export {
PathSymbolSet,
PathConstrainer
}
}
/**
* A `SymbolSet` consisting of symbols that may form paths.
*
* Additional symbols (e.g. a `Symbol` representing an empty
* space) may be added to this `SymbolSet` by calling
* `SymbolSet.append` after it's constructed.
*/
export declare class PathSymbolSet extends SymbolSet {
private readonly _includeTerminals;
private readonly _symbolsForDirection;
private readonly _symbolForDirectionPair;
private readonly _terminalForDirection;
private _maxPathSegmentSymbolIndex;
private _maxPathTerminalSymbolIndex;
/**
* @param lattice The structure of the grid.
* @param includeTerminals If true, create symbols for path terminals.
* Defaults to true.
*/
constructor(lattice: Lattice, includeTerminals?: boolean);
/**
* Returns true if the given symbol represents part of a path.
* @param symbol An `Arith` expression representing a symbol.
* @returns A true `Bool` if the symbol represents part of a path.
*/
isPath<Name extends string>(symbol: Arith<Name>): Bool<Name>;
/**
* Returns true if the given symbol represents a non-terminal path segment.
* @param symbol An `Arith` expression representing a symbol.
* @returns A true `Bool` if the symbol represents a non-terminal path segment.
*/
isPathSegment<Name extends string>(symbol: Arith<Name>): Bool<Name>;
/**
* Returns true if the given symbol represents a path terminal.
* @param symbol An `Arith` expression representing a symbol.
* @returns A true `Bool` if the symbol represents a path terminal.
*/
isTerminal<Name extends string>(symbol: Arith<Name>): Bool<Name>;
/**
* Returns the symbols with one arm going in the given direction.
* @param d The given direction.
* @returns A `number[]` of symbol indices corresponding to symbols with one
* arm going in the given direction.
*/
symbolsForDirection(d: Direction): number[];
/**
* Returns the symbol with arms going in the two given directions.
* @param d1 The first given direction.
* @param d2 The second given direction.
* @returns The symbol index for the symbol with one arm going in each of the
* two given directions.
*/
symbolForDirectionPair(d1: Direction, d2: Direction): number;
/**
* Returns the symbol that terminates the path from the given direction.
* @param d The given direction.
* @returns The symbol index for the symbol that terminates the path from the
* given direction.
*/
terminalForDirection(d: Direction): number | undefined;
}
/**
* A point, generally corresponding to the center of a grid cell.
*/
export declare class Point {
/**
* The location in the y dimension.
*/
y: number;
/**
* The location in the x dimension.
*/
x: number;
constructor(y: number, x: number);
/**
* Translates this point by the given `Vector` or `Direction`.
*/
translate(other: Vector | Direction): Point;
toString(): PointString;
static fromString(s: PointString): Point;
equals(other: Point): boolean;
static comparator(a: Point, b: Point): number;
}
export declare const PointMap: KeyedMapConstructor<Point>;
export declare const PointSet: KeyedSetConstructor<Point>;
export declare type PointString = `P(${string},${string})`;
/**
* A set of points forming a pointy-topped hexagonal lattice.
*
* All points must lie on a hexagonal lattice in which each hexagon has
* a pointy top. We use the doubled coordinates scheme described at
* https://www.redblobgames.com/grids/hexagons/. That is, y describes
* the row and x describes the column, so hexagons that are horizontally
* adjacent have their x coordinates differ by 2.
*/
export declare class PointyToppedHexagonalLattice extends HexagonalLattice {
static DIRECTIONS: {
E: Direction;
W: Direction;
NE: Direction;
NW: Direction;
SE: Direction;
SW: Direction;
};
edgeSharingDirections(): Direction[];
transformationFunctions(allowRotations: boolean, allowReflections: boolean): ((vector: Vector) => Vector)[];
getInsideOutsideCheckDirections(): [Direction, Direction[]];
}
export declare class RectangularLattice extends Lattice {
private _points;
private _pointIndices;
static EDGE_DIRECTIONS: {
N: Direction;
S: Direction;
E: Direction;
W: Direction;
};
static VERTEX_DIRECTIONS: {
NE: Direction;
NW: Direction;
SE: Direction;
SW: Direction;
N: Direction;
S: Direction;
E: Direction;
W: Direction;
};
/**
* @param points A set of points corresponding to a rectangular lattice.
* Note that these points need not fill a complete rectangle.
*/
constructor(points: Point[]);
get points(): Point[];
pointToIndex(point: Point): number | undefined;
edgeSharingDirections(): Direction[];
vertexSharingDirections(): Direction[];
labelForDirection(direction: Direction): string;
labelForDirectionPair(dir1: Direction, dir2: Direction): string;
transformationFunctions(allowRotations: boolean, allowReflections: boolean): ((vector: Vector) => Vector)[];
getInsideOutsideCheckDirections(): [Direction, Direction[]];
}
/**
* Returns a computation of a sightline through a grid.
* @param context The context in which to construct the constraints.
* @param symbolGrid The grid to check against.
* @param start The location of the cell where the sightline should begin.
* This is the first cell checked.
* @param direction The direction to advance to reach the next cell in the
* sightline.
* @param initializer The initial value for the accumulator.
* @param accumulate A function that accepts an accumulated value, a symbol,
* and (optionally) a point as arguments, and returns a new accumulated
* value. This function is used to determine a new accumulated value for
* each cell along the sightline, based on the accumulated value from the
* previously encountered cells as well as the point and/or symbol of the
* current cell.
* @param stop A function that accepts an accumulated value, a symbol, and
* (optionally) a point as arguments, and returns True if we should stop
* following the sightline when this symbol or point is encountered. By
* default, the sightline will continue to the edge of the grid.
* @returns The accumulated value.
*/
export declare function reduceCells<Name extends string, Accumulator extends Arith<Name>>(context: GrilopsContext<Name>, symbolGrid: SymbolGrid<Name>, start: Point, direction: Direction, initializer: Accumulator, accumulate: (a: Accumulator, c: Arith<Name>, p: Point) => Accumulator, stop?: (a: Accumulator, c: Arith<Name>, p: Point) => Bool<Name>): Accumulator;
/**
* Creates constraints for grouping cells into contiguous regions.
*/
export declare class RegionConstrainer<Name extends string, const Core extends Solver<Name> | Optimize<Name> = Solver<Name> | Optimize<Name>> {
private static _instanceIndex;
readonly ctx: GrilopsContext<Name>;
private readonly _solver;
private readonly _lattice;
private readonly _complete;
private readonly _minRegionSize;
private readonly _maxRegionSize;
private _edgeSharingDirectionToIndex;
private _parentTypeToIndex;
private _parentTypes;
private _parentGrid;
private _subtreeSizeGrid;
private _regionIdGrid;
private _regionSizeGrid;
/**
* @param lattice The structure of the grid.
* @param solver A `Solver` object. If None, a `Solver` will be constructed.
* @param complete If true, every cell must be part of a region. Defaults to
* true.
* @param rectangular If true, every region must be "rectangular"; for each
* cell in a region, ensure that pairs of its neighbors that are part of
* the same region each share an additional neighbor that's part of the
* same region when possible.
* @param minRegionSize The minimum possible size of a region.
* @param maxRegionSize The maximum possible size of a region.
*/
constructor(context: GrilopsContext<Name>, lattice: Lattice, solver?: Core | undefined, complete?: boolean, rectangular?: boolean, minRegionSize?: number | undefined, maxRegionSize?: number | undefined);
/**
* Creates the structures used for managing edge-sharing directions.
*
* Creates the mapping between edge-sharing directions and the parent
* indices corresponding to them.
*/
private _manageEdgeSharingDirections;
/**
* Create the grids used to model region constraints.
*/
private _createGrids;
/**
* Add constraints to the region modeling grids.
*/
private _addConstraints;
private _addRectangularConstraints;
/**
* Returns the `RegionConstrainer.parent_grid` value for the direction.
*
* For instance, if direction is (-1, 0), return the index for N.
*
* @param direction The direction to an edge-sharing cell.
* @returns The `RegionConstrainer.parent_grid` value that means that the
* parent in its region's subtree is the cell offset by that direction.
*/
edgeSharingDirectionToIndex(direction: Direction): number;
/**
* Returns the `RegionConstrainer.parent_grid` value for the parent type.
*
* The parent_type may be a direction name (like "N") or name of a special
* value like "R" or "X".
*
* @param parentType The parent type.
* @returns The corresponding `RegionConstrainer.parent_grid` value.
*/
parentTypeToIndex(parentType: string): number;
/**
* The `Solver` associated with this `RegionConstrainer`.
*/
get solver(): Core;
/**
* A dictionary of numbers identifying regions.
*
* A region's identifier is the position in the grid (going in order from left
* to right, top to bottom) of the root of that region's subtree. It is the
* same as the index of the point in the lattice.
*/
get regionIdGrid(): Map<Point, Arith<Name>>;
/**
* A dictionary of region sizes.
*/
get regionSizeGrid(): Map<Point, Arith<Name>>;
/**
* A dictionary of region subtree parent pointers.
*/
get parentGrid(): Map<Point, Arith<Name>>;
/**
* A dictionary of cell subtree sizes.
*
* A cell's subtree size is one plus the number of cells that are descendents
* of the cell in its region's subtree.
*/
get subtreeSizeGrid(): Map<Point, Arith<Name>>;
/**
* Prints the region parent assigned to each cell.
*
* Should be called only after the solver has been checked.
*/
treesToString(): string;
/**
* Prints the region subtree size of each cell.
*
* Should be called only after the solver has been checked.
*/
subtreeSizesToString(): string;
/**
* Prints a number identifying the region that owns each cell.
*
* Should be called only after the solver has been checked.
*/
regionIdsToString(): string;
/**
* Prints the size of the region that contains each cell.
*
* Should be called only after the solver has been checked.
*/
regionSizesToString(): string;
}
/**
* A shape defined by a list of `Vector` offsets.
*
* Each offset may optionally have an associated payload value.
*/
export declare class Shape<Name extends string, Payload extends Expr<Name>> {
readonly ctx: GrilopsContext<Name>;
private _offsetTuples;
/**
* @param offsets A list of offsets that define the shape. An offset may be a
* `Vector`; or, to optionally associate a payload value with the offset, it
* may be a `[Vector, Payload]`. A payload may be any z3 expression.
*/
constructor(context: GrilopsContext<Name>, offsets: Offset<Name, Payload>[]);
/**
* The offset vectors that define this shape.
*/
get offsetVectors(): Vector[];
/**
* The offset vector and payload value tuples for this shape.
*/
get offsetsWithPayloads(): [Vector, Payload | undefined][];
/**
* Returns a new shape with each offset transformed by `f`.
*/
transform(f: (vector: Vector) => Vector): Shape<Name, Payload>;
/**
* Returns a new shape that's canonicalized.
*
* A canonicalized shape is in sorted order and its first offset is
* `Vector`(0, 0). This helps with deduplication, since equivalent shapes
* will be canonicalized identically.
*
* @returns A `Shape` of offsets defining the canonicalized version of the
* shape, i.e., in sorted order and with first offset equal to
* `Vector`(0, 0).
*/
canonicalize(): Shape<Name, Payload>;
/**
* Returns true iff the given shape is equivalent to this shape.
*/
equivalent(shape: Shape<Name, Payload>): boolean;
}
/**
* Creates constraints for placing fixed shape regions into the grid.
*/
export declare class ShapeConstrainer<Name extends string, Payload extends Expr<Name>, const Core extends Solver<Name> | Optimize<Name> = Solver<Name> | Optimize<Name>> {
private static _instanceIndex;
readonly ctx: GrilopsContext<Name>;
private readonly _solver;
private readonly _lattice;
private readonly _complete;
private readonly _allowCopies;
private readonly _shapes;
private _variants;
private _shapeTypeGrid;
private _shapeInstanceGrid;
private _shapePayloadGrid;
/**
* @param lattice The structure of the grid.
* @param shapes A list of region shape definitions. The same region shape
* definition may be included multiple times to indicate the number of times
* that shape may appear (if allowCopies is false).
* @param solver A `Solver` object. If undefined, a `Solver` will be constructed.
* @param complete If true, every cell must be part of a shape region.
* Defaults to false.
* @param allowRotations If true, allow rotations of the shapes to be placed
* in the grid. Defaults to false.
* @param allowReflections If true, allow reflections of the shapes to be
* placed in the grid. Defaults to false.
* @param allowCopies If true, allow any number of copies of the shapes to
* be placed in the grid. Defaults to false.
*/
constructor(context: GrilopsContext<Name>, lattice: Lattice, shapes: Shape<Name, Payload>[], solver?: Core | undefined, complete?: boolean, allowRotations?: boolean, allowReflections?: boolean, allowCopies?: boolean);
private _makeVariants;
/**
* Create the grids used to model shape region constraints.
*/
private _createGrids;
private _addConstraints;
private _addGridAgreementConstraints;
private _addShapeInstanceConstraints;
private _addSingleCopyConstraints;
/**
* The `Solver` associated with this `ShapeConstrainer`.
*/
get solver(): Core;
/**
* A dictionary of z3 constants of shape types.
*
* Each cell contains the index of the shape type placed in that cell (as
* indexed by the shapes list passed in to the `ShapeConstrainer`
* constructor), or -1 if no shape is placed within that cell.
*/
get shapeTypeGrid(): Map<Point, Arith<Name>>;
getShapeTypeAt(p: Point): Arith<Name>;
/**
* z3 constants of shape instance IDs.
*
* Each cell contains a number shared among all cells containing the same
* instance of the shape, or -1 if no shape is placed within that cell.
*/
get shapeInstanceGrid(): Map<Point, Arith<Name>>;
getShapeInstanceAt(p: Point): Arith<Name>;
/**
* z3 constants of the shape offset payloads initially provided.
*
* undefined if no payloads were provided during construction.
*/
get shapePayloadGrid(): Map<Point, Payload> | undefined;
getShapePayloadAt(p: Point): Payload;
/**
* Prints the shape type assigned to each cell.
*
* Should be called only after the solver has been checked.
*/
shapeTypesToString(): string;
/**
* Prints the shape instance ID assigned to each cell.
*
* Should be called only after the solver has been checked.
*/
shapeInstancesToString(): string;
}
export declare enum ShapeExprKey {
HAS_INSTANCE_ID = 0,
NOT_HAS_INSTANCE_ID = 1,
HAS_SHAPE_TYPE = 2
}
/**
* @module symbols This module supports defining symbols that may be filled into grid cells.
*/
/**
* A marking that may be filled into a `grilops.grids.SymbolGrid` cell.
*/
declare class Symbol_2 {
private _index;
private _name;
private _label;
/**
* @param index The index value assigned to the symbol.
* @param name The code-safe name of the symbol.
* @param label The printable label of the symbol.
*/
constructor(index: number, name?: string, label?: string);
/**
* The index value assigned to the symbol.
*/
get index(): number;
/**
* The code-safe name of the symbol.
*/
get name(): string;
/**
* The printable label of the symbol.
*/
get label(): string;
toString(): string;
}
export { Symbol_2 as Symbol }
/**
* A grid of cells that can be solved to contain specific symbols.
*/
export declare class SymbolGrid<Name extends string, const Core extends Solver<Name> | Optimize<Name> = Solver<Name> | Optimize<Name>> {
private static _instanceIndex;
readonly ctx: GrilopsContext<Name>;
private _lattice;
private _symbolSet;
private _solver;
private _grid;
/**
* @param context The context in which to construct the grid.
* @param lattice The structure of the grid.
* @param symbolSet The set of symbols to be filled into the grid.
* @param solver A `Solver` object. If undefined, a `Solver` will be constructed.
*/
constructor(context: GrilopsContext<Name>, lattice: Lattice, symbolSet: SymbolSet, solver?: Core | undefined);
/**
* The `Solver` object associated with this `SymbolGrid`.
*/
get solver(): Core;
/**
* The `grilops.symbols.SymbolSet` associated with this `SymbolGrid`.
*/
get symbolSet(): SymbolSet;
/**
* The grid of cells.
*/
get grid(): Map<Point, Arith<Name>>;
/**
* The lattice of points in the grid.
*/
get lattice(): Lattice;
/**
* Returns a list of cells that share an edge with the given cell.
* @param p The location of the given cell.
* @returns A `Neighbor[]` representing the cells sharing
* an edge with the given cell.
*/
edgeSharingNeighbors(p: Point): Neighbor<Name>[];
/**
* Returns the cells that share a vertex with the given cell.
*
* In other words, returns a list of cells orthogonally and diagonally
* adjacent to the given cell.
* @param p The location of the given cell.
* @returns A `Neighbor[]` representing the cells sharing
* a vertex with the given cell.
*/
vertexSharingNeighbors(p: Point): Neighbor<Name>[];
/**
* Returns the cell at the given point.
* @param p The location of the cell.
* @returns The cell at the given point.
*/
cellAt(p: Point): Arith<Name>;
/**
* Returns an expression for whether this cell contains this value.
* @param p The location of the given cell.
* @param value The value to satisfy the expression.
* @returns An expression that's true if and only if the cell at p contains
* this value.
*/
cellIs(p: Point, value: number): Bool<Name>;
/**
* Returns an expression for whether this cell contains one of these values.
* @param p The location of the given cell.
* @param values The set of values to satisfy the expression.
* @returns An expression that's true if and only if the cell at p contains
* one of these values.
*/
cellIsOneOf(p: Point, values: number[]): Bool<Name>;
/**
* Returns true if the puzzle has a solution, false otherwise.
*/
solve(): Promise<boolean>;
/**
* Returns true if the solution to the puzzle is unique, false otherwise.
*
* Should be called only after `SymbolGrid.solve` has already completed
* successfully.
*/
isUnique(): Promise<boolean>;
/**
* Returns the solved symbol grid.
*
* Should be called only after `SymbolGrid.solve` has already completed
* successfully.
*/
solvedGrid(): Map<Point, number>;
/**
* Prints the solved grid using symbol labels.
*
* Should be called only after `SymbolGrid.solve` has already completed
* successfully.
* @param hookFunction A function implementing custom symbol display
* behavior, or None. If this function is provided, it will be called for
* each cell in the grid, with the arguments p (`Point`)
* and the symbol index for that cell (`number`). It may return a string to
* print for that cell, or None to keep the default behavior.
*/
toString(hookFunction?: ((p: Point, i: number) => string) | undefined): string;
}
declare namespace symbols {
export {
makeLetterRangeSymbolSet,
makeNumberRangeSymbolSet,
Symbol_2 as Symbol,
SymbolSet
}
}
/**
* A set of markings that may be filled into a `grilops.grids.SymbolGrid`.
*/
export declare class SymbolSet {
private _indexToSymbol;
private _labelToSymbolIndex;
readonly indices: Record<string, number>;
/**
* @param symbols A list of specifications for the symbols. Each specification
* may be a code-safe name, a (code-safe name, printable label) tuple, or
* a (code-safe name, printable label, index value) tuple.
*/
constructor(symbols: (string | [string, string] | [string, string, number])[]);
private _nextUnusedIndex;
/**
* Appends an additional symbol to this symbol set.
* @param name The code-safe name of the symbol.
* @param label The printable label of the symbol.
*/
append(name?: string | undefined, label?: string | undefined): void;
/**
* Returns the minimum index value of all of the symbols.
*/
minIndex(): number;
/**
* Returns the maximum index value of all of the symbols.
*/
maxIndex(): number;
/**
* The map of all symbols.
*/
get symbols(): Map<number, Symbol_2>;
toString(): string;
}
/**
* A vector representing an offset in two dimensions.
*/
export declare class Vector {
/**
* The relative distance in the y dimension.
*/
dy: number;
/**
* The relative distance in the x dimension.
*/
dx: number;
constructor(dy: number, dx: number);
/**
* Returns a vector that's the negation of this one.
*/
negate(): Vector;
/**
* Translates this vector's endpoint in the given direction.
*/
translate(other: Vector): Vector;
toString(): VectorString;
static fromString(s: VectorString): Vector;
equals(other: Vector): boolean;
static comparator(a: Vector, b: Vector): number;
}
export declare const VectorMap: KeyedMapConstructor<Vector>;
export declare const VectorSet: KeyedSetConstructor<Vector>;
export declare type VectorString = `V(${string},${string})`;
export declare function zip<T1, T2>(a: T1[], b: T2[]): [T1, T2][];
export declare function zip<T1, T2, T3>(a: T1[], b: T2[], c: T3[]): [T1, T2, T3][];
export declare function zip<T>(...args: T[][]): T[][];
export { }