×

Welcome to TagMyCode

Please login or create account to add a snippet.
0
0
 
0
Language: Javascript
Posted by: Isaac Dettman
Added: Nov 26, 2016 6:03 PM
Views: 4
Fixed 2D Array
  1. /**
  2.  * An array with a fixed height and width.
  3.  *
  4.  * @param row {number} number of rows, corresponds to the height.
  5.  * @param cols {number} number of columns, corresponds to the width.
  6.  * @param defaultValue the initial value for the array elements
  7.  * @class
  8.  */
  9. var Fixed2DArray = function Fixed2DArray(rows, cols, defaultValue) {
  10.   if(rows <= 0 || cols <= 0){
  11.     throw new Error('fixed-2d-array: Must have more then 0 rows and 0 columns.');
  12.   }
  13.  
  14.   this._width = cols;
  15.   this._height = rows;
  16.   this._grid = [];
  17.  
  18.   for (var i = 0; i < rows; i++) {
  19.     this._grid[i] = [];
  20.     for (var j = 0; j < cols; j++) {
  21.       this._grid[i][j] = defaultValue;
  22.     }
  23.   }
  24. };
  25.  
  26. /**
  27.  * Returns the height of the grid
  28.  */
  29. Fixed2DArray.prototype.getHeight = function getHeight() {
  30.   return this._height;
  31. };
  32.  
  33. /**
  34.  * Returns the width of the grid
  35.  */
  36. Fixed2DArray.prototype.getWidth = function getWidth() {
  37.   return this._width;
  38. };
  39.  
  40. /**
  41.  * Returns the requested row from the grid.
  42.  *
  43.  * @param rowIndex {number} index of the requested row.
  44.  */
  45. Fixed2DArray.prototype.getRow = function getRow(rowIndex) {
  46.   try {
  47.     this.validateCoords(rowIndex,0);
  48.   } catch (err) {
  49.     throw new Error('fixed-2d-array: row index ' + rowIndex + ' is not valid.' +
  50.       ' The size of this array is (' + this._width + '/' + this._height + ')');
  51.   }
  52.  
  53.   return this._grid[rowIndex];
  54. };
  55.  
  56. /**
  57.  * Sets the indicated row with the given array.
  58.  *
  59.  * If the given array is smaller then the current row, `undefined` will fill
  60.  * the given array until it is the same length as the current row.
  61.  *
  62.  * @param rowIndex {number} index of the row where top left is (0,0).
  63.  * @param newRow {array} array of values to replace the indicated row's values.
  64.  */
  65. Fixed2DArray.prototype.setRow = function setRow(rowIndex, newRow) {
  66.   try {
  67.     this.validateCoords(0, rowIndex);
  68.   } catch (err) {
  69.     throw new Error('fixed-2d-array: row index ' + rowIndex + ' is not valid.' +
  70.       ' The size of this array is (' + this.getHeight() + '/' + this.getRow() + ')');
  71.   }
  72.  
  73.   var currentRow = this.getRow(rowIndex);
  74.  
  75.   if (newRow.length > currentRow.length){
  76.     throw new Error('fixed-2d-array: the length of the new row, '+newRow.length+
  77.       ', can not exceed the length of the current row, '+currentRow.length);
  78.   }
  79.  
  80.   currentRow.forEach(function(_,index){
  81.     currentRow[index] = newRow[index];
  82.   });
  83. };
  84.  
  85. /**
  86.  * Adds one or more arrays to the bottom of the Fixed2DArray.
  87.  * Returns the new width of the Fixed2DArray.
  88.  *
  89.  * Only arguments that are arrays will be appended as rows.
  90.  *
  91.  * If the given array is smaller then the height of the Fixed2DArray, `undefined` will fill
  92.  * the given array until it is the same length as the current row.
  93.  */
  94. Fixed2DArray.prototype.pushRow = function pushRow() {
  95.   for (var i = 0; i < arguments.length; i++){
  96.     var newRow = arguments[i];
  97.  
  98.     if(newRow.constructor !== Array){ continue; }
  99.     else if (newRow.length > this.getWidth()){ //no adding rows that are too wide.
  100.       throw new Error('fixed-2d-array: the length of the new row, '+newRow.length+
  101.         ', can not exceed the length of the current rows, '+this.getWidth());
  102.     }
  103.     else{ //expand a smaller row to be the same size as other rows.
  104.       for (var j = newRow.length; j < this.getWidth(); j++){
  105.         newRow[j] = undefined;
  106.       }
  107.     }
  108.     this._grid[this.getHeight()] = newRow;
  109.     this._height += 1;
  110.   }
  111.   return this.getHeight();
  112. };
  113.  
  114. /**
  115.  * Returns the requested column from the grid.
  116.  *
  117.  * @param colIndex {number} index of the requested column
  118.  */
  119. Fixed2DArray.prototype.getColumn = function getColumn(colIndex) {
  120.   try {
  121.     this.validateCoords(0, colIndex);
  122.   } catch (err) {
  123.     throw new Error('fixed-2d-array: column index ' + colIndex + ' is not valid.' +
  124.       ' The size of this array is (' + this.getHeight() + '/' + this.getWidth() + ')');
  125.   }
  126.  
  127.   var returnArray = [];
  128.  
  129.   for (var i = 0; i < this._height; i++) {
  130.     returnArray.push(this._grid[i][colIndex]);
  131.   }
  132.   return returnArray;
  133. };
  134.  
  135. /**
  136.  * Sets the indicated column with the given array.
  137.  *
  138.  * If the given array is smaller then the current column, `undefined` will fill
  139.  * the given array until it is the same length as the current column.
  140.  *
  141.  * @param colIndex {number} index of the column where top left is (0,0).
  142.  * @param newColumn {array} array of values to replace the indicated column's values.
  143.  */
  144. Fixed2DArray.prototype.setColumn = function setColumn(colIndex, newColumn) {
  145.   try {
  146.     this.validateCoords(colIndex, 0);
  147.   } catch (err) {
  148.     throw new Error('fixed-2d-array: column index ' + colIndex + ' is not valid.' +
  149.       ' The size of this array is (' + this.getHeight() + '/' + this.getWid() + ')');
  150.   }
  151.  
  152.   var currentColumn = this.getColumn(colIndex);
  153.  
  154.   if (newColumn.length > currentColumn.length){
  155.     throw new Error('fixed-2d-array: the length of the new column, '+newColumn.length+
  156.       ', can not exceed the length of the current column, '+currentColumn.length);
  157.   }
  158.  
  159.   for (var i = 0; i < currentColumn.length; i++){
  160.     this._grid[i][colIndex] = newColumn[i];
  161.   }
  162. };
  163.  
  164. /**
  165.  * Executes a provided function once per array element.
  166.  *
  167.  * @param fn {function} Function to execute for each element, taking three arguments:
  168.  *
  169.  *  currentValue
  170.  *    The current element being processed in the array.
  171.  *  index
  172.  *    The object index, {x: x, y: y}, of the current element being processed in the 2d array.
  173.  *  array
  174.  *    The Fixed2DArray that forEach is being applied to.
  175.  *
  176.  * @param thisArg Optional. Value to use as this when executing callback.
  177.  */
  178. Fixed2DArray.prototype.forEach = function forEach(fn, thisArg) {
  179.   for (var i = 0; i < this.getHeight(); i++) {
  180.     for (var j = 0; j < this.getWidth(); j++) {
  181.       fn.call(thisArg, this._grid[i][j], { x: i, y: j }, this);
  182.     }
  183.   }
  184. };
  185.  
  186. /**
  187.  * Throws an Error if the given coordinate is invalid.
  188.  *
  189.  * @param row {number} index of the requested row
  190.  * @param col {number} index of the requested column
  191.  */
  192. Fixed2DArray.prototype.validateCoords = function validateCoords(row, col) {
  193.   if (row < 0 || col < 0 || row >= this.getHeight() || col >= this.getWidth()) {
  194.     throw new Error('fixed-2d-array: the coordinate (' + row + '/' + col + ') ' +
  195.       'is not valid. The size of this array is (' + this.getHeight() + '/' + this.getWidth() + ')');
  196.   }
  197. };
  198.  
  199. /**
  200.  * Returns true if the given object has the same height and width as the Fixed2DArray.
  201.  * Returns false if the given object does not have the same height and width as the Fixed2DArray.
  202.  * Throws an error if the given object does not have .getWidth() and .getHeight() methods.
  203.  *
  204.  * @param fixedArray {object with .getWidth() and .getHeight() methods} object to compare size with
  205.  */
  206. Fixed2DArray.prototype.sameSize = function sameSize(fixedArray){
  207.   try{
  208.     return ((fixedArray.getWidth() === this.getWidth()) && (fixedArray.getHeight() === this.getHeight()));
  209.   }catch(err){
  210.     throw new Error('fixed-2d-array: the given object needs to implement a getWidth and getHeight method ' +
  211.                     'in order for Fixed2DArray to compare size.');
  212.   }
  213. };
  214.  
  215. /**
  216.  * Returns the value for the coordinate.
  217.  *
  218.  * @param row {number} index of the requested row
  219.  * @param col {number} index of the requested column
  220.  */
  221. Fixed2DArray.prototype.get = function get(row, col) {
  222.   this.validateCoords(row, col);
  223.   return this._grid[row][col];
  224. };
  225.  
  226. /**
  227.  * Sets the value for the coordinate.
  228.  *
  229.  * @param row {number} index of the requested row
  230.  * @param col {number} index of the requested column
  231.  * @param val new value
  232.  */
  233. Fixed2DArray.prototype.set = function set(row, col, val) {
  234.   this.validateCoords(row, col);
  235.   this._grid[row][col] = val;
  236. };
  237.  
  238. /**
  239.  * Returns all neighbours of the given coordinate.
  240.  *
  241.  * For example:
  242.  * <pre>
  243.  * [ ][ ][ ][ ][ ]
  244.  * [ ][*][*][*][ ]
  245.  * [ ][*][X][*][ ]
  246.  * [ ][*][*][*][ ]
  247.  * [ ][ ][ ][ ][ ]
  248.  * </pre>
  249.  *
  250.  * The given coordinate is marked with an `X`.
  251.  * The function will return an array containing
  252.  * the values for the fields marked with an `*`.
  253.  *
  254.  * @param row {number} index of the requested row
  255.  * @param col {number} index of the requested column
  256.  * @param distance {number} length of the neighbor-square around the given coordinate.
  257.  */
  258. Fixed2DArray.prototype.getNeighbours = function getNeighbours(row, col, distance) {
  259.   this.validateCoords(row, col);
  260.  
  261.   if (typeof distance === 'undefined') { distance = 1; }
  262.   if (distance <= 0) {
  263.     return [];
  264.   }
  265.  
  266.   var returnArray = [];
  267.  
  268.   for (var i = row - distance; i <= row + Number(distance); i++) {
  269.     for (var j = col - distance; j <= col + Number(distance); j++) {
  270.       try {
  271.         if (!(i === row && j === col)) {
  272.           var element = this.get(i, j);
  273.           returnArray.push(element);
  274.         }
  275.       } catch (e) {
  276.         //this is a field at the edge of the grid.
  277.         //ignore
  278.       }
  279.     }
  280.   }
  281.   return returnArray;
  282. };
  283.  
  284. /**
  285.  * Returns true if the given coordinates are neighbors, false otherwise.
  286.  *
  287.  * The distance between each coordinate must be within `distance` or one unit away from
  288.  * each other for the given coordinates to be considered neighbors.
  289.  *
  290.  * For example, distance not set:
  291.  *
  292.  *    0  1  2
  293.  * 0 [A][ ][ ]
  294.  * 1 [ ][B][ ]
  295.  * 2 [ ][ ][ ]
  296.  * 3 [ ][ ][ ]
  297.  *
  298.  * The first given coordinate (0,0) is marked with an `A`, the second (1,1), a `B`.
  299.  * A and B are neighbors.
  300.  *
  301.  * If A and B were instead placed at (0,0) and (2,2) respectively, like this:
  302.  *
  303.  *    0  1  2
  304.  * 0 [A][ ][ ]
  305.  * 1 [ ][ ][ ]
  306.  * 2 [ ][ ][B]
  307.  * 3 [ ][ ][ ]
  308.  *
  309.  * A and B are no longer neighbors.
  310.  *
  311.  * Example, distance = 2:
  312.  *
  313.  *    0  1  2
  314.  * 0 [A][ ][ ]
  315.  * 1 [ ][ ][ ]
  316.  * 2 [ ][ ][B]
  317.  * 3 [ ][ ][ ]
  318.  *
  319.  * A (0,0) and B (2,2) are neighbors.
  320.  *
  321.  * @param row1 {number} first row index.
  322.  * @param col1 {number} first column index.
  323.  * @param row2 {number} second row index.
  324.  * @param col2 {number} second column index.
  325.  * @param distance {number} Optional. Maximum distance for coordinates to be considered neighbors.
  326.  */
  327. Fixed2DArray.prototype.areNeighbours = function areNeighbours(row1, col1, row2, col2, distance) {
  328.   this.validateCoords(row1, col1);
  329.   this.validateCoords(row2, col2);
  330.  
  331.   if (typeof distance === 'undefined') { distance = 1; }
  332.   if (distance <= 0) {
  333.     return false;
  334.   }
  335.  
  336.  
  337.   return (Math.abs(row1 - row2) <= distance) && (Math.abs(col1 - col2) <= distance);
  338. };
  339.  
  340. module.exports = Fixed2DArray;