MSV FM

dot.antimicrobial@66.96.161.157: ~ $
Path : /hermes/bosweb/b1536/thecopelandscom.ipage.com/games/sudoku/
File Upload :
Current < : /hermes/bosweb/b1536/thecopelandscom.ipage.com/games/sudoku/script.js

//Global Variables
enteredSudokuVals = [];                                         //Array to track User Entered Data

blockGroupElements = [];
for (gBlkGrpCnt = 1; gBlkGrpCnt <= 9; gBlkGrpCnt++) {
  blockGroupElements[gBlkGrpCnt - 1] = [];
}

possibleValues = [];
for (r = 1; r <= 9; r++) {
  possibleValues[r - 1] = [];
  for (c = 1; c <= 9; c++) {
    possibleValues[r - 1][c - 1] = [];
  }
}

openFields = 0;



function dispMsg(msgTxt, msgType) {
  if (msgType == "ERROR") {
    document.getElementById("msgDtls").className = "msgDtlsErr";
  } else {
    document.getElementById("msgDtls").className = "";
  }

  document.getElementById("msgDtls").innerHTML=msgTxt;
}



function buildSudoku() {
  sudoku = "";

  sudoku = sudoku + "<table id=\"sudoku\">";
  for (r=1; r<=9; r++) {
    sudoku = sudoku + "<tr>";
    for (c=1; c<=9; c++) {
      sudokuCellClass = "sudokuCell";
      if(c % 3 == 0 && c != 9) {
        sudokuCellClass = sudokuCellClass + " sudokuCellRight";
      }
      if(r % 3 == 0 && r != 9) {
        sudokuCellClass = sudokuCellClass + " sudokuCellBottom";
      }
      
      sudoku = sudoku + "<td class=\"" + sudokuCellClass + "\"><input id=\"R" + r + "C" + c + "\" class=\"sudokuInput\" type=\"text\"></td>";
    }
    sudoku = sudoku + "</tr>";
  }
  sudoku = sudoku + "</table>";

  document.getElementById("puzzle").innerHTML = sudoku;
}



function assignBlockGroups() {
  const blockGroupings = [1.1, 1.2, 1.3, 2.1, 2.2, 2.3, 3.1, 3.2, 3.3];
  
  for (r = 1; r <= 9; r++) {
    rwBlockVal = Number(Math.trunc((r - 1) / 3) + 1);
    for (c = 1; c <= 9; c++) {
      colBlockVal = Number((Math.trunc((c - 1) / 3) + 1) / 10);
      grpCalcVal = Number(rwBlockVal + colBlockVal);

      blockGrp = blockGroupings.indexOf(grpCalcVal) + 1;

      blockGroupElements[blockGrp - 1].push(document.getElementById("R" + r + "C" + c));
    }
  }
}



function identifyBlockGroups(r, c) {
  const blockGroupings = [1.1, 1.2, 1.3, 2.1, 2.2, 2.3, 3.1, 3.2, 3.3];
  
  rwBlockVal = Number(Math.trunc((r - 1) / 3) + 1);
  colBlockVal = Number((Math.trunc((c - 1) / 3) + 1) / 10);
  grpCalcVal = Number(rwBlockVal + colBlockVal);
  blockGrp = blockGroupings.indexOf(grpCalcVal) + 1;

  return blockGrp;
}



function initSudoku() {
  enteredSudokuVals = [];

  //Init blank sudoku 2x array
  for (i = 1; i <= 9; i++) {
    let blankRow = new Array(9);
    enteredSudokuVals.push(blankRow);
  }

  dispMsg("Enter initial puzzle values to solve", "NORMAL");
}



function clearSudoku() {
  //Clear Sudoku 2x array variable
  initSudoku();

  //Clear Sudoku Puzzle Display
  for (r = 1; r <= 9; r++) {
    for (c = 1; c <= 9; c++) {
      document.getElementById("R" + r + "C" + c).value="";
      document.getElementById("R" + r + "C" + c).className = "sudokuInput";
    }
  }
}



function countOpenFields() {
  let r = 0;
  let c = 0;

  openFields = 0;
  for (r = 1; r <= 9; r++) {
    for (c = 1; c <= 9; c++) {
      if (document.getElementById("R" + r + "C" + c).value == "") {
         openFields++;
      }
    }
  }
}



function solveSudoku() {
  if (validateSudoku("INIT") == 0) {
    countOpenFields();
    calculateSudoku();
  }
}



function validateSudoku(valType) {
  let minEnteredCnt = 18;
  let enteredValCnt = 0;
  let r = 0;
  let c = 0;

  if (valType == "INIT") {
    //Track Initial User Entered Values
    for (r = 1; r <= 9; r++) {
      for (c = 1; c <= 9; c++) {
        objID = "R" + r + "C" + c;

        enteredSudokuVals[r - 1][c - 1] = document.getElementById(objID).value;
        document.getElementById(objID).className = "sudokuInput";

        //Count Number of Entered Data Points
        if(enteredSudokuVals[r - 1][c - 1] != "") {
          enteredValCnt ++;
        }
      }
    }

    //Validate Enough Values Entered
    if (enteredValCnt < minEnteredCnt) {
      dispMsg("Please enter at least " + minEnteredCnt + " values.", "ERROR");
      return -1;
    }
  }

  //Validate Duplicates w/i Row
  for (r = 1; r <= 9; r++) {
    if (!checkDupes(enteredSudokuVals[r-1])) {
      dispMsg("Duplicate values within Row " + r + ".", "ERROR");

      for(errStyleCnt=1; errStyleCnt<=9; errStyleCnt++){
        document.getElementById("R" + r + "C" + errStyleCnt).className = "sudokuInputErr";
      }
      return -1;
    }
  }

  //Validate Duplicates w/i Column
  for (c = 1; c <= 9; c++) {
    colValues = [];

    for (r = 1; r <= 9; r++) {
      colValues.push(enteredSudokuVals[r-1][c-1]);
    }

    if (!checkDupes(colValues)) {
      dispMsg("Duplicate values within Column " + c + ".", "ERROR");

      for(errStyleCnt=1; errStyleCnt<=9; errStyleCnt++){
        document.getElementById("R" + errStyleCnt + "C" + c).className = "sudokuInputErr";
      }
      return -1;
    }
  }

  //Validate Duplicates w/i Blocks
  for (blckGrpCnt = 1; blckGrpCnt <= blockGroupElements.length; blckGrpCnt++) {
    aryBlock = [];

    for (blkGrpElmntCnt = 1; blkGrpElmntCnt <= blockGroupElements[blckGrpCnt - 1].length; blkGrpElmntCnt++) {
      aryBlock.push(blockGroupElements[blckGrpCnt - 1][blkGrpElmntCnt - 1].value);
    }

    if (!checkDupes(aryBlock)) {
      dispMsg("Duplicate values within Block " + blckGrpCnt + ".", "ERROR");
      for(errStyleCnt = 1; errStyleCnt <= blockGroupElements[blckGrpCnt - 1].length; errStyleCnt++) {
        blockGroupElements[blckGrpCnt - 1][errStyleCnt - 1].className = "sudokuInputErr";
      }
      return -1;
    }
  }

  return 0;
}



function checkDupes(inputArray) {
  nonEmptyVals = [];

  nonEmptyVals = inputArray.filter((str) => str !== '');

  if (nonEmptyVals.length > 1) {
    nonEmptyVals.sort();
    for (dupeCnt = 1; dupeCnt <= nonEmptyVals.length - 1; dupeCnt++) {
      if (nonEmptyVals[dupeCnt - 1] == nonEmptyVals[dupeCnt]) {
        return false;
      }
    }
  }

  return true;
}



function calculateSudoku() {
  //Simple Fill Missing Numbers
  blnSudokuUpdated = true;
  blnSudokuSolved = false;

  while (!blnSudokuSolved) {
    // alert("Remaining Fields 1: " + openFields);
    while (blnSudokuUpdated) {
      blnSudokuUpdated = calcSimpleMissing();
      // alert("Remaining Fields 2: " + openFields);
    }

    if (!buildPossibleValues()) {
      blnSudokuSolved = true;
    } else {
      blnSudokuUpdated = true;
    }
    // alert("Remaining Fields 3: " + openFields);
  }

  if (validateSudoku("CHECK") == 0) {
    alert("SOLVED");
  }
}



function calcSimpleMissing() {
  let blnSudokuUpdated = false;
  let n = 0;
  let b = 0;
  let f = 0;
  let r = 0;
  let c = 0;

  for (n = 1; n <= 9; n++) {                                    //Number Loop
    for (b = 1; b <= blockGroupElements.length; b++) {          //Block Loop
      let blnFldMatchVal = false;
      let possibleFields = [];

      //Validate Block Open for Number
      blnFldMatchVal = inBlk(0, 0, n, b);

      //Loop Through Each Block Field - Validate Column & Row
      if(!blnFldMatchVal) {
        for (f = 1; f <= blockGroupElements[b-1].length; f++) {    //Field Loop
          let blnRowMatchVal = false;
          let blnColMatchVal = false;

          //Field Not Populated?
          if (blockGroupElements[b-1][f-1].value == "") {
            //Validate Row Values Match
            r = String(blockGroupElements[b-1][f-1].id).substring(1,2);
            blnRowMatchVal = inRow(r, n);

            //Validate Column Values Match
            if (!blnRowMatchVal) {
              c = String(blockGroupElements[b-1][f-1].id).substring(3,4);
              blnColMatchVal = inCol(c, n);
            }

            if (!blnFldMatchVal && !blnRowMatchVal && !blnColMatchVal) {
              possibleFields.push(f);
            }
          }
        }

        if (possibleFields.length == 1) {
          openFields--;
          blockGroupElements[b-1][possibleFields[0]-1].value = n;
          blockGroupElements[b-1][possibleFields[0]-1].className = "sudokuInputSolved";
          blnSudokuUpdated = true;
        }
      }
    }
  }
  return blnSudokuUpdated;
}



function buildPossibleValues() {
  let blnSudokuUpdated = false;
  let r = 0;
  let c = 0;
  let n = 0;

  for (r = 1; r <= 9; r++) {
    for (c = 1; c <= 9; c++) {
      possibleValues[r-1][c-1] = [];
      if (document.getElementById("R" + r + "C" + c).value == "") {
        for (n = 1; n <= 9; n++) {
          let blnRowMatch = false;
          let blnColMatch = false;
          let blnBlkMatch = false;

          //In Row?
          blnRowMatch = inRow(r, n);

          if (!blnRowMatch) {
            //In Col?
            blnColMatch = inCol(c, n);

            if (!blnColMatch) {
              //In Block?
              blnBlkMatch = inBlk(r, c, n);
            }
          }

          if (!blnRowMatch && !blnColMatch && !blnBlkMatch) {
            possibleValues[r-1][c-1].push(n);
          }
        }

        if (possibleValues[r-1][c-1].length == 1) {
          openFields--;
          document.getElementById("R" + r + "C" + c).value = possibleValues[r-1][c-1][0];
          document.getElementById("R" + r + "C" + c).className = "sudokuInputSolved";
          blnSudokuUpdated = true;
        }
      }
    }
  }

  return blnSudokuUpdated;
}



function inRow(r, n) {
  blnMatch = false;
  let c = 0;

  for (c = 1; c <= 9; c++) {
    if (document.getElementById("R" + r + "C" + c).value == n) {
      return true;
    }
  }

  return blnMatch;
}



function inCol(c, n) {
  blnMatch = false;
  let r = 0;

  for (r = 1; r <= 9; r++) {
    if (document.getElementById("R" + r + "C" + c).value == n) {
      return true;
    }
  }

  return blnMatch;
}



function inBlk(r, c, n, bg = 0) {
  blnMatch = false;
  let b = 0;

  if (bg == 0){
    blockGrp = identifyBlockGroups(r, c);
  } else {
    blockGrp = bg;
  }
  
  for (b = 1; b <= 9; b++) {
    if (blockGroupElements[blockGrp-1][b-1].value == n) {
      return true;
    }
  }

  return blnMatch;
}



function hoverPossibleValues() {
  // alert(this.id);

  let r = String(this.id).substring(1,2);
  let c = String(this.id).substring(3,4);

  // alert("R:" + r + " C:" + c);
  
  dispMsg(possibleValues[r-1][c-1], "INFO");
}



function testSudoku() {
  let r = 0;
  let c = 0;

  // let testValues = [,2,,8,,,,,1,9,,,2,,3,6,,,6,,,,9,1,,,5,7,6,,,,,,,,5,,8,4,,7,1,,,,,,5,8,,,,7,,,,,,9,,5,,3,,,,,,,,2,,5,,,,,8,1,9];
  // let testValues = [7,,,,4,6,,,,6,,,1,,8,,,5,,,2,5,,3,,9,,,,,,1,,,2,9,,,4,,,,3,,,8,,,7,3,4,,,,1,,,4,,,,,,,,6,3,,,,8,,,,5,2,,,,1,3];
  // let testValues = [,6,,,,,8,,9,,,4,,,,,6,,8,,,,,,,5,,4,,2,,6,8,,,,9,5,,,,2,,,8,6,,,1,9,7,,,,,,3,,,5,,,7,,8,,7,3,,,,,,4,,2,1,,,,,];
  let testValues = [,,1,,2,,,8,6,,,,,3,6,,1,,,,,1,,,,7,2,9,,,,,2,,,,,8,,,5,,,3,,,,,6,,,,,7,4,3,,,,1,,,,,7,,9,6,,,,,6,1,,,7,,5,,,];

  testValues.reverse();

  for (r = 1; r <= 9; r++) {
    for (c = 1; c <= 9; c++) {
      val = testValues.pop();
      if (typeof val != "undefined") {
        document.getElementById("R" + r + "C" + c).value = val;
      }
    }
  }
}