Data commit

This commit is contained in:
Ingy döt Net 2023-07-01 11:58:00 -04:00
parent 7387c8f97b
commit cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions

View file

@ -0,0 +1,103 @@
using System;
class SudokuSolver
{
private int[] grid;
public SudokuSolver(String s)
{
grid = new int[81];
for (int i = 0; i < s.Length; i++)
{
grid[i] = int.Parse(s[i].ToString());
}
}
public void solve()
{
try
{
placeNumber(0);
Console.WriteLine("Unsolvable!");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(this);
}
}
public void placeNumber(int pos)
{
if (pos == 81)
{
throw new Exception("Finished!");
}
if (grid[pos] > 0)
{
placeNumber(pos + 1);
return;
}
for (int n = 1; n <= 9; n++)
{
if (checkValidity(n, pos % 9, pos / 9))
{
grid[pos] = n;
placeNumber(pos + 1);
grid[pos] = 0;
}
}
}
public bool checkValidity(int val, int x, int y)
{
for (int i = 0; i < 9; i++)
{
if (grid[y * 9 + i] == val || grid[i * 9 + x] == val)
return false;
}
int startX = (x / 3) * 3;
int startY = (y / 3) * 3;
for (int i = startY; i < startY + 3; i++)
{
for (int j = startX; j < startX + 3; j++)
{
if (grid[i * 9 + j] == val)
return false;
}
}
return true;
}
public override string ToString()
{
string sb = "";
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
sb += (grid[i * 9 + j] + " ");
if (j == 2 || j == 5)
sb += ("| ");
}
sb += ('\n');
if (i == 2 || i == 5)
sb += ("------+-------+------\n");
}
return sb;
}
public static void Main(String[] args)
{
new SudokuSolver("850002400" +
"720000009" +
"004000000" +
"000107002" +
"305000900" +
"040000000" +
"000080070" +
"017000000" +
"000036040").solve();
Console.Read();
}
}

View file

@ -0,0 +1,77 @@
using System.Linq;
using static System.Linq.Enumerable;
using System.Collections.Generic;
using System;
using System.Runtime.CompilerServices;
namespace SodukoFastMemoBFS {
internal readonly record struct Square (int Row, int Col);
internal record Constraints (IEnumerable<int> ConstrainedRange, Square Square);
internal class Cache : Dictionary<Square, Constraints> { };
internal record CacheGrid (int[][] Grid, Cache Cache);
internal static class SudokuFastMemoBFS {
internal static U Fwd<T, U>(this T data, Func<T, U> f) => f(data);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int RowCol(int rc) => rc <= 2 ? 0 : rc <= 5 ? 3 : 6;
private static bool Solve(this CacheGrid cg, Constraints constraints, int finished) {
var (row, col) = constraints.Square;
foreach (var i in constraints.ConstrainedRange) {
cg.Grid[row][col] = i;
if (cg.Cache.Count == finished || cg.Solve(cg.Next(constraints.Square), finished))
return true;
}
cg.Grid[row][col] = 0;
return false;
}
private static readonly int[] domain = Range(0, 9).ToArray();
private static readonly int[] range = Range(1, 9).ToArray();
private static bool Valid(this int[][] grid, int row, int col, int val) {
for (var i = 0; i < 9; i++)
if (grid[row][i] == val || grid[i][col] == val)
return false;
for (var r = RowCol(row); r < RowCol(row) + 3; r++)
for (var c = RowCol(col); c < RowCol(col) + 3; c++)
if (grid[r][c] == val)
return false;
return true;
}
private static IEnumerable<int> Constraints(this int[][] grid, int row, int col) =>
range.Where(val => grid.Valid(row, col, val));
private static Constraints Next(this CacheGrid cg, Square square) =>
cg.Cache.ContainsKey(square)
? cg.Cache[square]
: cg.Cache[square]=cg.Grid.SortedCells();
private static Constraints SortedCells(this int[][] grid) =>
(from row in domain
from col in domain
where grid[row][col] == 0
let cell = new Constraints(grid.Constraints(row, col), new Square(row, col))
orderby cell.ConstrainedRange.Count() ascending
select cell).First();
private static CacheGrid Parse(string input) =>
input
.Select((c, i) => (index: i, val: int.Parse(c.ToString())))
.GroupBy(id => id.index / 9)
.Select(grp => grp.Select(id => id.val).ToArray())
.ToArray()
.Fwd(grid => new CacheGrid(grid, new Cache()));
public static string AsString(this int[][] grid) =>
string.Join('\n', grid.Select(row => string.Concat(row)));
public static int[][] Run(string input) {
var cg = Parse(input);
var marked = cg.Grid.SelectMany(row => row.Where(c => c > 0)).Count();
return cg.Solve(cg.Grid.SortedCells(), 80 - marked) ? cg.Grid : new int[][] { Array.Empty<int>() };
}
}
}

View file

@ -0,0 +1,36 @@
using System.Linq;
using static System.Linq.Enumerable;
using static System.Console;
using System.IO;
namespace SodukoFastMemoBFS {
static class Program {
static void Main(string[] args) {
var num = int.Parse(args[0]);
var puzzles = File.ReadLines(@"sudoku17.txt").Take(num);
var single = puzzles.First();
var watch = new System.Diagnostics.Stopwatch();
watch.Start();
WriteLine(SudokuFastMemoBFS.Run(single).AsString());
watch.Stop();
WriteLine($"{single}: {watch.ElapsedMilliseconds} ms");
WriteLine($"Doing {num} puzzles");
var total = 0.0;
watch.Start();
foreach (var puzzle in puzzles) {
watch.Reset();
watch.Start();
SudokuFastMemoBFS.Run(puzzle);
watch.Stop();
total += watch.ElapsedMilliseconds;
Write(".");
}
watch.Stop();
WriteLine($"\nPuzzles:{num}, Total:{total} ms, Average:{total / num:0.00} ms");
ReadKey();
}
}
}

View file

@ -0,0 +1,73 @@
using Microsoft.SolverFoundation.Solvers;
namespace Sudoku
{
class Program
{
private static int[,] B = new int[,] {{9,7,0, 3,0,0, 0,6,0},
{0,6,0, 7,5,0, 0,0,0},
{0,0,0, 0,0,8, 0,5,0},
{0,0,0, 0,0,0, 6,7,0},
{0,0,0, 0,3,0, 0,0,0},
{0,5,3, 9,0,0, 2,0,0},
{7,0,0, 0,2,5, 0,0,0},
{0,0,2, 0,1,0, 0,0,8},
{0,4,0, 0,0,7, 3,0,0}};
private static CspTerm[] GetSlice(CspTerm[][] sudoku, int Ra, int Rb, int Ca, int Cb)
{
CspTerm[] slice = new CspTerm[9];
int i = 0;
for (int row = Ra; row < Rb + 1; row++)
for (int col = Ca; col < Cb + 1; col++)
{
{
slice[i++] = sudoku[row][col];
}
}
return slice;
}
static void Main(string[] args)
{
ConstraintSystem S = ConstraintSystem.CreateSolver();
CspDomain Z = S.CreateIntegerInterval(1, 9);
CspTerm[][] sudoku = S.CreateVariableArray(Z, "cell", 9, 9);
for (int row = 0; row < 9; row++)
{
for (int col = 0; col < 9; col++)
{
if (B[row, col] > 0)
{
S.AddConstraints(S.Equal(B[row, col], sudoku[row][col]));
}
}
S.AddConstraints(S.Unequal(GetSlice(sudoku, row, row, 0, 8)));
}
for (int col = 0; col < 9; col++)
{
S.AddConstraints(S.Unequal(GetSlice(sudoku, 0, 8, col, col)));
}
for (int a = 0; a < 3; a++)
{
for (int b = 0; b < 3; b++)
{
S.AddConstraints(S.Unequal(GetSlice(sudoku, a * 3, a * 3 + 2, b * 3, b * 3 + 2)));
}
}
ConstraintSolverSolution soln = S.Solve();
object[] h = new object[9];
for (int row = 0; row < 9; row++)
{
if ((row % 3) == 0) System.Console.WriteLine();
for (int col = 0; col < 9; col++)
{
soln.TryGetValue(sudoku[row][col], out h [col]);
}
System.Console.WriteLine("{0}{1}{2} {3}{4}{5} {6}{7}{8}", h[0],h[1],h[2],h[3],h[4],h[5],h[6],h[7],h[8]);
}
}
}
}

View file

@ -0,0 +1,279 @@
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);
}