Skip to content

Instantly share code, notes, and snippets.

@patrickguevara
Last active September 19, 2015 21:33
Show Gist options
  • Save patrickguevara/b14449c13c1605cd5d39 to your computer and use it in GitHub Desktop.
Save patrickguevara/b14449c13c1605cd5d39 to your computer and use it in GitHub Desktop.
Tried my hand at a Sudoku Generator
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
class SudokuController extends Controller
{
/**
* Display a listing of the resource.
*
* @return Response
*/
public function index()
{
$puzzle = $this->generate();
return view('sudoku.index', compact('puzzle', 'incomplete'));
}
private function generate()
{
// The global index of the Puzzle array.
$count = 1;
// Backtrack counters to determine "drastic" backtrack.
$backtrack_count = 0;
$global_backtrack_count = 0;
// Init empty arrays.
$rows = $columns = $squares = [1 => [], 2 => [], 3 => [], 4 => [], 5 => [], 6 => [], 7 => [], 8 => [], 9 => []];
$puzzle = [];
// Grab available values from here instead of randomly generating.
// We will randomize the cell-value inside the while-loop.
$availableValues = [1, 2, 3, 4, 5, 6, 7, 8, 9];
// The loop.
while ($count < 82) {
// If Backtrack gets above 9 (one whole row) backtrack 5 cells and try again.
// Reset Backtrack
if($backtrack_count > 9) {
$count = $this->backtrackSingleCell($count, $rows, $columns, $squares);
$count = $this->backtrackSingleCell($count, $rows, $columns, $squares);
$count = $this->backtrackSingleCell($count, $rows, $columns, $squares);
$count = $this->backtrackSingleCell($count, $rows, $columns, $squares);
$count = $this->backtrackSingleCell($count, $rows, $columns, $squares);
$puzzle = $this->backtrackPuzzle($count, $puzzle);
$backtrack_count = 0;
$global_backtrack_count++;
}
// Determine Column, Row, and Square (based on current $count)
$column = $this->determineColumn($count);
$row = $this->determineRow($count);
$square = $this->determineSquare($column, $row);
// Determine which Values are already present in each Column, Row, and Square.
$takenArray = [];
foreach($columns[$column] as $value) {
$takenArray[] = $value;
}
foreach($rows[$row] as $value) {
$takenArray[] = $value;
}
foreach($squares[$square] as $value) {
$takenArray[] = $value;
}
// Remove duplicates.
$takenValues = array_unique($takenArray);
// Only keep Values that are not taken.
$possibleValues = array_diff($availableValues, $takenValues);
// Randomize Values.
shuffle($possibleValues);
// Take first Value as possible cell-value.
$cell = array_shift($possibleValues);
if(empty($cell)) {
// Need to backtrack single cell.
$count = $this->backtrackSingleCell($count, $rows, $columns, $squares);
$puzzle = $this->backtrackPuzzle($count, $puzzle);
$backtrack_count++;
} else {
// Insert cell into current Column, Row, and Square.
$columns[$column][] = $cell;
$rows[$row][] = $cell;
$squares[$square][] = $cell;
// Insert into Puzzle array, increment Count.
$puzzle[] = $cell;
$count++;
}
}
return $puzzle;
}
/**
* Determines current Column
*
* @param $count
* @return int
*/
private function determineColumn($count)
{
$column = $count % 9;
if ($column == 0) {
$column = 9;
}
return $column;
}
/**
* Determines current Row
*
* @param $count
* @return int
*/
private function determineRow($count)
{
return (int) ceil($count / 9);
}
/**
* Determines current Square.
*
* @param $column
* @param $row
* @return int
*/
private function determineSquare($column, $row)
{
$square = 0;
if ($column >= 1 && $column <= 3 && $row >= 1 && $row <= 3) {
$square = 1;
} elseif ($column >= 4 && $column <= 6 && $row >= 1 && $row <= 3) {
$square = 2;
} elseif ($column >= 7 && $column <= 9 && $row >= 1 && $row <= 3) {
$square = 3;
} elseif ($column >= 1 && $column <= 3 && $row >= 4 && $row <= 6) {
$square = 4;
} elseif ($column >= 4 && $column <= 6 && $row >= 4 && $row <= 6) {
$square = 5;
} elseif ($column >= 7 && $column <= 9 && $row >= 4 && $row <= 6) {
$square = 6;
} elseif ($column >= 1 && $column <= 3 && $row >= 7 && $row <= 9) {
$square = 7;
} elseif ($column >= 4 && $column <= 6 && $row >= 7 && $row <= 9) {
$square = 8;
} elseif ($column >= 7 && $column <= 9 && $row >= 7 && $row <= 9) {
$square = 9;
}
return $square;
}
/**
* Backtrack Puzzle array to given $count index. Removes all elements after given $count.
*
* @param $count
* @param $puzzle
* @return array
*/
private function backtrackPuzzle($count, $puzzle)
{
// Slice puzzle result to remove the current row values.
$puzzle = array_slice($puzzle, 0, $count - 1);
return $puzzle;
}
/**
* Backtrack a single cell. Removes most recent values in Column, Row, and Square arrays.
*
* @param $count
* @param $rows
* @param $columns
* @param $squares
* @return mixed
*/
private function backtrackSingleCell($count, &$rows, &$columns, &$squares)
{
// Reset counter
if($count > 1) {
$count = $count - 1;
}
// Determine Column., Row, and Square
$column = $this->determineColumn($count);
$row = $this->determineRow($count);
$square = $this->determineSquare($column, $row);
// Unset cell in current column.
array_pop($columns[$column]);
end($columns[$column]);
// Unset cell in current row.
array_pop($rows[$row]);
end($rows[$row]);
// Unset cell in current square.
array_pop($squares[$square]);
end($squares[$square]);
return $count;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment