/** Various rendering targets
 *
 *  Copyright (C) 2018-2024  Nathan Fritzler
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see http://www.gnu.org/licenses/
 */
/** The location of a pixel */
export interface Location {
    /** x position */
    x: number;
    /** y position */
    y: number;
    /** Should this location loop around screen borders? */
    loop?: boolean;
    /** Should this location be treated to be on the current frame, previous, or older?
    *
    * Current frame is zero. Higher is older - but not guarenteed to be present
    */
    frame?: number;
}
/** Convert a loction to a index to reduce need for 2D arrays
* @param x - x location
* @param y - y location
* @param width - width of the canvas
*/
export function location2Index({ x, y }: Location, width: number): number;
/** Transpose a list of locations, using a location.
* @param locs - Locations to be transposed. If the frame or loop values are
* absent, they are set to the value in [offset]. If absent from [offset] they
* are not set.
* @param offset - Amount to transpose the locations by, represented by a
* location.
*/
export function transposeLocations(locs: Location[], offset: Location): Location[];
/** Abstract rendering type. Used by {@link pixelmanipulator.PixelManipulator} to enable rendering to
* various targets. */
export abstract class Renderer<T> {
    /** Renders a pixel on a given location on the next call to {@link Renderer.update}
    * @param location - Where to render the pixel.
    * @param id - the pixel to render.
    */
    abstract renderPixel(location: Location, id: number): void;
    /** Reset the render target. */
    abstract reset(): void;
    /** Update the render target. Draws all changes queued up by {@link Renderer.renderPixel}. */
    abstract update(): void;
    /** The {@link pixelmanipulator.ElementData.renderAs} value for the default element */
    abstract defaultRenderAs: T;
    /** Ordered by ID, the {@link pixelmanipulator.ElementData.renderAs} info for each element. */
    renderInfo: T[];
    /** Intentionally overridable, called when an element is modified.
    * @param id - The id of the element to modify.
    * @param newRenderAs - The new {@link pixelmanipulator.ElementData.renderAs} info.
    * @returns The value passed upstream to be stored as the actual renderAs info,
    * allowing for sanitation in this function, or one overriding it.
    */
    modifyElement(id: number, newRenderAs: T): T;
    /** @param value - The new width of the canvas */
    set_width(value: number): void;
    /** @returns the width of the canvas */
    get_width(): number;
    /** @param value - The new height of the canvas */
    set_height(value: number): void;
    /** @returns the height of the canvas */
    get_height(): number;
}
/** The color of an element */
export type Color = [number, number, number, number] | [number, number, number] | [number, number] | [number] | [];
/** Render onto an {@link HTMLCanvasElement} using a {@link CanvasRenderingContext2D} */
export class Ctx2dRenderer extends Renderer<Color> {
    /** @param canvas - The canvas to render on, and to adjust the size of */
    constructor(canvas: HTMLCanvasElement);
    /** The last known image data from {@link Ctx2dRenderer.ctx} */
    imageData: ImageData;
    /** The rendering context for the canvas */
    ctx: CanvasRenderingContext2D;
    /** The canvas */
    canvas: HTMLCanvasElement;
    /** Default color is solid black */
    defaultRenderAs: Color;
    /** In addition to calling {@link Renderer.modifyElement}, this leftpads colors
    * with `255` and checks for dupicates.
    * @param id - Id of element
    * @param newRenderAs - The proposed color of the element.
    * @returns the actual color of the element. Always 4 long.
    */
    modifyElement(id: number, newRenderAs: Color): Color;
    /** @param loc - location of the pixel to render. Ignores {@link Location.frame} and {@link Location.loop}
    * @param id - The id of the pixel to render.
    */
    renderPixel(loc: Location, id: number): void;
    reset(): void;
    update(): void;
    set_width(value: number): void;
    set_height(value: number): void;
}
/** Render to a string */
export class StringRenderer extends Renderer<string> {
    defaultRenderAs: string;
    /** The callback function passed to the constructor. Called on {@link StringRenderer.update} */
    readonly _callback: (string: string) => void;
    /** @param callback - A function called on {@link StringRenderer.update}. Passed a
    * string with the renderable state of the {@link pixelmanipulator.PixelManipulator} */
    constructor(callback: (string: string) => void);
    /** @param newRenderAs - The proposed character to use. Must be 1 char long and unique */
    modifyElement(id: number, newRenderAs: string): string;
    reset(): void;
    /** @param x - X location of pixel
    * @param y - y location of pixel
    * @param id - The id of the pixel
    */
    renderPixel({ x, y }: Location, id: number): void;
    update(): void;
}
/** render on two different targets (which may also be {@link SplitRenderer}) */
export class SplitRenderer<A, B> extends Renderer<{
    a: A;
    b: B;
}> {
    defaultRenderAs: {
        a: A;
        b: B;
    };
    a: Renderer<A>;
    b: Renderer<B>;
    constructor(a: Renderer<A>, b: Renderer<B>);
    renderPixel(loc: Location, id: number): void;
    reset(): void;
    update(): void;
    modifyElement(id: number, { a, b }: {
        a: A;
        b: B;
    }): {
        a: A;
        b: B;
    };
}
/** A list of locations, usually relative around a pixel. */
type Hitbox = Location[];
declare function startAnimation(callback: () => void): number | ReturnType<typeof setInterval>;
/** The argument to {@link ElementDataUnknown.liveCell} and
* {@link ElementDataUnknown.deadCell}
*/
export interface Rel {
    /** The X location of this pixel. */
    x: number;
    /** The Y location of this pixel. */
    y: number;
    /** The ID number of the current pixel. Reccommended if performance profiling
    * shows string comparision is a bottleneck.
    */
    oldId: number;
    /** The ID of the element for which this is being called. (in a
    * {@link ElementDataUnknown.liveCell} that's the same as {@link Rel.oldId}, but in a
    * {@link ElementDataUnknown.deadCell} it's the id that the deadCell belongs to.
    */
    thisId: number;
}
/** Much like {@link ElementDataUnknown} but all fields except {@link ElementData.madeWithRule},
* {@link ElementData.liveCell} and {@link ElementData.deadCell} are mandatory. */
export interface ElementData<T> extends ElementDataUnknownNameMandatory<T> {
    renderAs: T;
    hitbox: Hitbox;
}
/** Information about an element. */
export interface ElementDataUnknown<T> {
    /** The name of the element. */
    name?: string;
    /** Information on how to render this element */
    renderAs?: T;
    /** {@link ElementDataUnknown.deadCell} will only be called on empty
    * pixels within the hitbox of a live cell. Array of relative coordinate pairs.
    * Optional, defaults to the result of {@link neighborhoods.moore}
    * called with no arguments.
    */
    hitbox?: Hitbox;
    /** Every frame of animation, pixelmanipulator iterates through each and every pixel on the screen. If this element is found, it calls this function.
    */
    liveCell?: (rel: Rel) => void;
    /** Every frame of animation, pixelmanipulator iterates through each and every
    * pixel on the screen. If this element is found, it calls this function on
    * each of the locations defined in {@link ElementDataUnknown.hitbox} so long as
    * the pixel matches the value in {@link PixelManipulator.defaultId}, without
    * calling the same dead pixel twice.
    */
    deadCell?: (rel: Rel) => void;
    /** If present, indicates that this element was auto-generated */
    madeWithRule?: true;
}
/** Much like {@link ElementDataUnknown} but the name is mandatory. */
export interface ElementDataUnknownNameMandatory<T> extends ElementDataUnknown<T> {
    name: string;
}
/** Template generators for your elements. */
export const rules: {
    /** Generates elements like conway's game of life.
    * @param p - `lifelike` needs to be able to call {@link PixelManipulator.mooreNearbyCounter}
    * @param pattern - The B/S syntax indicator of on how many cells of the same
    * type in the moore radius around each pixel should survive, and on how many
    * should be born.
    * @param loop - Should this loop around screen edges? (Passed to {@link renderers.Location.loop})
    */
    lifelike: <T>(p: PixelManipulator<T>, pattern: string, loop?: boolean) => ElementDataUnknown<T>;
    /** Generates fundamental cellular automata
    * @param p - `wolfram` needs to be able to call {@link PixelManipulator.wolframNearbyCounter}
    * @param pattern - The Rule num syntax, where the 8-bit number is translated
    * into a binary list, each where the inverted 3-binary-digit index represents
    * the state of cells in the row above. On a match, the cell becomes the state
    * specified in the initial 8-bit number.
    * @param loop - Should this loop around screen edges? (Passed to {@link PixelManipulator.wolframNearby})
    */
    wolfram: <T>(p: PixelManipulator<T>, pattern: string, loop?: boolean) => ElementDataUnknown<T>;
};
/** Sizes to set the canvases to. If a value below is absent, old value is used.
*/
export interface CanvasSizes {
    /** width of the canvas */
    canvasW?: number;
    /** height of the canvas */
    canvasH?: number;
}
/** A cellular automata engine */
export class PixelManipulator<T> {
    /**
    * @param renderer - The target to render things to.
    * @param width - How wide should the initial target be?
    * @param height - How tall should the initial target be?
    */
    constructor(renderer: Renderer<T>, width: number, height: number);
    /** An instanace of the object that shows the state to the user. */
    renderer: Renderer<T>;
    /**
    * This is the number that indicates what animation frame the iterate function
    * is being called with.
    *
    * You can use this to mannually stop the iterations like so:
    * `cancelAnimationFrame(this.loopint)` (not reccommended)
    */
    loopint: ReturnType<typeof startAnimation>;
    /**
    * A low-level listing of the availiable elements.
    *
    * Format is much like the argument to
    * {@link PixelManipulator.addMultipleElements}, but is not sanitized.
    */
    readonly elements: Array<ElementData<T>>;
    /**
    * A mapping from old names for elements to new names for elements.
    *
    * Allows a user to modify the name of an element at runtime.
    */
    nameAliases: Map<string, string>;
    /**
    * A string indicating weather it is currently animating or not.
    *
    * It is `"playing"` if it is currently animating, or `"paused"` if not
    * currently animating.
    *
    * This has been around since early version 0, and once was the `innerText`
    * value of a pause/play button!
    */
    mode: 'playing' | 'paused';
    /**
    * The elm that pixelmanipulator will fill the screen with upon initialization,
    * and what elements should return to when they are "dead". Default value is
    * 0, an element with the color `#000F`
    *
    * If you update this, be sure to update {@link renderers.Renderer.defaultRenderAs} in {@link PixelManipulator.renderer}
    */
    defaultId: number;
    /** Called before {@link PixelManipulator.iterate} does its work.
    * @returns false to postposne iteration.
    */
    onIterate: () => (boolean | undefined);
    /** Called after {@link PixelManipulator.iterate} does its work. */
    onAfterIterate: () => undefined;
    /** Gets called after a call to {@link PixelManipulator.modifyElement}. The ID is
    * passed as the only argument.
    * @param id - The element that was modified.
    */
    onElementModified: (id: number) => void;
    /** @returns the width of the canvas */
    get_width(): number;
    /** @param value - The new width of the canvas */
    set_width(value: number): void;
    /** @returns the height of the canvas */
    get_height(): number;
    /** @param value - The new height of the canvas */
    set_height(value: number): void;
    /** fills the screen with value, at an optional given percent
    * @param value - The element to put on the screen
    * @param pr - The percent as a number from 1 to 100, defaulting at 15
    */
    randomlyFill(value: string | number, pr?: number): void;
    /** Adds multiple elements.
    *
    * @param elements - Index is the element name, value is the element data (and
    * does not require the name). Value is passed to
    * {@link PixelManipulator.addElement}
    */
    addMultipleElements(elements: Record<string, ElementDataUnknown<T>>): void;
    /** Add an element with the given element data
    * @param data - The details about the element.
    * @returns The generated {@link PixelManipulator.elements} index
    */
    addElement(data: ElementDataUnknownNameMandatory<T>): number;
    /**
    * @param id - How to identify what element to modify.
    * @param data - Values to apply to the pre-existing element.
    *
    * Automatically calls {@link PixelManipulator.aliasElements} if
    * {@link ElementDataUnknown.name} is present in `data`
    */
    modifyElement(id: number, data: ElementDataUnknown<T>): void;
    /**
    * @param oldName - The old {@link ElementData.name}
    * @param newName - The new {@link ElementData.name}
    *
    * Adds the name to {@link PixelManipulator.nameAliases}, and ensures no alias
    * loops are present.
    */
    aliasElements(oldName: string, newName: string): void;
    /** Respecting aliases, convert an element name into its number.
    * @param name - name of element
    * @returns The number of the element
    */
    nameToId(name: string): number;
    /**
    * @param name - Name of the (possibly aliased) element.
    * @returns The element from {@link PixelManipulator.elements}, respecting
    * aliases in {@link PixelManipulator.nameAliases}, or {@link undefined} if not found.
    */
    getElementByName(name: string): ElementData<T> | undefined;
    /**
    * @param loc - Location of the element.
    * @returns Name of element at passed-in location. See {@link ElementData.name}
    */
    whatIs(loc: Location): string;
    /** Start iterations on all of the elements on the canvas.
    * Sets {@link PixelManipulator.mode} to `"playing"`, and requests a new animation
    * frame, saving it in {@link PixelManipulator.loopint}.
    *
    * @param canvasSizes - If {@link PixelManipulator.mode} is already `"playing"` then
    * canvasSizes is passed to {@link PixelManipulator.reset}. Otherwise reset is not
    * called.
    */
    play(canvasSizes?: CanvasSizes): void;
    /** Reset, resize and initialize the canvas(es).
    * Calls {@link PixelManipulator.pause} then
    * {@link PixelManipulator.update}. Resets all internal state, excluding the
    * element definitions.
    *
    * @param canvasSizes - Allows one to change the size of the canvases during
    * the reset.
    */
    reset(canvasSizes?: CanvasSizes): void;
    /** pause canvas iterations
    * Sets {@link PixelManipulator.mode} to `"paused"` and cancels the animation frame
    * referenced in {@link PixelManipulator.loopint}
    */
    pause(): void;
    /**
    * @param loc - Location of the pixel (could be out of bounds).
    * @returns null if out-of-bounds when loop setting is false, or the location (loop set to false).
    */
    locationBoundsCheck(loc: Location): null | Location;
    /**
    * @param loc - Location of the pixel
    * @returns the element id at a given location
    */
    getPixelId(loc: Location): number;
    /**
    * Applies any changes made with {@link renderers.Renderer.renderPixel} on {@link PixelManipulator.renderer} to the canvas
    */
    update(): void;
    /**
    * @param loc - Where to confirm the element
    * @param id - The elm you expect it to be
    * @returns Does the cell at `loc` match `ident`?
    */
    confirmElm(loc: Location, id: number | string): boolean;
    /** Calculate the total number of elements within an area
    * @param area - The locations to total up.
    * @param search - The element to look for
    * @returns The total
    */
    totalWithin(area: Location[], search: number | string): number;
    /** @param name - element to look for
    * @param center - location of the center of the moore area
    * @returns Number of matching elements in moore radius */
    mooreNearbyCounter(center: Location, search: number | string): number;
    /** @param area - The Area to search within
    * @param ruleNum - A bitfield of what states a pixel should live or die on.
    * @param search - The element to search for
    * @see {@link PixelManipulator.wolframNewState} for higher-level tool
    * @see {@link PixelManipulator.fundamentalStatesWithin} for lower-level tool
    * @returns The state that the bitfied says this pixel should be in the next frame.
    */
    fundamentalNewState(area: Location[], ruleNum: number, search: number | string): boolean;
    /** @param area - Locations to look at.
    * @param search - Locations to mark as a true bit.
    * @see {@link PixelManipulator.fundamentalNewState} for higher-level tool
    * @returns number as a bitfied array, in order of the items in area, from left to right.
    *
    * That means that `(fundamentalStatesWithin([loc], search) & 1) === boolToNumber(confirmElm(loc, search))`
    *
    * You may want to see [this page](https://www.wolframscience.com/nks/notes-5-2--general-rules-for-multidimensional-cellular-automata/)
    * for more details on how this might be used.
    */
    fundamentalStatesWithin(area: Location[], search: number | string): number;
    /** @param loc - The pixel to change. (Defaults {@link renderers.Location.loop} to false)
    * @param ruleNum - A bitfield of what states a pixel should live or die on.
    * @param search - The element to search for
    * @see {@link PixelManipulator.fundamentalNewState} for more general tool.
    * @returns The state that the bitfied says this pixel should be in the next frame.
    */
    wolframNewState(loc: Location, ruleNum: number, search: number | string): boolean;
    /**
    * @param current - "Current" pixel location. (Defaults {@link renderers.Location.loop} to false)
    * @param search - element to look for
    * @see {@link PixelManipulator.fundamentalStatesWithin} for lower-level tool
    * @returns Number used as bit area to indicate occupied cells
    */
    wolframNearby(current: Location, search: number | string): number;
    /** Counter tool used in slower wolfram algorithim.
    * @deprecated Replaced with {@link PixelManipulator.wolframNearby} for use in faster
    * algorithms
    * @param current - "Current" pixel location
    * @param name - element to look for
    * @param bindex - Either a string like `"001"` to match to, or the same
    * encoded as a number.
    * @returns Number of elements in wolfram radius */
    wolframNearbyCounter(current: Location, name: number | string, binDex: number | string): boolean;
    /** Set a pixel in a given location.
    *
    * @param x - X position.
    * @param y - Y position.
    * @param ident - Value to identify the element.
    *
    * - If a string, it assumes it's an element name.
    * - If a number, it assumes it's an element ID
    *
    * @param loop - Defaults to {@link true}. Wraps `x` and `y` around canvas borders.
    */
    setPixel(loc: Location, ident: string | number): void;
    /** Number of pixels per element in the last frame */
    pixelCounts: Record<number, number>;
    /** A single frame of animation. Media functions pass this into
    * {@link requestAnimationFrame}.
    *
    * Be careful! Calling this while {@link PixelManipulator.mode} is `"playing"`
    * might cause two concurrent calls to this function. If any of your automata
    * have "hidden state" - that is they don't represent every detail about
    * themselves as data within the pixels - it might cause conflicts.
    */
    iterate(): void;
    /**
    * A List of {@link Uint32Array}s each the length of width times height of the
    * canvas. Frame 0 is the new frame, frame one is the prior, etc. Each item
    * holds the element id of each element on screen, from left to right, top to
    * bottom.
    */
    frames: Uint32Array[];
}
/** Version of library **for logging purposes only**. Uses semver. */
export const version: string;
/** Licence disclaimer for PixelManipulator */
export const licence: string;

//# sourceMappingURL=types.d.ts.map
