数独求解器无限循环

时间:2016-02-24 23:56:43

标签: php oop sudoku

我正在编写一个基于backtrace algorithm的数独求解器。

我写了整个课程来解决它并且它正在工作,但仅用于非常简单的谜题(例如,缺少81个数字中的5个)。使用经典的简易拼图(大约40个缺失的数字)它会抛出一个错误(具体地说是致命错误:允许的内存大小为1342177280字节耗尽(试图分配65488字节))。我认为这是一个无限循环,但我找不到它。

我的求解功能就是这样:

Find empty cell
   If empty cell request return true, there is no empty cell -> sudoku is solved

If selected cell is empty prepare number 1
If selected cell is not empty, get it's number do +1

Try if prepared number is valid, if not do +1, if tryied number is 9, then start function again and go back

If prepared number was valid, write it into array.

Run this solving function (here probably will be the infinity loop I guess)

我试图用die()编号来调试它,但是前几个数字还可以,并且它很顺利。

哪里应该是个错误?

现在编码,我希望这是可以理解的。如果你问我,我可以解释代码的任何部分。

<?php

class sudokuSolver {

    private $line = 0; 
    private $column = 0;

    private $sudokuOnlyForRead = array( 
    array('', '', '6', '4', '7', '', '3', '', ''),
    array('', '', '4', '6', '5', '', '9', '', ''),
    array('3', '', '', '', '', '8', '', '4', ''),

    array('2', '6', '7', '3', '', '9', '5', '', ''),
    array('8', '', '', '2', '4', '7', '1', '', ''),
    array('', '', '', '', '', '', '', '', '7'),

    array('', '', '2', '', '6', '5', '4', '3', '1'),
    array('', '', '8', '9', '3', '1', '', '2', ''),
    array('', '3', '', '', '', '', '', '', ''),
    );

    private $sudoku = array( 
    array('', '', '6', '4', '7', '', '3', '', ''),
    array('', '', '4', '6', '5', '', '9', '', ''),
    array('3', '', '', '', '', '8', '', '4', ''),

    array('2', '6', '7', '3', '', '9', '5', '', ''),
    array('8', '', '', '2', '4', '7', '1', '', ''),
    array('', '', '', '', '', '', '', '', '7'),

    array('', '', '2', '', '6', '5', '4', '3', '1'),
    array('', '', '8', '9', '3', '1', '', '2', ''),
    array('', '3', '', '', '', '', '', '', ''),
    );


    public function solve()
    {
        $nextEmptyCell = $this->findNextEmptyCell(); 

        startForLastEmptyCell:

        if ($nextEmptyCell === true) {
            return $this->sudoku;
        }

        if (empty($this->getActualCell())) { 
            $newNumber = 1; 
        } else {
            $newNumber = $this->getActualCell()+1;
        }

        while ($this->isNewNumberValid($newNumber) == false) { 
            $newNumber++; 

            if ($newNumber == 10) {
                $this->findLastEmptyCell();
                goto startForLastEmptyCell;
            }
        }

        $this->sudoku[$this->line][$this->column] = $newNumber;

        $this->solve();
    }

    private function isValidInLine($number)
    {
        $searchedLine = $this->line;

        if (in_array($number, $this->sudoku[$searchedLine])) {
            return false;
        } 

        return true;
    }

    private function isValidInColumn($number) 
    {
        $searchedColumn = $this->column;

        foreach ($this->sudoku as $lines) {
            if ($lines[$searchedColumn] == $number) {
                return false;
            }
        }

        return true;
    }

    private function isValidInBox($number)
    {
        $searchedLine = $this->line;
        $searchedColumn = $this->column;

        $linesToInspect = $this->coordsToInspectInBox($searchedLine);
        $columnsToInspect = $this->coordsToInspectInBox($searchedColumn);

        foreach ($linesToInspect as $lineToInspect) {
            foreach ($columnsToInspect as $columnToInspect) {
                if ($number == $this->sudoku[$lineToInspect][$columnToInspect]) {
                    return false;
                }
            }
        }

        return true;
    }

    private function isNewNumberValid($number)
    {
        if ($this->isValidInLine($number) && $this->isValidInColumn($number) && $this->isValidInBox($number)) {
            return true;
        }

        return false;
    }

    private function findNextEmptyCell()
    {
        $nextEmptyCell = '';

        $searchedLine = $this->line; 
        $searchedColumn = $this->column;

        while(empty($nextEmptyCell)) { 

            if ($searchedColumn == 9) { 
                $searchedColumn = 0;
                $searchedLine++;
            } 

            if ($searchedLine == 9) { 
                return true;
            }

            if(empty($this->sudoku[$searchedLine][$searchedColumn])) { 
                $nextEmptyCell = array($searchedLine, $searchedColumn);

                $this->line = $searchedLine;
                $this->column = $searchedColumn;

                return $nextEmptyCell; 
            }

            $searchedColumn++; 
        }
    }

    private function findLastEmptyCell() 
    {
        $lastEmptyCell = '';

        $searchedLine = $this->line;
        $searchedColumn = $this->column;

        while(empty($lastEmptyCell)) { 

            if ($searchedColumn == 0) { 

                $searchedColumn = 8;
                --$searchedLine;
            }

            --$searchedColumn; 

            if(empty($this->sudokuOnlyForRead[$searchedLine][$searchedColumn])) { 

                $lastEmptyCell = array($searchedLine, $searchedColumn);

                $this->line = $searchedLine;
                $this->column = $searchedColumn;
            }
        }

        return $lastEmptyCell; 
    }

    private function coordsToInspectInBox($coord)
    {
        if ($coord % 3 == 0) {
            return array($coord, $coord+1, $coord+2);
        } elseif ($coord % 3 == 1) {
            return array($coord-1, $coord, $coord+1);
        } elseif ($coord % 3 == 2) {
            return array($coord-2, $coord-1, $coord);
        }
    }

    private function getActualCell()
    {
        return $this->sudoku[$this->line][$this->column];
    }

}

0 个答案:

没有答案