3v4l.org

run code in 300+ PHP versions simultaneously
<?php class SudokuGenerator extends SudokuSolver { public $EleArray = NULL; const METRIC_EASY = 27; const METRIC_MEDIUM = 22; const METRIC_HARD = 17; public function __construct() { $this->EleArray(); parent::__construct(); } /* Creates an array of possible (row, col) combinations. So that uniquely a random elemnt can be selected */ public function EleArray() { $EleArray = array(); foreach(range(0, 8) as $i ) foreach(range(0, 8) as $j ) $EleArray[] = array($i, $j); $this->EleArray = $EleArray; } public function FillRandomValue() { if( $this->EleArray === NULL ) throw new Exception('$this->EleArray() must be called before FillRandomValue', 1); $ele = array_rand( $this->EleArray ); $randCol = $this->EleArray[$ele][0]; $randRow = $this->EleArray[$ele][1]; unset($this->EleArray[$ele]); for ( $i = 1; $i <= 9; $i++ ) { if( $this->checkValid($randRow, $randCol, $i) ) { $this->_oSudoku[$randRow][$randCol] = $i; break; } } } public function GenerateSudoku( $difficulty ) { $this->EleArray(); for( $i = 0; $i < $difficulty; $i++ ) $this->FillRandomValue(); do { $this->FillRandomValue(); $this->Solve(); } while( $this->HasUnique() === self::NOT_UNIQUE ); } } class SudokuSolver { protected $_iSudoku = array(); protected $_oSudoku = array(); protected $_stack; protected $_blocks; protected $_oSudoku90; protected $_compare; const NOT_SOLVABLE = 10; const NOT_UNIQUE = 11; public function __construct( $sudoku = NULL, $stack = NULL, $seedVal = 0 ) { $this->seedVal = $seedVal; if ( $stack === NULL ) $this->_stack = new Stack(); else $this->_stack = $stack; if ( $sudoku === NULL ) $sudoku = str_repeat( "0", 81 ); /** Creates an sudoku array from the supplied string or empty string */ if ( is_string( $sudoku ) ): $sudoku = str_split( $sudoku, 9 ); array_walk( $sudoku, function( &$arg ) { $arg = str_split( $arg ); } ); endif; $this->_iSudoku = $this->_oSudoku = $sudoku; $this->_compare = range(1, 9); $this->_constuctBlock(); } // Constructs block of 3 x 3 array, and row wise block that can later be used for direct // finding of possibles instead of looping protected function _constuctBlock() { for ( $x = 0; $x < 9; $x++ ) { $this->_oSudoku90[$x] = array(); for ( $y = 0; $y < 9; $y++ ) { $this->_oSudoku90[$x][$y] = &$this->_oSudoku[$y][$x]; } } // create '_blocks' for ( $blockX = 0; $blockX < 3; $blockX++ ) { $this->_blocks[$blockX] = array(); for ( $blockY = 0; $blockY < 3; $blockY++ ) { $this->_blocks[$blockX][$blockY] = array(); $gridX = $blockX * 3; for ( $cellX = 0; $cellX < 3; $cellX++ ) { $gridY = $blockY * 3; for ( $cellY = 0; $cellY <3; $cellY++ ) { $this->_blocks[$blockX][$blockY][] = &$this->_oSudoku[$gridX][$gridY++]; } $gridX++; } } } } /** The following functions find the possibles for column, row and 3 x 3 block */ public function missingColumn($m) { return array_diff($this->_compare, $this->_oSudoku[$m]); } public function missingRow($n) { return array_diff($this->_compare, $this->_oSudoku90[$n]); } public function missingBlock($m,$n) { return array_diff($this->_compare, $this->_blocks[$m][$n]); } /* An intersect of all the possibles finds the possibles obeying rules of sudoku */ public function possibles( $m, $n ) { return array_intersect( $this->missingBlock((int)$m / 3, (int)$n / 3), $this->missingColumn($m), $this->missingRow($n) ); } public function checkValid( $m, $n, $val ) { return in_array( $val, array_intersect( $this->missingBlock((int)$m / 3, (int)$n / 3), $this->missingColumn($m), $this->missingRow($n) )); } /** * Function checks if the sudoku has a unique solution */ public function HasUnique() { while ( !$this->_stack->isEmpty() ) { $stack = new Stack(); $oldSudoku = &$this->_oSudoku; list( $m, $n ) = $this->_stack->pop(); $val = $oldSudoku[$m][$n]; $oldSudoku[$m][$n] = 0; $sudoku = new SudokuSolver( $oldSudoku, $stack, $val ); if ( $sudoku->Solve() !== self::NOT_SOLVABLE ) return self::NOT_UNIQUE; } return TRUE; } public function Solve() { $m = $n = 0; fx: while ( $m !== 9 ): //Loop till 9 x 9 sudoku processed if ( ( (int)( $cell = &$this->_oSudoku[$m][$n] ) === 0 ) ) { foreach ( $this->possibles($m, $n) as $val) { $this->seedVal = 0; //If cell's value was less than value of $val means insertion //must be done otherwise it means it has returned from backtracking if( $cell < $val ) $cell = $val; else continue; $this->_stack->push( $m, $n ); //Record the insertion if ( $n === 8 ): $m += 1; $n = 0; else: $n += 1; endif; goto fx; ///if insertion was valid continue while } $this->_oSudoku[$m][$n] = 0; if ( $this->_stack->isEmpty() ) //If backtracked till begining return NOT SOLVABLE return self::NOT_SOLVABLE; else list( $m, $n ) = $this->_stack->pop(); //backtrack } else { if ( $n === 8 ): $m += 1; $n = 0; else: $n += 1; endif; } endwhile; } public function OutputArray() { return $this->_oSudoku; } public function OutputString() { array_walk( $this->_oSudoku, function( &$ele ) { $ele = implode( "", $ele ); } ); return implode( "", $this->_oSudoku ); } public function __toString() { return print_r( $this->_oSudoku, true ); } } class Stack { private $stk = array(); public function push($m, $n) { array_push( $this->stk, array($m, $n) ); } public function pop() { return array_pop($this->stk); } public function isEmpty() { return count($this->stk) === 0; } public function stackHeight() { return count( $this->stk ); } public function emptyStack() { while( !$this->isEmpty() ) $this->pop(); } } $sudoku = new SudokuGenerator(); $sudoku->GenerateSudoku( SudokuGenerator::METRIC_EASY ); $sudoku = new SudokuSolver($sudoku->OutputString()); $sudoku->Solve(); print $sudoku->OutputString();

Here you find the average performance (time & memory) of each version. A grayed out version indicates it didn't complete successfully (based on exit-code).

VersionSystem time (s)User time (s)Memory (MiB)
7.4.10.0070.01114.88
7.4.00.0070.01015.31
7.3.130.0140.00714.76
7.3.120.0070.00714.63
7.3.110.0110.00714.77
7.3.100.0090.00615.10
7.3.90.0040.01114.98
7.3.80.0060.00915.13
7.3.70.0080.01114.90
7.3.60.0070.00315.02
7.3.50.0090.00514.90
7.3.40.0060.01214.82
7.3.30.0050.01514.89
7.3.20.0100.00815.72
7.3.10.0140.00615.76
7.3.00.0130.00515.65
7.2.260.0140.00714.79
7.2.250.0100.00515.16
7.2.240.0130.00615.02
7.2.230.0070.01015.22
7.2.220.0110.00715.33
7.2.210.0100.01015.42
7.2.200.0070.01014.95
7.2.190.0070.00714.97
7.2.180.0080.00815.11
7.2.170.0030.01315.18
7.2.160.0120.00315.29
7.2.150.0120.00916.00
7.2.140.0090.01016.12
7.2.130.0080.01215.93
7.2.120.0110.00816.14
7.2.110.0030.01716.23
7.2.100.0130.00715.95
7.2.90.0130.00516.01
7.2.80.0080.01015.95
7.2.70.0080.00815.89
7.2.60.0160.00715.88
7.2.50.0130.00715.93
7.2.40.0120.01116.08
7.2.30.0070.00915.99
7.2.20.0130.00616.04
7.2.10.0130.01516.17
7.2.00.0160.00316.00
7.1.330.0040.01115.93
7.1.320.0000.01115.72
7.1.310.0040.01415.59
7.1.300.0000.01515.62
7.1.290.0100.00915.32
7.1.280.0080.01214.79
7.1.270.0100.00714.91
7.1.260.0090.01115.01
7.1.250.0110.01114.73
7.1.240.0040.01115.69
7.1.230.0060.00915.65
7.1.220.0070.01015.57
7.1.210.0030.01415.42
7.1.200.0000.01415.71
7.1.190.0090.00615.67
7.1.180.0000.01215.75
7.1.170.0060.01315.68
7.1.160.0040.01115.33
7.1.150.0060.00915.71
7.1.140.0000.01215.56
7.1.130.0090.00615.88
7.1.120.0100.00315.24
7.1.110.0070.00715.43
7.1.100.0140.00415.78
7.1.90.0030.01215.83
7.1.80.0090.00315.71
7.1.70.0070.01015.34
7.1.60.0070.00715.73
7.1.50.0000.01315.71
7.1.40.0040.01115.59
7.1.30.0030.01315.94
7.1.20.0030.00715.59
7.1.10.0110.00715.56
7.1.00.0060.00915.61

preferences:
35.37 ms | 400 KiB | 5 Q