algs4js
Version:
Basic algorithms and data structures implemented with es6
195 lines (167 loc) • 6.65 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/**
Class to find shortest path
This class uses a Breadth First Search (BFS) algorithm to find the shortest path.
@class
*/
var KnightShortestPath = function () {
/**
@constructor
*/
function KnightShortestPath(boardSize) {
_classCallCheck(this, KnightShortestPath);
// The number of squares per edge of the board square
this.boardSize = boardSize;
// The shortest path predecessor array
this.predArr = [];
// Board square markers so the engine knows if it already visited a square
this.board = [];
for (var row = 0; row < this.boardSize; row++) {
this.board[row] = [];
for (var col = 0; col < this.boardSize; col++) {
this.board[row][col] = -1;
}
}
}
/**
This function will use BFS to find the shortest path between
two squares. The results are an array of move predecessor
indices. The predecessor array is a MoveEngine property.
@function
@param {number} startIdx - The index of the starting square
@param {number} endIdx - The index of the ending square
@return {number} The number of moves in shortest path
*/
_createClass(KnightShortestPath, [{
key: "getShortestPath",
value: function getShortestPath(startIdx, endIdx) {
var _this = this;
// Boiler plate operations
this.startIdx = startIdx;
this.endIdx = endIdx;
var startPos = this.getRowColFromIdx(startIdx);
var endPos = this.getRowColFromIdx(endIdx);
// The DFS search queue
var queue = [];
// Initialize the starting square
this.board[startPos.row][startPos.col] = 0;
this.predArr[startIdx] = null;
// Start search
queue.push(startPos);
var _loop = function _loop() {
// Remove element from head of queue
var pos = queue.shift();
// Check if reached the end position
if (pos.row === endPos.row && pos.col === endPos.col) {
return {
v: _this.board[endPos.row][endPos.col]
};
}
// Get all neighboring moves
var neighbors = _this.getValidNeighbors(pos.row, pos.col);
neighbors.forEach(function (neighbor) {
_this.board[neighbor.row][neighbor.col] = _this.board[pos.row][pos.col] + 1;
_this.addPredecessor(neighbor, pos);
queue.push(neighbor);
});
};
while (queue.length > 0) {
var _ret = _loop();
if ((typeof _ret === "undefined" ? "undefined" : _typeof(_ret)) === "object") return _ret.v;
}
return -1;
}
/**
Function to convert from square index to row, column position
@function
@param {number} idx - The index of the square
*/
}, {
key: "getRowColFromIdx",
value: function getRowColFromIdx(idx) {
var row = Math.floor(idx / this.boardSize);
var col = idx % this.boardSize;
return {
row: row,
col: col
};
}
/**
Function to add the predecessor square index of a neighbor square
to the predecessor array.
@function
@param (Object) neighbor - The neighbor row, column position
@param {Object} predecessor- the predecessor row, column position
*/
}, {
key: "addPredecessor",
value: function addPredecessor(neighbor, predecessor) {
var neighborIdx = this.boardSize * neighbor.row + neighbor.col;
var predecessorIdx = this.boardSize * predecessor.row + predecessor.col;
this.predArr[neighborIdx] = predecessorIdx;
}
/**
Function to add a nieghboring move to and array of moves
@function
@param (Array) arr - The array of neighboring moves
@param {number} row - the neighbor row position
@param {number} col - the neighbor column position
*/
}, {
key: "addValidNeighbor",
value: function addValidNeighbor(arr, row, col) {
if (row >= 0 && row < this.boardSize && col >= 0 && col < this.boardSize && this.board[row][col] === -1) {
arr.push({
row: row,
col: col
});
}
}
/**
Function to get all nieghboring moves from a square.
It will validate and reject any squares already visited
@function
@param {number} row - the position row position
@param {number} col - the position column position
@return (Array) arr - The array of neighboring moves
*/
}, {
key: "getValidNeighbors",
value: function getValidNeighbors(row, col) {
var arr = [];
this.addValidNeighbor(arr, row + 2, col + 1);
this.addValidNeighbor(arr, row + 1, col + 2);
this.addValidNeighbor(arr, row - 1, col + 2);
this.addValidNeighbor(arr, row - 2, col + 1);
this.addValidNeighbor(arr, row - 2, col - 1);
this.addValidNeighbor(arr, row - 1, col - 2);
this.addValidNeighbor(arr, row + 1, col - 2);
this.addValidNeighbor(arr, row + 2, col - 1);
return arr;
}
/**
Function that gets the array of indices visited during
the shortest path moves.
@return {Array} - The array of idices visited
*/
}, {
key: "getMoveStack",
value: function getMoveStack() {
var moveStack = [this.endIdx];
for (var idx = this.endIdx; idx !== this.startIdx; idx = this.predArr[idx]) {
if (this.predArr[idx] !== this.startIdx) {
moveStack.unshift(this.predArr[idx]);
}
}
return moveStack;
}
}]);
return KnightShortestPath;
}();
exports.default = KnightShortestPath;