Sudoku: Difference between revisions

m
Line 1,826:
}</lang>
 
=== Functional"Smart" Recursive Backtrack Solution===
<!-- By Martin Freedman, 20/11/2021 -->
Still needs profiling/hot path tuning:
<lang csharp>using System.Linq;
using static System.Linq.Enumerable;
using System.Collections.Generic;
using System;
using System.Runtime.CompilerServices;
 
namespace Sudoku {
internal static class Sudoku {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool Unique(this IEnumerable<int> values) => values.Distinct().Count() == values.Count();
private static boolint IsUnequalRowCol(this IEnumerable<int> valuesrc) => values.Where(crc <=> c2 !=? 0).Unique() : rc <= 5 ? 3 : 6;
 
private static IEnumerable<(int RowCol(r,int rcc) => rcGetBoxIndices(int <=row, 2int ?col) 0 : rc <= 5 ? 3 : 6;>
private static IEnumerable<int> GetBox(int[][] grid, int row, int col) =>
from r in Range(RowCol(row), 3)
from c in Range(RowCol(col), 3)
select grid[(r][,c]);
 
private static boolreadonly ConstraintsDictionary<(thisint r, int[][] gridc), List<(int rowr, int colc)>> Boxes =>
grid[(from row].IsUnequal in Range(0, 3).Select(i &&=> i * 3)
from col in Range(0, 93).Select(ri => grid[r][col]).IsUnequal()i &&* 3)
GetBox select (grid(row, col), GetBoxIndices(row, col).IsUnequal();)
.ToDictionary(kvp => kvp.Item1, kvp => kvp.Item2.ToList());
 
private static IEnumerable<int> HintsGetBox(this int[][] grid, int row, int col) =>
grid Boxes[(RowCol(row), RowCol(col))].DistinctSelect(p=>grid[p.r][p.c]);
 
.Union(Range(0, 9).Select(r => grid[r][col]).Distinct())
private static readonly .Unionint[] Domain = Range(GetBox(grid1, row, col9).DistinctToArray());
 
.Where(c => c != 0);
private static bool Solve(this int[][] grid, List<(int, int)> cells, int idx) {
private static IEnumerable<(int, int)> SortedCells(this int[][] grid) =>
from row in Range(0, 9)
from col in Range(0, 9)
let cell = (count: Hints(grid, row, col).Count(), cell: (row, col))
orderby cell.count descending
select cell.cell;
private static bool Solve(this int[][] grid, List<(int,int)> cells, int idx) {
if (idx == 81)
return true;
 
var (r, c) = cells[idx];
ifforeach (var i in Domain.Except(grid[.Hints(r][,c] != 0))) {
return grid.Solve(cells,idx+1)[r][c] = i;
if (grid.Constraints(r, c) && grid.Solve(cells, idx + 1))
 
foreach (var i in Range(1, 9)) { return true;
grid[r][c] = i;
if (grid.Constraints(r, c) && grid.Solve(cells,idx+1))
return true;
}
grid[r][c] = 0;
return false;
}
 
private static readonly int[] Unmarked = new[] { 0 };
 
private static IEnumerable<int> GetBoxHints(this int[][] grid, int row, int col) =>
grid[row]
.Union(Range(0, 9).Select(r => grid[r][col]).Distinct())
.Union(GetBox(grid, row, col))
.WhereExcept(c => c != 0Unmarked);
 
private static IEnumerable<(int, int)> SortedCells(this int[][] grid) =>
from row in Range(0, 9)
from col in Range(0, 9)
let cell = (count: grid[row][col] > 0 ? 10 : Hints(grid, row, col).Count(), cell: (row, col))
orderby cell.count descending
select cell.cell;
 
private static int[][] 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())
.Select(grp => grp.Select(id => id.val).ToArray())
.ToArray();
 
Line 1,890 ⟶ 1,897:
public static int[][] Run(string input) {
var grid = Parse(input);
returnvar gridhits = input.SolveWhere(grid.SortedCells().ToList(),c 0)=> ?c grid!= : new int[][]{ Array'0').Empty<int>Count() };
var sorted = grid.SortedCells().ToList();
return grid.Solve(sorted, hits) ? grid : new int[][] { Array.Empty<int>() };
}
}
Line 1,900 ⟶ 1,909:
static class Program {
static void Main(string[] args) {
//https://staffhome.ecm.uwa.edu.au/~00013890/sudoku17 format
var puzzle = "000028000800010000000000700000600403200004000100700000030400500000000010060000000";
WriteLine(Sudoku.Run(puzzle).AsString());
Line 1,906 ⟶ 1,916:
}
}</lang>
Output
<pre>
617328945