'How to reset randomness in a function in a sudoku generator in javascript

I am building a sudoku generator which has randomness in it. In my code, there is a function that generates that sudoku. The problem is that I can't get the two sudoku's to be different

I tried running that function twice, but as expected the two generated sudoku's are exactly the same. I expect that when I copy the entire function and paste it underneath, the sudoku's will be different, but then there would be way too much code.

This is my sudoku generating function, I included some comments for you to better understand what the code does:

let sudoku = [
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
      ];

  let sudoku2 = JSON.parse(JSON.stringify(sudoku));

  let changesMade = false;
  let fields = [];
  let counter = 0;
  let sudoku3;

  window.onload = function () {
    generateRandomSudoku(25);
    print_sudoku(sudoku3, "table1");
    print_sudoku(sudoku, "table2");
    // this is the code I used to generate the function twice
    generateRandomSudoku(25);
    print_sudoku(sudoku3, "table3");
    print_sudoku(sudoku, "table4");
  };

  // solves a sudoku
  function solveSudoku() {
    fill_possible_fields();

    changesMade = false;
    counter = 0;

    while (!sudoku_complete()) {
      counter++;
      test_rows_and_cols();
      test_blocks();
      test_possible_fields();
      if (!changesMade) {
        break;
      } else {
        changesMade = false;
      }
      if (counter === 100) {
        break;
      }
    }
  }

  // returns true if there are two equal numbers in the same row
  function duplicateNumberInRow(s, fieldY) {
    numbers = new Array();
    for (var i = 0; i < 9; i++) {
      if (s[i][fieldY] !== 0) {
        if (numbers.includes(s[i][fieldY])) {
          return true;
        } else {
          numbers.push(s[i][fieldY]);
        }
      }
    }
    return false;
  }

  // returns true if there are two equal numbers in the same col
  function duplicateNumberInCol(s, fieldX) {
    numbers = new Array();
    for (var i = 0; i < 9; i++) {
      if (s[fieldX][i] !== 0) {
        if (numbers.includes(s[fieldX][i])) {
          return true;
        } else {
          numbers.push(s[fieldX][i]);
        }
      }
    }
    return false;
  }

  // returns true if there are two equal numbers in the same box
  function duplicateNumberInBox(s, fieldX, fieldY) {
    boxX = Math.floor(fieldX / 3);
    boxY = Math.floor(fieldY / 3);
    numbers = new Array();
    for (var i = 0; i < 3; i++) {
      for (var j = 0; j < 3; j++) {
        x = i + 3 * boxX;
        y = j + 3 * boxY;
        if (s[x][y] !== 0) {
          if (numbers.includes(s[x][y])) {
            return true;
          } else {
            numbers.push(s[x][y]);
          }
        }
      }
    }
    return false;
  }

  // returns true if there are two equal numbers in the same row, col or box
  function duplicateNumberExists(s, fieldX, fieldY) {
    if (duplicateNumberInRow(s, fieldY)) {
      return true;
    }
    if (duplicateNumberInCol(s, fieldX)) {
      return true;
    }
    if (duplicateNumberInBox(s, fieldX, fieldY)) {
      return true;
    }
    return false;
  }

  // generates a random sudoku with a given amount of numbers in it
  function generateRandomSudoku(numbers) {
    while (!sudoku_complete() || sudoku_invalid(sudoku)) {
      // new empty sudoku
      sudoku3 = [
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
      ];
      sudoku = JSON.parse(JSON.stringify(sudoku3));

      // how many numbers are entered already?
      let numbersDone = 0;

      while (numbersDone < numbers) {
        let fieldX = Math.floor(Math.random() * 9);
        let fieldY = Math.floor(Math.random() * 9);
        let number = Math.floor(Math.random() * 9) + 1;
        //alert("" + fieldX + " " + fieldY + " " + number);

        if (sudoku3[fieldX][fieldY] === 0) {
          sudoku3[fieldX][fieldY] = number;
          if (duplicateNumberExists(sudoku3, fieldX, fieldY)) {
            sudoku3[fieldX][fieldY] = 0;
            continue;
          } else {
            numbersDone++;
          }
          //alert("" + numbersDone);
        }
      }
      sudoku = JSON.parse(JSON.stringify(sudoku3));
      solveSudoku();
    }
  }

  // fills the possible numbers for the fields
  function fill_possible_fields() {
    for (var i = 0; i < 9; i++) {
      fields[i] = [];
    }
    for (var i = 0; i < 9; i++) {
      for (var j = 0; j < 9; j++) {
        fields[i][j] = [];
      }
    }

    for (var i = 0; i < 9; i++) {
      for (var j = 0; j < 9; j++) {
        for (var k = 0; k < 9; k++) {
          fields[i][j][k] = k + 1;
        }
      }
    }
  }

  // show the sudoku as a table

  function print_sudoku(s, position) {
    var tbl = document.createElement("table");
    // tbl.style.width = "500px"
    // tbl.style.backgroundColor = "blue"
    var tbdy = document.createElement("tbody");
    tbl.appendChild(tbdy);
    for (var i = 0; i < 9; i++) {
      var tr = document.createElement("tr");
      tbdy.appendChild(tr);
      for (var j = 0; j < 9; j++) {
        var td = document.createElement("td");
        td.appendChild(document.createTextNode("" + s[i][j]));
        if (s[i][j] === 0) {
          td.style.backgroundColor = "white";
          td.style.color = "white";
        }
        tr.appendChild(td);
      }
    }
    document.getElementById(position).appendChild(tbl);
    document.getElementById("table1").style.padding = "0px";
  }

  // tests the possible 9 numbers for a field, if only one is possible then it's entered to the field
  function test_possible_fields() {
    for (var i = 0; i < 9; i++) {
      for (var j = 0; j < 9; j++) {
        if (sudoku[i][j] === 0) {
          var numbers = 0;
          var number = 0;
          for (var k = 0; k < 9; k++) {
            if (fields[i][j][k] !== 0) {
              number = k + 1;
              numbers++;
            }
          }
          if (numbers === 1) {
            sudoku[i][j] = number;
            changesMade = true;
          }
        }
      }
    }
  }

  // tests the rows and cols
  function test_rows_and_cols() {
    for (var i = 0; i < 9; i++) {
      for (var j = 0; j < 9; j++) {
        if (sudoku[i][j] !== 0) {
          var number = sudoku[i][j];
          for (var k = 0; k < 9; k++) {
            if (sudoku[i][k] === 0) {
              if (fields[i][k][number - 1] !== 0) {
                changesMade = true;
              }
              fields[i][k][number - 1] = 0;
            }
          }
          var number = sudoku[i][j];
          for (var k = 0; k < 9; k++) {
            if (sudoku[k][j] === 0) {
              if (fields[k][j][number - 1] !== 0) {
                changesMade = true;
              }
              fields[k][j][number - 1] = 0;
            }
          }
        }
      }
    }
  }

  // tests the blocks
  function test_blocks() {
    for (var k = 0; k < 3; k++) {
      for (var l = 0; l < 3; l++) {
        for (var i = 0 + k * 3; i < 3 + k * 3; i++) {
          for (var j = 0 + l * 3; j < 3 + l * 3; j++) {
            if (sudoku[i][j] !== 0) {
              var number = sudoku[i][j];
              for (var a = 0 + k * 3; a < 3 + k * 3; a++) {
                for (var b = 0 + l * 3; b < 3 + l * 3; b++) {
                  if (sudoku[a][b] === 0) {
                    if (fields[a][b][number - 1] !== 0) {
                      changesMade = true;
                    }
                    fields[a][b][number - 1] = 0;
                  }
                }
              }
            }
          }
        }
      }
    }
  }

  // tests if a sudoku is complete and returns eiter true or false
  function sudoku_complete() {
    for (var i = 0; i < 9; i++) {
      for (var j = 0; j < 9; j++) {
        if (sudoku[i][j] === 0) {
          return false;
        }
      }
    }
    return true;
  }

  //Tests if there are any duplicate numbers in a sudoku
  function sudoku_invalid(s) {
    for (var i = 0; i < 9; i++) {
      for (var j = 0; j < 9; j++) {
        if (duplicateNumberExists(s, i, j)) {
          return true;
        }
      }
    }
    return false;
  }

And this is the html code, which does not contain tables because it is all generated in javascript:

<div id="example-table" style="width: min-content">
    <div id="table1"></div>
  </div>
  <div id="example-table2" style="width: min-content">
    <div id="table2"></div>
  </div>
  <div id="example-table" style="width: min-content">
    <div id="table3"></div>
  </div>
  <div id="example-table2" style="width: min-content">
    <div id="table4"></div>
  </div>
  <br />
  <button id="dl-png">Download as png</button>


Solution 1:[1]

In your function window.onload = function () I added resetSudoku() after you print the first one.

that looks like this:

  function resetSudoku(){
  sudoku = [
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
      ];
  }

It resets the sudoku. I suspect the error is here

function generateRandomSudoku(numbers) {
    while (!sudoku_complete() || sudoku_invalid(sudoku)) {}

you check if the sudoku is not completed but if you do not reset sudoku, the sudoku is already completed.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Bjop