I have one core object to my project called SudokuBoard. The only field SudokuBoard has is a 2D array. All prototype functions of SudokuBoard involve the 2D array and need visibility of it at all times.
The problem:
In an algorithm coming up, I NEED to have some way to make copies of the SudokuBoard. It's mandatory functionality. Whenever I try to make a copy, it's 2D array is simply a reference to the old one. I'm not sure why.
I read about how clone is an absolute nightmare in Javascript so I'm a bit worried. I'm a beginner so the last thing I want to do is install Jquery or use some external library to solve this problem. I provided the files below; they should run with no errors.
SudokuBoard.js
/** * Constructs a SudokuBoard object. * Initializes the board with the numbers * provided to the constructor. * @param nums array, must be BOARD_SIZE^2 length. * @constructor */ function SudokuBoard(nums) { // Private Fields: var BOARD_SIZE = 9; // The Sudoku board, represented as a 2D array. var gameboard = []; if (nums.length != BOARD_SIZE * BOARD_SIZE) { document.write("InvalidSizeError"); throw "InvalidSizeError"; } var counter = 0; for (var i = 0; i < BOARD_SIZE; i++) { var row = []; // Each row has a set amount of elements. while (row.length < BOARD_SIZE) { row.push(nums[counter]); counter++; } // Add the row to the board. gameboard.push(row); } SudokuBoard.prototype.getBoard = function() { return gameboard; } } /** * Gets all values within a row of the 2D array. * The Y coordinate works on the typical number * scale, meaning indexes start from 1, not 0. * Y corresponds to the vertical axis. The bottom * left of the board is at 1,1. The bottom right * of the board is at 9,1. * @param y coordinate of the row. * @returns {Array} */ SudokuBoard.prototype.getRow = function(y) { return this.getBoard()[this.getBoard().length - y]; }; /** * Gets all values within a column of the 2D array. * The X coordinate works on the typical number * scale, meaning indexes start from 1, not 0. * X corresponds to the horizontal axis. The bottom * left of the board is at 1,1. The bottom right * of the board is at 9,1. * @param x coordinate of the column. * @returns {Array} */ SudokuBoard.prototype.getColumn = function(x) { var column = []; for (var i = 1; i <= this.getBoard().length; i++) { column.push(this.getSlot(x, i)); } return column; }; /** * Algorithm which finds the correct quadrant of a given * coordinate and gets all the numbers which are contained * inside it. This operation relies on the fact that there * are three quadrants and once you make it so the first * index of quadrant one is considered as (3,3) you can * divide all X and Y values by 3 and yield their quadrant #. * @param x coordinate. * @param y coordinate. * @returns {Array} */ SudokuBoard.prototype.getQuadrant = function(x, y) { // Determine what quadrant this coordinate is in. var horizQuad = Math.floor((x + 2) / 3); // 1 2 or 3 var vertQuad = Math.floor((y + 2) / 3); // 1 2 or 3 var quadrant = []; for (var i = 1; i <= 3; i++) { for (var h = 1; h <= 3; h++) { // Add the number to the array. quadrant.push(this.getSlot((horizQuad - 1) * 3 + i, (vertQuad - 1) * 3 + h)); } } return quadrant; }; /** * Gets a given slot on the board. * The X,Y coordinates work on the typical number * scale, meaning indexes start from 1, not 0. * X corresponds to the horizontal axis while Y * corresponds to the vertical axis. The bottom * left of the board is at 1,1. The bottom right * of the board is at 9,1. * @param x coordinate. * @param y coordinate. */ SudokuBoard.prototype.getSlot = function(x, y) { return this.getBoard()[this.getBoard().length - y][x - 1]; }; /** * Sets a given slot on the board to a value. * The X,Y coordinates work on the typical number * scale, meaning indexes start from 1, not 0. * X corresponds to the horizontal axis while Y * corresponds to the vertical axis. The bottom * left of the board is at 1,1. The bottom right * of the board is at 9,1. * @param x coordinate. * @param y coordinate. * @param value to be placed. */ SudokuBoard.prototype.setSlot = function(x, y, value) { this.getBoard()[this.getBoard().length - y][x - 1] = value; }; SudokuBoard.prototype.clone = function() { var numbers = []; for (var i = 0; i < this.getBoard().length; i++) { for (var h = 0; h < this.getBoard()[i].length; h++) { numbers.push(this.getBoard()[i][h]); } } return new SudokuBoard(numbers); }; /** * ToString() method for SudokuBoard. * @returns {string} */ SudokuBoard.prototype.toString = function() { const border = "+-----+-----+-----+"; const nextline = "<br>"; var temp = border + nextline; for (var i = 0; i < this.getBoard().length; i++) { temp += "|"; for (var h = 0; h < this.getBoard()[i].length; h++) { // Every third character is proceeded by a | //\u00A0 for empty space. temp += ((this.getBoard()[i][h] == "0") ? "-" : this.getBoard()[i][h]) + ((h % 3 == 2) ? "|" : " "); } // Add a new line. temp += nextline; } // Return and add the bottom border. return temp + border; }; Tester.js
var nums = [0, 0, 0, 0, 0, 0, 1, 4, 6, 4, 0, 8, 7, 0, 0, 0, 0, 0, 0, 6, 0, 0, 5, 0, 8, 9, 0, 0, 0, 0, 1, 0, 0, 0, 0, 3, 0, 8, 0, 0, 7, 4, 0, 0, 0, 7, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 1, 8, 0, 9, 2, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 8, 0, 3, 0, 1, 7, 0, 0, 0]; var myBoard = new SudokuBoard(nums); println("ORIGINAL:"); println(myBoard); var clone = myBoard.clone(); println("CLONING:"); println(clone); myBoard.setSlot(1, 1, 3); println("CHANGED ORIGINAL:"); println(myBoard); println("CLONE:"); println(clone); /** * Used for debugging. * @param line */ function println(line) { document.write(line + "<br>"); } Runner.html
<!DOCTYPE html> <!-- Project: SudokuSolver Name: Kevin Date: 2/12/2016 --> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <font face="monospace"><font size="12"> <!--Load from JavaScript file. --> <script type="text/javascript" src="SudokuBoard.js"></script> <script type="text/javascript" src="Tester.js"></script> </font></font> </head> <body> </body> </html>