Last active
September 19, 2015 21:33
-
-
Save patrickguevara/b14449c13c1605cd5d39 to your computer and use it in GitHub Desktop.
Tried my hand at a Sudoku Generator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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