'use strict';
/**
* @class Grid
* @param {rows} rows - Number of rows in the grid.
* @param {cols} cols - Number of cols in the grid.
*/
function Grid(rows, cols) {
if (arguments.length !== 2) {
throw new Error('You should pass exactly 2 arguments to <span ' +
'class="code">new Grid(rows, cols)</span>');
}
if (typeof rows !== 'number' || !isFinite(rows)) {
throw new TypeError('Invalid value for <span class="code">rows' +
'</span>. Make sure you are passing finite numbers to <span ' +
'class="code">new Grid(rows, cols)</span>.');
}
if (typeof cols !== 'number' || !isFinite(cols)) {
throw new TypeError('Invalid value for <span class="code">cols' +
'</span>. Make sure you are passing finite numbers to <span ' +
'class="code">new Grid(rows, cols)</span>.');
}
rows = Math.max(0, rows);
cols = Math.max(0, cols);
this.grid = new Array(rows);
for (var i = 0; i < rows; i++) {
this.grid[i] = new Array(cols);
}
}
/**
* Initializes a Grid from an array.
* @param {array} arr - Array containing elements to be made into a Grid.
*/
Grid.prototype.initFromArray = function(arr) {
if (arguments.length !== 1) {
throw new Error('You should pass exactly 1 argument to ' +
'<span class="code">initFromArray</span>');
}
if (!Array.isArray(arr)) {
throw new Error('Invalid value passed to <span class="code">' +
'initFromArray</span>. Make sure you are passing an array.');
}
for (var i = 0; i < arr.length; i++) {
for (var j = 0; j < arr[0].length; j++) {
if (this.inBounds(i, j)) {
this.set(i, j, arr[i][j]);
}
}
}
};
/**
* Initializes the contents of the grid with `value`.
* @param {number|string|object|boolean} value - The value to be inserted in all
* positions of the grid.
*/
Grid.prototype.init = function(value) {
if (arguments.length !== 1) {
throw new Error('You should pass exactly 1 argument to ' +
'<span class="code">init</span>');
}
if (typeof value !== 'boolean' && typeof value !== 'number' &&
typeof value !== 'string' && typeof value !== 'object') {
throw new TypeError('Invalid value passed to <span class="code">' +
'init</span>. You passed a value of type ' + typeof value +
'. Make sure you are passing a number, string, object, or ' +
'boolean value.');
}
if (typeof value === 'number' && !isFinite(value)) {
throw new TypeError('Non finite number passed to <span class="code">' +
'init</span>. If you are passing a number, make sure it is a ' +
'finite number.');
}
for (var i = 0; i < this.numRows(); i++) {
for (var j = 0; j < this.numCols(); j++) {
this.grid[i][j] = value;
}
}
};
/**
* Gets the object stored at the requested row and column.
* @param {number} row - The row of the desired object.
* @param {number} col - The col of the desired object.
* @returns {number|string|object|boolean} The value stored in the grid
* at that position.
*/
Grid.prototype.get = function(row, col) {
if (arguments.length !== 2) {
throw new Error('You should pass exactly 2 arguments to <span ' +
'class="code">get(row, col)</span>');
}
if (typeof row !== 'number' || !isFinite(row)) {
throw new TypeError('Invalid value for <span class="code">row' +
'</span>. Make sure you are passing finite numbers to <span ' +
'class="code">get(row, col)</span>.');
}
if (typeof col !== 'number' || !isFinite(col)) {
throw new TypeError('Invalid value for <span class="code">col' +
'</span>. Make sure you are passing finite numbers to <span ' +
'class="code">get(row, col)</span>.');
}
return this.grid[row][col];
};
/**
* Sets an object at the requested row and column.
* @param {number} row - The row of the destination of the object.
* @param {number} col - The column of the destination of the object.
* @param {number|string|object|boolean} value - The value to be stored at
* the specified location in the grid
*/
Grid.prototype.set = function(row, col, value) {
if (arguments.length !== 3) {
throw new Error('You should pass exactly 3 arguments to <span ' +
'class="code">set(row, col, value)</span>');
}
if (typeof row !== 'number' || !isFinite(row)) {
throw new TypeError('Invalid value for <span class="code">row' +
'</span>. You passed a value of type ' + typeof row +
'. Make sure you are passing a number.');
}
if (typeof col !== 'number' || !isFinite(col)) {
throw new TypeError('Invalid value for <span class="code">col' +
'</span>. You passed a value of type ' + typeof col +
'. Make sure you are passing a number.');
}
if (typeof value !== 'boolean' && typeof value !== 'number' &&
typeof value !== 'string' && typeof value !== 'object') {
throw new TypeError('Invalid value passed to <span class="code">' +
'set</span>. You passed a value of type ' + typeof value +
'. Make sure you are passing a number, string, object, or ' +
'boolean value.');
}
if (typeof value === 'number' && !isFinite(value)) {
throw new TypeError('Non finite value passed to <span class="code">' +
'set</span>. If you are passing a number, make sure it is a ' +
'finite number.');
}
this.grid[row][col] = value;
};
/**
* Returns the number of rows in the grid.
* @returns {number} The number of rows in the grid.
*/
Grid.prototype.numRows = function() {
return this.grid.length;
};
/**
* Returns the number of cols in the grid.
* @returns {number} The number of cols in the grid.
*/
Grid.prototype.numCols = function() {
return this.grid[0].length;
};
/**
* Checks whether the given row and col exist in the grid.
* @param {number} row - Row of the position being checked.
* @param {number} col - Col of the position being checked.
* @returns {boolean} Whether or not the given position is in bounds.
*/
Grid.prototype.inBounds = function(row, col) {
if (arguments.length !== 2) {
throw new Error('You should pass exactly 2 arguments to <span ' +
'class="code">inBounds(row, col)</span>');
}
if (typeof row !== 'number' || !isFinite(row)) {
throw new TypeError('Invalid value for <span class="code">row' +
'</span>. Make sure you are passing finite numbers to <span ' +
'class="code">inBounds(row, col)</span>.');
}
if (typeof col !== 'number' || !isFinite(col)) {
throw new TypeError('Invalid value for <span class="code">col' +
'</span>. Make sure you are passing finite numbers to <span ' +
'class="code">inBounds(row, col)</span>.');
}
if (row < 0 || col < 0) {
return false;
}
if (row >= this.numRows() || col >= this.numCols()) {
return false;
}
return true;
};
/**
* Converts a grid to a list.
* For example:
* -------
* A B C D
* E F G H
* I J K L
* -------
* would convert to:
* -------
* [[0, 0, 'A'], [0, 1, 'B'], [0, 2, 'C'], [0, 3, 'D'], [1, 0, 'E']...[2, 3, 'L']]
* @returns {array} List representation of the Grid.
*/
Grid.prototype.toList = function() {
var list = [];
for (var i = 0; i < this.grid.length; i++) {
for (var j = 0; j < this.grid[0].length; j++) {
var value = this.grid[i][j];
if (value && value !== 0) {
list.push([i, j, value]);
}
}
}
return list;
};
/**
* Generates a string representation of the Grid.
* @returns {string} A representatino of a grid of the format
* "A B C <br/>D E F <br/>G H I <br/>"
*/
Grid.prototype.toString = function() {
var result = '';
for (var i = 0; i < this.numRows(); i++) {
for (var j = 0; j < this.numCols(); j++) {
result += this.get(i, j) + ' ';
}
result += '<br/>';
}
return result;
};
module.exports = Grid;