Skip to content

Commit

Permalink
Added lenses, tools, misc to PlannersJS
Browse files Browse the repository at this point in the history
  • Loading branch information
LaiYanKai committed May 21, 2024
1 parent 295a49f commit 80509e5
Show file tree
Hide file tree
Showing 33 changed files with 828 additions and 337 deletions.
70 changes: 53 additions & 17 deletions PlannersJS/scripts/algs/algs.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ Algs.AbstractNode = class {
Object.seal(this.costs);
}
};
Object.seal(Algs.AbstractNode);

Algs.AbstractPriorityQueueNode = class extends Algs.AbstractNode {
pq_sprite;
Expand All @@ -36,18 +35,20 @@ Algs.AbstractPriorityQueueNode = class extends Algs.AbstractNode {
Object.freeze(this.pq_sprite);
}
}
Object.seal(Algs.AbstractPriorityQueueNode);

Algs.AbstractAlg = class {
params;
steps;
canvases;
lenses;
#canvases;
#lenses;
default_lens_idx;
rank_names;
num_ranks;
default_rank;
#cells;

get num_canvases() { this.#canvases.length; }
get num_lenses() { this.#lenses.length; }

/** Constructs an abstract path planner.
* @param {Algs.Params} params key, value pair of parameters.
Expand All @@ -57,6 +58,28 @@ Algs.AbstractAlg = class {
this.#setParams(params);
}

/**
* @yields {UI.AbstractCanvas}
*/
*canvases() {
for (const canvas of this.#canvases)
yield canvas;
}

/** @returns {UI.AbstractCanvas} */
canvas(idx) { return this.#canvases[idx]; }

/**
* @yields {UI.AbstractLens}
*/
*lenses() {
for (const lens of this.#lenses)
yield lens;
}

/** @returns {UI.AbstractLens} */
lens(idx) { return this.#lenses[idx]; }

/** Returns the cost at the *cell* coordinate.
* @param {[number, number]} cell_coord A pair of non-negative integers describing the *cell* coordinates.
* @returns {number} the cost of the cell at the *cell* coordinate, or NaN if the cell does not exist.
Expand All @@ -75,18 +98,35 @@ Algs.AbstractAlg = class {
for (const canvas of canvases)
if (!(canvas instanceof UI.AbstractCanvas))
throw new Error(`"canvas" is not UI.AbstractCanvas!`);
this.canvases = canvases;
Object.freeze(this.canvases);
this.#canvases = canvases;
Object.freeze(this.#canvases);
}

setLenses(lenses) {
/**
*
* @param {Array<UI.AbstractLens>} lenses Array of lenses
* @param {number} default_lens_idx The default lens is given by lenses[default_lens_idx].
*/
setLenses(lenses, default_lens_idx) {
if (Array.isArray(lenses) === false)
throw new TypeError(`"lenses" must be an array of UI.AbstractLens`)
for (const lens of lenses)
if (!(lens instanceof UI.AbstractLens))
throw new Error(`layer is not UI.AbstractLens!`);
this.lenses = lenses;
Object.freeze(this.lenses);
if (!Utils.isFiniteNonNegativeInteger(default_lens_idx) || default_lens_idx > lenses.length)
throw new RangeError(`"default_lens_idx" must be >= 0 and shorter than the length of "lenses"`);
let num_lens_none = 0;
for (const lens of lenses) {
if (lens instanceof UI.AbstractLens === false)
throw new TypeError(`"lenses" must be an array of UI.AbstractLens`)
if (lens instanceof UI.LensNone)
++num_lens_none;
}
if (num_lens_none !== 1) {
throw new Error(`There must be exactly one UI.LensNone in lenses`);
}

this.#lenses = lenses;
this.default_lens_idx = default_lens_idx;
Object.freeze(this.#lenses);
Object.freeze(this.default_lens_idx);
}

// used only once
Expand All @@ -109,13 +149,12 @@ Algs.AbstractAlg = class {
this.rank_names = rank_names;
this.default_rank = default_rank;
this.num_ranks = this.rank_names.length;

Object.freeze(this.rank_names);
Object.freeze(this.default_rank);
Object.freeze(this.num_ranks);
}
};
Object.seal(Algs.AbstractAlg);

Algs.GridAlgNeighbor = class {

Expand Down Expand Up @@ -163,7 +202,6 @@ Algs.GridAlgNeighbor = class {
Object.freeze(this.is_cardinal);
Object.freeze(this.metric_length);
Object.freeze(this.adj_cell_dir);
Object.seal(this);
}
};

Expand Down Expand Up @@ -269,8 +307,6 @@ Algs.AbstractGridAlg = class extends Algs.AbstractAlg {
this.#nbNodeInfoV = has_lethal ? this.#nbNodeInfoVL.bind(this) : this.#nbNodeInfoVN.bind(this);
this.#nbNodeInfos = this.#nbNodeInfosV.bind(this);
}

Object.seal(this);
};

/** Used only once */
Expand Down
71 changes: 48 additions & 23 deletions PlannersJS/scripts/algs/astar.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"use strict";

Algs.AStarCanvasCell = class extends UI.AbstractCanvasCell {
constructor() {
super(AStarAction.length);
super(0, AStarAction.length);
}

add(f, g, h, status, ...abstract_canvas_cell_args) {
Expand All @@ -10,9 +11,9 @@ Algs.AStarCanvasCell = class extends UI.AbstractCanvasCell {
sprite.register(AStarAction.G, g);
sprite.register(AStarAction.H, h);
sprite.register(AStarAction.Status, status);
sprite.dom_svg.addEventListener(
sprite.dom.addEventListener(
"mousemove", this.#setTip.bind(this, sprite), false);
sprite.dom_svg.addEventListener(
sprite.dom.addEventListener(
"mouseout", ui.tooltip.hide.bind(ui.tooltip), false);
return sprite;
}
Expand All @@ -39,15 +40,15 @@ Algs.AStarCanvasCell = class extends UI.AbstractCanvasCell {
ui.tooltip.setTip(
TooltipPosition.Right,
message,
sprite.dom_svg,
sprite.dom,
);
}
};

Algs.AStarCanvasVertex = class extends UI.AbstractCanvasVertex {
/** @type {UI.Tooltip} */
constructor() {
super(AStarAction.length);
super(0, AStarAction.length);
}

add(f, g, h, status, ...abstract_canvas_cell_args) {
Expand All @@ -56,9 +57,9 @@ Algs.AStarCanvasVertex = class extends UI.AbstractCanvasVertex {
sprite.register(AStarAction.G, g);
sprite.register(AStarAction.H, h);
sprite.register(AStarAction.Status, status);
sprite.dom_svg.addEventListener(
sprite.dom.addEventListener(
"mousemove", this.#setTip.bind(this, sprite), false);
sprite.dom_svg.addEventListener(
sprite.dom.addEventListener(
"mouseout", ui.tooltip.hide.bind(ui.tooltip), false);
return sprite;
}
Expand All @@ -84,7 +85,7 @@ Algs.AStarCanvasVertex = class extends UI.AbstractCanvasVertex {
ui.tooltip.setTip(
TooltipPosition.Right,
message,
sprite.dom_svg,
sprite.dom,
);
}
}
Expand Down Expand Up @@ -112,34 +113,45 @@ Algs.AStarNode = class extends Algs.AbstractPriorityQueueNode {
this.f = this.g * g_weight + this.h * h_weight;
}
}
Object.seal(Algs.AstarNode);


Algs.AStar = class extends Algs.AbstractGridAlg {
/** @type {Algs.AbstractPriorityQueue} */
#open_list;
/** @type {Map<Algs.AStarNode} */
#nodes;
get #canvas_arrows() { return this.canvases[0]; }
get #canvas_nodes() { return this.canvases[1]; }
/** @returns {UI.AbstractCanvasArrow} */
get #canvas_arrows() { return this.canvas(1); }
/** @returns {Algs.AStarCanvasCell | Algs.AStarCanvasVertex} */
get #canvas_nodes() { return this.canvas(0); }
/** @returns {UI.AbstractLens} */
get #lens_f() { return this.lens(1); }
/** @returns {UI.AbstractLens} */
get #lens_g() { return this.lens(2); }
/** @returns {UI.AbstractLens} */
get #lens_h() { return this.lens(3); }
/** @type{UI.Step} */
#step; // current step
/** @type{Array<[number, number]>} */
#path;

constructor(alg_params) {
super(["0: Smallest", "1: Every Expansion"], 1, alg_params);
super(["1: Smallest", "2: Every Expansion"], 1, alg_params);

// Set up canvases
let size;
const canvases = Array(2);
canvases[0] = new UI.AbstractCanvasArrow(0); // put arrows below the nodes
if (alg_params.node_type === AlgNodeType.Cell) {
canvases[1] = new Algs.AStarCanvasCell();
canvases[0] = new Algs.AStarCanvasCell();
this.#addArrow = this.#addArrowCell;
size = ui_states.size;
}
else if (alg_params.node_type === AlgNodeType.Vertex) {
canvases[1] = new Algs.AStarCanvasVertex();
canvases[0] = new Algs.AStarCanvasVertex();
this.#addArrow = this.#addArrowVertex;
size = Utils.addCoord(ui_states.size, [1, 1]);
}
canvases[1] = new UI.AbstractCanvasArrow(1, 0); // put arrows above the nodes
super.setCanvases(canvases);

// Check h_weight and g_weight
Expand All @@ -149,7 +161,13 @@ Algs.AStar = class extends Algs.AbstractGridAlg {
throw new TypeError("g_weight must be a number!");

// Set up lenses

const lenses = [
new UI.LensNone(this.#canvas_nodes, "None", "None"),
new UI.LensRainbow(this.#canvas_nodes, AStarAction.F, "F-cost", "$F"),
new UI.LensRainbow(this.#canvas_nodes, AStarAction.G, "G-cost", "$G"),
new UI.LensRainbow(this.#canvas_nodes, AStarAction.H, "H-cost", "$H"),
]
super.setLenses(lenses, 0);

// Set up Openlist
let cost_indices = [];
Expand Down Expand Up @@ -177,6 +195,7 @@ Algs.AStar = class extends Algs.AbstractGridAlg {
SpriteActionClass.Transparent,
0,
SpriteActionOutline.None);
this.#lens_h.updateBounds(h);
sprite.vis(); // sprites are not visualized at the first step.
const node = new Algs.AStarNode(coord, Infinity, h, sprite, null);
this.#nodes.set(id, node);
Expand Down Expand Up @@ -257,6 +276,8 @@ Algs.AStar = class extends Algs.AbstractGridAlg {
node.changeGandF(new_g, this.params.g_weight, this.params.h_weight);
this.#step.registerWithData(node.sprite, AStarAction.G, node.g);
this.#step.registerWithData(node.sprite, AStarAction.F, node.f);
this.#lens_g.updateBounds(node.g);
this.#lens_f.updateBounds(node.f);
}

#changeParent(node, new_parent_node) {
Expand Down Expand Up @@ -358,6 +379,14 @@ Algs.AStar = class extends Algs.AbstractGridAlg {
#visualizeExpanded(node) {
this.#step.registerWithData(node.sprite, SpriteAction.Class, SpriteActionClass.Red);
this.#step.registerWithData(node.sprite, AStarAction.Status, AStarNodeStatus.Expanding);

const id = this.serialize(node.coord);
const sprite = this.#canvas_arrows.sprite(id);
if (sprite) {
this.#step.registerWithData(sprite,
SpriteAction.Class,
SpriteActionClass.Blue);
}
}

#visualizeOpened(node) {
Expand All @@ -377,7 +406,7 @@ Algs.AStar = class extends Algs.AbstractGridAlg {
Utils.addCoord(node.coord, [0.5, 0.5]),
Utils.subtractCoord(new_parent.coord, node.coord),
false,
SpriteActionClass.Blue,
SpriteActionClass.Orange,
0);
}
#addArrowVertex(id, node, new_parent) {
Expand All @@ -386,7 +415,7 @@ Algs.AStar = class extends Algs.AbstractGridAlg {
node.coord,
Utils.subtractCoord(new_parent.coord, node.coord),
false,
SpriteActionClass.Blue,
SpriteActionClass.Orange,
0);
}

Expand All @@ -397,9 +426,6 @@ Algs.AStar = class extends Algs.AbstractGridAlg {
this.#step.registerWithData(sprite,
SpriteAction.Display,
true);
this.#step.registerWithData(sprite,
SpriteAction.Class,
SpriteActionClass.Blue);
}
else { // reroute current arrow
const sprite = this.#canvas_arrows.sprite(id);
Expand Down Expand Up @@ -443,5 +469,4 @@ Algs.AStar = class extends Algs.AbstractGridAlg {
ui.player.register(this.#step);
this.#step = null;
}
};
Object.seal(Algs.AStar);
};
5 changes: 1 addition & 4 deletions PlannersJS/scripts/algs/containers.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,6 @@ Algs.AbstractPriorityQueue = class {
this.#length = 0;
}
};
Object.seal(Algs.AbstractPriorityQueue);


Algs.AbstractQueue = class {
Expand All @@ -191,7 +190,6 @@ Algs.AbstractQueue = class {
return this.#nodes.shift();
}
};
Object.seal(Algs.AbstractQueue);

Algs.AbstractStack = class {
#nodes;
Expand All @@ -215,5 +213,4 @@ Algs.AbstractStack = class {
pop() {
return this.#nodes.shift(); // for consistency with how the ui tables are visualized.
}
};
Object.seal(Algs.AbstractStack);
};
3 changes: 1 addition & 2 deletions PlannersJS/scripts/algs/parameters.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,4 @@ Algs.Parameters = class {
if (!Utils.isEnum(this.checkerboard, AlgCheckerboard))
throw new Error(`"checkerboard" must be null or a value from AlgCheckerboard`);
}
};
Object.seal(Algs.Parameters);
};
3 changes: 1 addition & 2 deletions PlannersJS/scripts/dialog/dialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,4 @@ UI.Dialog = class {
* Sends a cancel response to the current form shown by the dialog box.
*/
cancel() { this.#current_form.cancel(); }
}
Object.seal(UI.Dialog);
}
3 changes: 1 addition & 2 deletions PlannersJS/scripts/dialog/form_alg.js
Original file line number Diff line number Diff line change
Expand Up @@ -693,5 +693,4 @@ UI.FormAlg = class extends UI.AbstractForm {

_change_lethal(e) { ui.form_alg._setCustomPreset(e); }
_change_checkerboard(e) { ui.form_alg._setCustomPreset(e); }
};
Object.seal(UI.FormAlg);
};
3 changes: 1 addition & 2 deletions PlannersJS/scripts/dialog/form_new_map.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,5 +128,4 @@ UI.FormNewMap = class extends UI.AbstractForm {
}

cancel() { ui.hideDialog(); }
}
Object.seal(UI.FormNewMap);
}
Loading

0 comments on commit 80509e5

Please sign in to comment.