Advertisement
Guest User

Untitled

a guest
Aug 3rd, 2015
266
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.04 KB | None | 0 0
  1. <?php
  2.  
  3. /**
  4. * @author Anush Prem <goku.anush@gmail.com>
  5. * @package Solver
  6. * @subpackage Sudoku
  7. * @version 0.1
  8. */
  9.  
  10. /**
  11. * <i>Sudoku Solver</i> class
  12. *
  13. * This class solves the sudoku in my own logic.
  14. *
  15. * This solver takes time to execute according to the
  16. * complexity of the sudoku.
  17. *
  18. * @author Anush Prem <goku.anush@gmail.com>
  19. * @package Solver
  20. * @subpackage Sudoku
  21. * @version 0.1
  22. */
  23.  
  24. Class SudokuSolver{
  25.  
  26. /**
  27. * To store the input Sudoku
  28. * @access private
  29. * @var array $_input row == column mapping
  30. */
  31. private $_input;
  32.  
  33. /**
  34. * To store the currently solved sudoku at any moment of time
  35. * @access private
  36. * @var array $_currentSudoku row == column mapping
  37. */
  38. private $_currentSudoku;
  39.  
  40. /**
  41. * To store the probable values for each cell
  42. * @access private
  43. * @var array $_probable [row][col] == possible values array mapping
  44. */
  45. private $_probable;
  46.  
  47. /**
  48. * to store weather the sudoku have been solved or not
  49. * @access private
  50. * @var bool
  51. */
  52. private $_solved = false;
  53.  
  54. /**
  55. * store weather each cell is solved or not
  56. * @access private
  57. * @var array $_solvedParts row == column (bool) values
  58. */
  59. private $_solvedParts = array (
  60. array ( false, false, false, false, false, false, false, false, false ),
  61. array ( false, false, false, false, false, false, false, false, false ),
  62. array ( false, false, false, false, false, false, false, false, false ),
  63. array ( false, false, false, false, false, false, false, false, false ),
  64. array ( false, false, false, false, false, false, false, false, false ),
  65. array ( false, false, false, false, false, false, false, false, false ),
  66. array ( false, false, false, false, false, false, false, false, false ),
  67. array ( false, false, false, false, false, false, false, false, false ),
  68. array ( false, false, false, false, false, false, false, false, false )
  69. );
  70.  
  71. /**
  72. * SudokuSolver constructor
  73. *
  74. * If the input sudoku is provided it will store to the {@link _input} property.
  75. *
  76. * @access public
  77. * @param array $input row == column mapping
  78. * @return void
  79. */
  80. public function __construct($input = null){
  81.  
  82. // check if the input sudoku is provided, if yes then
  83. // store it in $_input
  84. if ( $input !== null ) $this -> _input = $input;
  85. }
  86.  
  87. /**
  88. * Input Method
  89. *
  90. * Explictly give a new input array if its not already provided in
  91. * the constructor. If already provieded in the constructore then
  92. * it will be replaced
  93. *
  94. * @access public
  95. * @param array $input row == column mapping
  96. * @return void
  97. */
  98. public function input($input){
  99.  
  100. // store the received input into $_input
  101. $this -> _input = $input;
  102. }
  103.  
  104. /**
  105. * Solve Method
  106. *
  107. * The main function to start solving the sudoku and return the
  108. * solved sudoku
  109. *
  110. * @access public
  111. * @return array row == column mapping of solved sudoku
  112. */
  113. public function solve (){
  114.  
  115. // Copy the input sudoku to _currentSudoku
  116. $this -> _currentSudoku = $this -> _input;
  117.  
  118. // update _solvedParts of the given sudoku
  119. $this -> _updateSolved ();
  120.  
  121. // Start solving the sudoku
  122. $this -> _solveSudoku();
  123.  
  124. // return the solved sudoku
  125. return $this -> _currentSudoku;
  126. }
  127.  
  128. /**
  129. * updateSolved Method
  130. *
  131. * Update the _solvedParts array to match the values of
  132. * _currentSudoku.
  133. *
  134. * @access private
  135. * @return void
  136. */
  137. private function _updateSolved(){
  138.  
  139. // loop for rows
  140. for ($i = 0; $i < 9; $i++ )
  141.  
  142. // loop for columns
  143. for ($j = 0; $j < 9; $j++ )
  144.  
  145. // if the value exists for the corresponding row, column
  146. // then update the _solvedParts corresponding row, column
  147. // to true
  148. if ( $this -> _currentSudoku[$i][$j] != 0 )
  149. $this -> _solvedParts[$i][$j] = true;
  150. }
  151.  
  152. /**
  153. * _solveSudoku Method
  154. *
  155. * Main sudoku solving method
  156. *
  157. * @access private
  158. * @return void
  159. */
  160. private function _solveSudoku(){
  161.  
  162. // continue running untill the sudoku is completly solved
  163. do{
  164. // calculate the probable values for each cell an solve
  165. // available cells
  166. $this -> _calculateProbabilityAndSolve();
  167.  
  168. // check weather the sudoku is completly solved
  169. $this -> _checkAllSolved();
  170. }while (!$this -> _solved); // run till the _solved value becomes true
  171.  
  172. }
  173.  
  174. /**
  175. * _calculateProbabilityAndSolve Method
  176. *
  177. * Find the possible values for each cell and
  178. * solve it if possible
  179. *
  180. * @access private
  181. * @return void
  182. */
  183. private function _calculateProbabilityAndSolve(){
  184.  
  185. // find possible values for each cell
  186. $this -> _findPosibilites();
  187.  
  188. // check if each cell is solveable and if yes solve it
  189. $this -> _solvePossible();
  190.  
  191. }
  192.  
  193. /**
  194. * _findPosibilites Method
  195. *
  196. * Find possible values for each cell
  197. *
  198. * @access private
  199. * @return void
  200. */
  201. private function _findPosibilites(){
  202.  
  203. // loop for rows
  204. for ($i = 0; $i < 9; $i++ ){
  205.  
  206. // loop for columns
  207. for ($j = 0; $j < 9; $j++ ){
  208.  
  209. // if the ixj cell is not solved yet
  210. if ( !$this -> _solvedParts[$i][$j] ){
  211.  
  212. // find all possible values for cell ixj
  213. $this -> _findAllProbables ($i, $j);
  214. }
  215. }
  216. }
  217. }
  218.  
  219. /**
  220. * _solvePossible Method
  221. *
  222. * Solve possible cells using probable values calculated
  223. *
  224. * @access private
  225. * @return void
  226. */
  227. private function _solvePossible(){
  228.  
  229. // loop for rows
  230. for ($i = 0; $i < 9; $i++ ){
  231.  
  232. // loop for column
  233. for ($j = 0; $j < 9; $j++ ){
  234.  
  235. // if cell ixj is not solved yet
  236. if ( !$this -> _solvedParts[$i][$j] ){
  237.  
  238. // solve the cell ixj if possible using probable values
  239. // calculated
  240. $this -> _solveIfSolveable ($i, $j);
  241. }
  242. }
  243. }
  244. }
  245.  
  246. /**
  247. * _checkAllSolved Method
  248. *
  249. * check if all the cells have been solved
  250. *
  251. * @access private
  252. * @return void
  253. */
  254. private function _checkAllSolved(){
  255.  
  256. // pre assign all solved as true
  257. $allSolved = true;
  258.  
  259. // loop for rows
  260. for ($i = 0; $i < 9; $i++ ){
  261.  
  262. // loop for columns
  263. for ($j = 0; $j < 9; $j++ ){
  264.  
  265. // if allSolved is still true an the cell iXj is not
  266. if ( $allSolved and !$this -> _solvedParts[$i][$j] ){
  267. // set all solved as false
  268. $allSolved = false;
  269. }
  270. }
  271. }
  272.  
  273. // copy the value of allSolved into _solved.
  274. $this -> _solved = $allSolved;
  275. }
  276.  
  277. /**
  278. * _solveIfSolveable Method
  279. *
  280. * Solve a single cell $rowx$col if it is solveable using
  281. * available probable datas
  282. *
  283. * @access private
  284. * @param int $row 0-8
  285. * @param int $col 0-8
  286. * @return bool
  287. */
  288. private function _solveIfSolveable ($row, $col){
  289.  
  290. // if there is only one probable value for the cell $rowx$col
  291. if ( count ($this -> _probable[$row][$col]) == 1 ){
  292.  
  293. // copy the only possible value to $value
  294. $value = $this -> _probable[$row][$col][0];
  295.  
  296. // set the value of cell $rowx$col as $value an update solvedParts
  297. $this -> _setValueForCell ($row, $col, $value);
  298.  
  299. // return true as solved
  300. return true;
  301. }
  302.  
  303. // pre assign $value as 0. ie; not solved
  304. $value = 0;
  305.  
  306. // loop through all the possible values for $row x $col
  307. // and check if any possiblity can be extracted from it
  308. // by checking if its possible for the same number to be
  309. // positioned anywhere else thus confilicting with current
  310. // cell. If a possibility is not a possibility for any other
  311. // cell in the confilicting places then it is the value for
  312. // current cell
  313. foreach ($this -> _probable[$row][$col] as $possible){
  314.  
  315. // a try-catch exception handling used here
  316. // as a control statement for continuing the main loop
  317. // if a value is possible in some place.
  318. try{
  319.  
  320. // loop through the current column
  321. for ($i = 0; $i < 9; $i++ ){
  322. // if the cell is solved continue the loop
  323. if ($this -> _currentSudoku[$i][$col] != 0)
  324. continue;
  325.  
  326. // if the possible is also possible in the $i x $col cell
  327. // then throw a ContinueException to continue the outer loop
  328. if (in_array($possible, $this -> _probable[$i][$col]))
  329. throw new ContinueException ("Exists");
  330.  
  331. }
  332.  
  333. // loop through the current row
  334. for ($i = 0; $i < 9; $i++ ){
  335. // if the cell is solved continue the loop
  336. if ($this -> _currentSudoku[$row][$i] != 0)
  337. continue;
  338.  
  339. // if the possible is also possible in the $i x $col cell
  340. // then throw a ContinueException to continue the outer loop
  341. if (in_array($possible, $this -> _probable[$row][$i]))
  342. throw new ContinueException ("Exists");
  343.  
  344. }
  345.  
  346. // find the start of the 3x3 grid with $row x $col cell
  347. $gridRowStart = $this -> _findGridStart($row);
  348. $gridColStart = $this -> _findGridStart($col);
  349.  
  350. // loop row through the current 3x3 grid
  351. for ($i = $gridRowStart; $i < $gridRowStart + 3; $i++){
  352.  
  353. // loop column through the current 3x3 gri
  354. for ($j = $gridColStart; $j < $gridColStart + 3; $j++){
  355.  
  356. // if its the current $row x $col cell then
  357. // continue the loop
  358. if ($i == $row && $j == $col )
  359. continue;
  360.  
  361. // if the cell is already solved then
  362. // continue the loop
  363. if ($this -> _currentSudoku[$row][$i] != 0)
  364. continue;
  365.  
  366. // if the possible is also possible in the
  367. // $i x $j cell then throw a ContinueException
  368. // to continue the outer loop
  369. if (in_array($possible, $this -> _probable[$i][$j]))
  370. throw new ContinueException ("Exists");
  371. }
  372. }
  373.  
  374. // if the loop is not continued yet,
  375. // then that means this possible value is
  376. // not possible in any other conflicting
  377. // cells. So assign the value of $value to
  378. // $possible and break the loop.
  379. $value = $possible;
  380. break;
  381. }catch (ContinueException $e){
  382. // if a ContinueException is thrown then contine
  383. // the outer loop
  384. continue;
  385. }
  386. }
  387.  
  388. // if the value of $value is not 0 then the value of
  389. // the cell is $value.
  390. if ($value != 0){
  391.  
  392. // set the value of cell $rowx$col as $value an update solvedParts
  393. $this -> _setValueForCell ($row, $col, $value);
  394.  
  395. // return true as solved
  396. return true;
  397. }
  398.  
  399. // return false as not solved yet.
  400. return false;
  401. }
  402.  
  403. /**
  404. * _setValueForCell Method
  405. *
  406. * If a cell is solved then update the value for
  407. * that cell, and also update the {@link _solvedParts}.
  408. *
  409. * @access private
  410. * @param int $row 0-8
  411. * @param int $col 0-8
  412. * @param int $value 1-9
  413. * @return void
  414. */
  415. private function _setValueForCell($row, $col, $value){
  416.  
  417. // update the solved parts in _currentSudoku.
  418. $this -> _currentSudoku[$row][$col] = $value;
  419.  
  420. // update the corresponding _solvedParts.
  421. $this -> _solvedParts[$row][$col] = true;
  422. }
  423.  
  424. /**
  425. * _findAllProbables Method
  426. *
  427. * Find all possible values for any given cell using
  428. * other already solved or given cell values.
  429. *
  430. * @access private
  431. * @param int $row 0-8
  432. * @param int $col 0-8
  433. * @return void
  434. */
  435. private function _findAllProbables ($row, $col){
  436.  
  437. // initially set the $probable as array 1 to 9.
  438. $probable = range(1,9);
  439.  
  440. // loop through current column
  441. for ($i = 0; $i < 9; $i++ )
  442.  
  443. // if the cell $i x $col is solved and the value of
  444. // cell $ix$col is in the $probable array then remove
  445. // that element.
  446. if (
  447. ( $current = $this -> _currentSudoku[$i][$col] ) != 0
  448. and
  449. ( $key = array_search($current, $probable) ) !== false
  450. )
  451. unset ($probable[$key]);
  452.  
  453. // loop through the current row
  454. for ($i = 0; $i < 9; $i++ )
  455.  
  456. // if the cell $row x $i is solved and the value of
  457. // cell $rowx$i is in the $probable array then remove
  458. // that element.
  459. if (
  460. ( $current = $this -> _currentSudoku[$row][$i] ) != 0
  461. and
  462. ( $key = array_search($current, $probable) ) !== false
  463. )
  464. unset ($probable[$key]);
  465.  
  466. // find the start of the 3x3 grid with $row x $col cell
  467. $gridRowStart = $this -> _findGridStart($row);
  468. $gridColStart = $this -> _findGridStart($col);
  469.  
  470. // loop row through the current 3x3 grid
  471. for ($i = $gridRowStart; $i < $gridRowStart + 3; $i++)
  472.  
  473. // loop column through the current 3x3 grid
  474. for ($j = $gridColStart; $j < $gridColStart + 3; $j++)
  475.  
  476. // if the cell $i x $j is solved and the value of
  477. // cell $ix$j is in the $probable array then remove
  478. // that element.
  479. if (
  480. ( $current = $this -> _currentSudoku[$i][$j] ) != 0
  481. and
  482. ( $key = array_search($current, $probable) ) !== false
  483. )
  484. unset ($probable[$key]);
  485.  
  486. // Store the rest of the probable values to
  487. // _probable[$row][$col]
  488. $this -> _probable[$row][$col] = array_values($probable);
  489.  
  490. }
  491.  
  492. /**
  493. * _findGridStart Method
  494. *
  495. * Find the start of the 3x3 grid in which the value
  496. * comes
  497. *
  498. * @access private
  499. * @param int $value 0-9
  500. * @return int
  501. */
  502. private function _findGridStart ($value){
  503.  
  504. // return the start of the current 3x3 grid
  505. return floor( $value / 3 ) * 3;
  506. }
  507. }
  508.  
  509. /**
  510. * <i>ContinueException</i> class
  511. *
  512. * Extends Exception. Used to throw exception for
  513. * continue the outer most loop.
  514. *
  515. */
  516. Class ContinueException extends Exception{}
  517.  
  518. ?>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement