Sudoku: Difference between revisions

Content added Content deleted
m (→‎{{header|OCaml}}: English language link)
(Added another C# solution)
Line 1,530: Line 1,530:
146 897 325
146 897 325
</pre>
</pre>

===Using the "Dancing Links" algorithm===
<lang csharp>using System;
using System.Collections.Generic;
using System.Text;
using static System.Linq.Enumerable;

public class Sudoku
{
public static void Main2() {
string puzzle = "....7.94.....9...53....5.7...74..1..463...........7.8.8........7......28.5.26....";
string solution = new Sudoku().Solutions(puzzle).FirstOrDefault() ?? puzzle;
Print(puzzle, solution);
}

private DLX dlx;

public void Build() {
const int rows = 9 * 9 * 9, columns = 4 * 9 * 9;
dlx = new DLX(rows, columns);
for (int i = 0; i < columns; i++) dlx.AddHeader();

for (int cell = 0, row = 0; row < 9; row++) {
for (int column = 0; column < 9; column++) {
int box = row / 3 * 3 + column / 3;
for (int digit = 0; digit < 9; digit++) {
dlx.AddRow(cell, 81 + row * 9 + digit, 2 * 81 + column * 9 + digit, 3 * 81 + box * 9 + digit);
}
cell++;
}
}
}

public IEnumerable<string> Solutions(string puzzle) {
if (puzzle == null) throw new ArgumentNullException(nameof(puzzle));
if (puzzle.Length != 81) throw new ArgumentException("The input is not of the correct length.");
if (dlx == null) Build();

for (int i = 0; i < puzzle.Length; i++) {
if (puzzle[i] == '0' || puzzle[i] == '.') continue;
if (puzzle[i] < '1' && puzzle[i] > '9') throw new ArgumentException($"Input contains an invalid character: ({puzzle[i]})");
int digit = puzzle[i] - '0' - 1;
dlx.Give(i * 9 + digit);
}
return Iterator();

IEnumerable<string> Iterator() {
var sb = new StringBuilder(new string('.', 81));
foreach (int[] rows in dlx.Solutions()) {
foreach (int r in rows) {
sb[r / 81 * 9 + r / 9 % 9] = (char)(r % 9 + '1');
}
yield return sb.ToString();
}
}
}

static void Print(string left, string right) {
foreach (string line in GetPrintLines(left).Zip(GetPrintLines(right), (l, r) => l + "\t" + r)) {
Console.WriteLine(line);
}

IEnumerable<string> GetPrintLines(string s) {
int r = 0;
foreach (string row in s.Cut(9)) {
yield return r == 0
? "╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗"
: r % 3 == 0
? "╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣"
: "╟───┼───┼───╫───┼───┼───╫───┼───┼───╢";
yield return "║ " + row.Cut(3).Select(segment => segment.DelimitWith(" │ ")).DelimitWith(" ║ ") + " ║";
r++;
}
yield return "╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝";
}
}

}

public class DLX //Some functionality elided
{
private readonly Header root = new Header(null, null) { Size = int.MaxValue };
private readonly List<Header> columns;
private readonly List<Node> rows;
private readonly Stack<Node> solutionNodes = new Stack<Node>();
private int initial = 0;

public DLX(int rowCapacity, int columnCapacity) {
columns = new List<Header>(columnCapacity);
rows = new List<Node>(rowCapacity);
}

public void AddHeader() {
Header h = new Header(root.Left, root);
h.AttachLeftRight();
columns.Add(h);
}

public void AddRow(params int[] newRow) {
Node first = null;
if (newRow != null) {
for (int i = 0; i < newRow.Length; i++) {
if (newRow[i] < 0) continue;
if (first == null) first = AddNode(rows.Count, newRow[i]);
else AddNode(first, newRow[i]);
}
}
rows.Add(first);
}

private Node AddNode(int row, int column) {
Node n = new Node(null, null, columns[column].Up, columns[column], columns[column], row);
n.AttachUpDown();
n.Head.Size++;
return n;
}

private void AddNode(Node firstNode, int column) {
Node n = new Node(firstNode.Left, firstNode, columns[column].Up, columns[column], columns[column], firstNode.Row);
n.AttachLeftRight();
n.AttachUpDown();
n.Head.Size++;
}

public void Give(int row) {
solutionNodes.Push(rows[row]);
CoverMatrix(rows[row]);
initial++;
}

public IEnumerable<int[]> Solutions() {
try {
Node node = ChooseSmallestColumn().Down;
do {
if (node == node.Head) {
if (node == root) {
yield return solutionNodes.Select(n => n.Row).ToArray();
}
if (solutionNodes.Count > initial) {
node = solutionNodes.Pop();
UncoverMatrix(node);
node = node.Down;
}
} else {
solutionNodes.Push(node);
CoverMatrix(node);
node = ChooseSmallestColumn().Down;
}
} while(solutionNodes.Count > initial || node != node.Head);
} finally {
Restore();
}
}

private void Restore() {
while (solutionNodes.Count > 0) UncoverMatrix(solutionNodes.Pop());
initial = 0;
}

private Header ChooseSmallestColumn() {
Header traveller = root, choice = root;
do {
traveller = (Header)traveller.Right;
if (traveller.Size < choice.Size) choice = traveller;
} while (traveller != root && choice.Size > 0);
return choice;
}

private void CoverRow(Node row) {
Node traveller = row.Right;
while (traveller != row) {
traveller.DetachUpDown();
traveller.Head.Size--;
traveller = traveller.Right;
}
}

private void UncoverRow(Node row) {
Node traveller = row.Left;
while (traveller != row) {
traveller.AttachUpDown();
traveller.Head.Size++;
traveller = traveller.Left;
}
}

private void CoverColumn(Header column) {
column.DetachLeftRight();
Node traveller = column.Down;
while (traveller != column) {
CoverRow(traveller);
traveller = traveller.Down;
}
}

private void UncoverColumn(Header column) {
Node traveller = column.Up;
while (traveller != column) {
UncoverRow(traveller);
traveller = traveller.Up;
}
column.AttachLeftRight();
}

private void CoverMatrix(Node node) {
Node traveller = node;
do {
CoverColumn(traveller.Head);
traveller = traveller.Right;
} while (traveller != node);
}

private void UncoverMatrix(Node node) {
Node traveller = node;
do {
traveller = traveller.Left;
UncoverColumn(traveller.Head);
} while (traveller != node);
}

private class Node
{
public Node(Node left, Node right, Node up, Node down, Header head, int row) {
Left = left ?? this;
Right = right ?? this;
Up = up ?? this;
Down = down ?? this;
Head = head ?? this as Header;
Row = row;
}

public Node Left { get; set; }
public Node Right { get; set; }
public Node Up { get; set; }
public Node Down { get; set; }
public Header Head { get; }
public int Row { get; }

public void AttachLeftRight() {
this.Left.Right = this;
this.Right.Left = this;
}

public void AttachUpDown() {
this.Up.Down = this;
this.Down.Up = this;
}

public void DetachLeftRight() {
this.Left.Right = this.Right;
this.Right.Left = this.Left;
}

public void DetachUpDown() {
this.Up.Down = this.Down;
this.Down.Up = this.Up;
}

}

private class Header : Node
{
public Header(Node left, Node right) : base(left, right, null, null, null, -1) { }
public int Size { get; set; }
}

}

static class Extensions
{
public static IEnumerable<string> Cut(this string input, int length)
{
for (int cursor = 0; cursor < input.Length; cursor += length) {
if (cursor + length > input.Length) yield return input.Substring(cursor);
else yield return input.Substring(cursor, length);
}
}

public static string DelimitWith<T>(this IEnumerable<T> source, string separator) => string.Join(separator, source);
}</lang>
{{out}}
<pre>
╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗ ╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗
║ . │ . │ . ║ . │ 7 │ . ║ 9 │ 4 │ . ║ ║ 2 │ 1 │ 5 ║ 8 │ 7 │ 6 ║ 9 │ 4 │ 3 ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢ ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║ . │ . │ . ║ . │ 9 │ . ║ . │ . │ 5 ║ ║ 6 │ 7 │ 8 ║ 3 │ 9 │ 4 ║ 2 │ 1 │ 5 ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢ ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║ 3 │ . │ . ║ . │ . │ 5 ║ . │ 7 │ . ║ ║ 3 │ 4 │ 9 ║ 1 │ 2 │ 5 ║ 8 │ 7 │ 6 ║
╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣ ╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣
║ . │ . │ 7 ║ 4 │ . │ . ║ 1 │ . │ . ║ ║ 5 │ 8 │ 7 ║ 4 │ 3 │ 2 ║ 1 │ 6 │ 9 ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢ ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║ 4 │ 6 │ 3 ║ . │ . │ . ║ . │ . │ . ║ ║ 4 │ 6 │ 3 ║ 9 │ 8 │ 1 ║ 7 │ 5 │ 2 ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢ ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║ . │ . │ . ║ . │ . │ 7 ║ . │ 8 │ . ║ ║ 1 │ 9 │ 2 ║ 6 │ 5 │ 7 ║ 3 │ 8 │ 4 ║
╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣ ╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣
║ 8 │ . │ . ║ . │ . │ . ║ . │ . │ . ║ ║ 8 │ 2 │ 6 ║ 7 │ 4 │ 3 ║ 5 │ 9 │ 1 ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢ ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║ 7 │ . │ . ║ . │ . │ . ║ . │ 2 │ 8 ║ ║ 7 │ 3 │ 4 ║ 5 │ 1 │ 9 ║ 6 │ 2 │ 8 ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢ ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║ . │ 5 │ . ║ 2 │ 6 │ . ║ . │ . │ . ║ ║ 9 │ 5 │ 1 ║ 2 │ 6 │ 8 ║ 4 │ 3 │ 7 ║
╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝ ╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝</pre>


=={{header|C++}}==
=={{header|C++}}==