PHP :: Aufgabe #189

1 Lösung Lösung öffentlich

Generierung eines SUDOKU

Anfänger - PHP von hollst - 13.08.2018 um 16:23 Uhr
Für alle, denen es nicht bekannt sein sollte: Ein SUDOKU ist ein 9 × 9 - Gitter,
das mit den Ziffern 1 bis 9 so ausgefüllt ist, dass jede Ziffer in jeder Spalte,
in jeder Zeile und in jedem 3 x 3 - Unterblock genau ein einziges Mal vorkommt (Bild 1).

Insgesamt sind fast 6.7 Trilliarden (10 hoch 21) unterschiedliche SUDOKUS konstruierbar
(genau 6.670.903.752.021.072.936.960).

Die Programmieraufgabe bestehe darin, mittels Zufallsgenerator SUDOKUS zu erzeugen
und anzuzeigen.

Durch Ausblendung einiger Felder entsteht aus einem SUDOKU ein SUDOKU-Rätsel. Dabei
müssen allerdings mindestens 17 Felder unausgeblendet sein, um eine eindeutige Lösung
zu erhalten (Beweis siehe McGuire, Gary; Tugemann, Bastian; Civario, Gilles:
There is no 16-Clue Sudoku: Solving the Sudoku Minimum Number of Clues Problem.
2012arXiv1201.0749M, Sep 2013). Die Erzeugung eines solchen SUDOKU-Rätsels sei
Fortgeschrittenen vorbehalten, da hierbei auch die Eindeutigkeit einer Lösung nachgewiesen
werden sollte. Der Gipfel wäre anschließend, einen computergestützten SUDOKU-Löser zu entwickeln;
aber, wir wollen es hier noch nicht übertreiben, eines nach dem anderen und nur, wer die
Herausforderung nich scheut.

Viel Spaß!

Lösungen:

vote_ok
von Holzi (430 Punkte) - 31.08.2018 um 15:18 Uhr
Ich hab mich diese Woche etwas näher damit beschäftigt, ich würde diese Aufgabe jedoch nicht für Anfänger einstufen sondern eher als Fortgeschritten. Das Programm erzeugt bei Seitenaufruf ein valides, komplett zufälliges Sudoku.

Quellcode ausblenden PHP-Code
<?php

class Sudoku
{
	private $field = [];
	
	public function __construct ()
	{
		$this->init();
	}
	
	private function init()
	{
		$this->field = array_fill(0, 9, array_fill(0, 9, 0));
	}
	
	public function createField ()
	{
		$this->init();
		
		for ($row = 0; $row < 9; $row++)
		{
			$this->fillRow($row);
		}
	}
	
	private function fillRow($row)
	{
		$col = 0;
		
		$status = false;
		$count = 0;
		$errorOccuredAtCol = 0;
		$errorCount = 0;
		
		while ($status === false)
		{
			$possibleNumbers = $this->getPossibleNumbers($row, $col);
			
			if (count($possibleNumbers) > 0)
			{
				if ($col >= $errorOccuredAtCol)
				{
					$count = 0;
				}
				
				shuffle($possibleNumbers);
				
				$this->field[$row][$col] = $possibleNumbers[0];
				
				if ($col >= 8)
				{
					$status = true;
				}
				
				$col++;
			}
			else
			{
				$errorOccuredAtCol = $col;
				$count++;
				
				if ($col - $count < 0)
				{
					$col = 0;
					$errorCount++;
					
					if ($errorCount > 3)
					{
						for ($k = 0; $k < 9; $k++)
						{
							$this->field[$row][$k] = 0;
						}
						
						$tempRow = $row - 1 < 0 ? 0 : $row -1;
						
						$errorCount = 0;
						$this->fillRow($tempRow);
						$count = 0;
					}
				}
				else
				{
					$col -= $count;
				}
				
				$col = $col - $count < 0 ? $col = 0 : $col - $count;
				
				for ($i = $col; $i < 9; $i++)
				{
					$this->field[$row][$i] = 0;
				}
			}
		}
	}
	
	private function getPossibleNumbers ($row, $col)
	{
		$values = [];
		
		$rowValues = $this->getRowValues($row);
		
		foreach ($rowValues as $value)
		{
			$values[] = $value;
		}
		
		$colValues = $this->getColValues($col);
		
		foreach ($colValues as $value)
		{
			$values[] = $value;
		}
		
		$squareValues = $this->getSquareValues($row, $col);
		
		foreach ($squareValues as $squareValue)
		{
			$values[] = $squareValue;
		}
		
		$values = array_unique($values);
		
		$range = range(1,9);
		
		return array_diff($range, $values);
	}
	
	private function getRowValues ($row)
	{
		$values = [];
		
		for ($i = 0; $i < 9; $i++)
		{
			if ($this->field[$row][$i] !== 0)
			{
				$values[] = $this->field[$row][$i];
			}
		}
		
		return $values;
	}
	
	private function getColValues ($col)
	{
		$values = [];
		
		for ($i = 0; $i < 9; $i++)
		{
			if ($this->field[$i][$col] !== 0)
			{
				$values[] = $this->field[$i][$col];
			}
		}
		
		return $values;
	}
	
	private function getSquareValues($row, $col)
	{
		$xSquare = floor($row / 3);
		$ySquare = floor($col / 3);
		
		$square = [];
		
		for ($i = 0; $i < 3; $i++)
		{
			for ($j = 0; $j < 3; $j++)
			{
				$square[] = $this->field[$i + $xSquare * 3][$j + $ySquare * 3];
			}
		}
		
		return $square;
	}
	
	public function drawField ()
	{
		echo '<table>';
		for ($i = 0; $i < 9; $i++)
		{
			echo '<tr>';
			for ($j = 0; $j < 9; $j++)
			{
				echo '<td class="table-field">' . $this->field[$i][$j] . '</td>';
			}
			echo '</tr>';
		}
		echo '</table>';
	}
}

echo "
<style>
	table {
		border-collapse: collapse;
		border: 1px solid black;
		width: 200px;
		height: 200px;
	}
	td {
		text-align: center;
	}
	td:nth-of-type(3n + 0) {
		border-right: 1px solid black;
	}
	tr:nth-of-type(3n + 0) {
		border-bottom: 1px solid black;
	}
</style>";

$sudoku = new Sudoku;
$sudoku->createField();
$sudoku->drawField();
1808827

Du scheinst einen AdBlocker zu nutzen. Ich würde mich freuen, wenn du ihn auf dieser Seite deaktivierst und dich davon überzeugst, dass die Werbung hier nicht störend ist.