javascriptfunctionoptimizationsudoku

Code review, help improving this code to avoid duplication


I working on the Sudoku puzzle, the following code works but it's easy to see that there is a lot of duplicated code. How can I optimize it? Thanks

Problem: getSection: This function should accept three arguments: a sudoku grid, and an x and y coordinate for one of the puzzle's 3x3 subgrids. The function should return an array with all the numbers in the specified subgrid.

Input example:

var puzzle = [[ 8,9,5,   7,4,2,   1,3,6 ],
             [ 2,7,1,   9,6,3,   4,8,5 ],
             [ 4,6,3,   5,8,1,   7,9,2 ],

             [ 9,3,4,   6,1,7,   2,5,8 ],
             [ 5,1,7,   2,3,8,   9,6,4 ],
             [ 6,8,2,   4,5,9,   3,7,1 ],

             [ 1,5,9,   8,7,4,   6,2,3 ],
             [ 7,4,6,   3,2,5,   8,1,9 ],
             [ 3,2,8,   1,9,6,   5,4,7 ]];

Output:

getSection(puzzle, 0, 0);
// -> [ 8,9,5,2,7,1,4,6,3 ]

Solution:

 function getSection(arr, x, y) {
    var section = [];

    if (y === 0) {
        arr = arr.slice(0, 3);
        if (x === 0) {
            arr.forEach(function (element) {
                section.push(element.slice(0, 3));
            })
        } else if (x === 1) {
            arr.forEach(function (element) {
                section.push(element.slice(3, 6));
            })
        } else {
            arr.forEach(function (element) {
                section.push(element.slice(6, 9));
            })
        }
    }


    if (y === 1) {
        arr = arr.slice(4, 7);
        if (x === 0) {
            arr.forEach(function (element) {
                section.push(element.slice(0, 3));
            })
        } else if (x === 1) {
            arr.forEach(function (element) {
                section.push(element.slice(3, 6));
            })
        } else {
            arr.forEach(function (element) {
                section.push(element.slice(6, 9));
            })
        }
    }

    if (y === 2) {
        arr = arr.slice(6, 9);
        if (x === 0) {
            arr.forEach(function (element) {
                section.push(element.slice(0, 3));
            })
        } else if (x === 1) {
            arr.forEach(function (element) {
                section.push(element.slice(3, 6));
            })
        } else {
            arr.forEach(function (element) {
                section.push(elemet.slice(6, 9));
            })
        }
    }
    var subgrid = section.reduce(function (a, b) {
        return a.concat(b);
    },
        []
    );
    return subgrid;

}

console.log(getSection(puzzle, 0, 0));
// // -> [ 8,9,5,2,7,1,4,6,3 ]

console.log(getSection(puzzle, 1, 0));
// -> [ 7,4,2,9,6,3,5,8,1 ]

Solution

  • I assume your x and y will not exceed your array length. Here's the simplest way to achieve the solution.

    function getSection(arr, x, y) {
      var GRID_SIZE = 3;
      var indexX = x*GRID_SIZE;
      var indexY = y*GRID_SIZE;
      var results = [];
      for(var i = indexY; i< indexY+GRID_SIZE; i++){
        results = results.concat(puzzle[i].slice(indexX, indexX+GRID_SIZE));
      }
      return results;
    }
    
    console.log(getSection(puzzle, 0, 0));
    // // -> [ 8,9,5,2,7,1,4,6,3 ]
    
    console.log(getSection(puzzle, 1, 0));
    // -> [ 7,4,2,9,6,3,5,8,1 ]