C# WPF 数独求解器
By
jerryxjr1220
at 2023-10-27 • 0人收藏 • 570人看过
原来写过的数独算法,套了个WPF的框,方便数独输入和输出。

<hc:GlowWindow x:Class="WPFSudokuSolver.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:WPFSudokuSolver.ViewModels"
xmlns:hc="https://handyorg.github.io/handycontrol"
d:DataContext="{d:DesignInstance Type=vm:MainViewModel}"
mc:Ignorable="d"
Title="Sudoku Puzzle" Height="480" Width="800" Background="White"
FontFamily="JetBrains Mono" ResizeMode="NoResize"
FontSize="{StaticResource TextFontSize}">
<Window.Resources>
</Window.Resources>
<hc:SimplePanel>
<ScrollViewer x:Name="scrollViewer" VerticalScrollBarVisibility="Auto">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="8*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Sudoku Puzzle Solver"
Style="{StaticResource TextBlockDefaultPrimary}" FontSize="20" HorizontalAlignment="Left"
Margin="10" />
<Button Grid.Row="0" Grid.Column="0" Content="Solve" Style="{StaticResource ButtonPrimary}" Margin="10"
HorizontalAlignment="Right"
Command="{Binding SolveCommand}" />
<WrapPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<TextBox hc:InfoElement.Title="Steps:" hc:InfoElement.TitlePlacement="Left" Margin="10, 0"
Style="{StaticResource TextBoxExtend}" IsReadOnly="True" VerticalAlignment="Center"
FontSize="12" Foreground="{StaticResource PrimaryBrush}" Width="250"
Text="{Binding Steps}" />
</WrapPanel>
<StackPanel Grid.Row="1" Grid.Column="0">
<TextBlock Text="Original Matrix" Style="{StaticResource TextBlockDefaultInfo}" />
<ItemsControl ItemsSource="{Binding OriginalBlocks}" Margin="10">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding XPosActual}" />
<Setter Property="Canvas.Top" Value="{Binding YPosActual}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="DarkGray" BorderThickness="1" Width="40" Height="40">
<TextBox Text="{Binding BlockType, Mode=TwoWay}"
HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
FontSize="20" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
<StackPanel Grid.Row="1" Grid.Column="1">
<TextBlock Text="Solution Matrix" Style="{StaticResource TextBlockDefaultSuccess}" />
<ItemsControl ItemsSource="{Binding SolvedBlocks}" Margin="10">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding XPosActual}" />
<Setter Property="Canvas.Top" Value="{Binding YPosActual}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="DarkGray" BorderThickness="1" Width="40" Height="40">
<TextBox Text="{Binding BlockType}" IsReadOnly="True"
HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
FontSize="20" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Grid>
</ScrollViewer>
</hc:SimplePanel>
</hc:GlowWindow>using System.ComponentModel;
using CommunityToolkit.Mvvm.ComponentModel;
namespace WPFSudokuSolver.Models;
public partial class BlockModel : ObservableObject
{
[ObservableProperty] private int _blockSize;
[ObservableProperty] private string _blockType;
[ObservableProperty] private int _xPos;
[ObservableProperty] private int _xPosActual;
[ObservableProperty] private int _yPos;
[ObservableProperty] private int _yPosActual;
public BlockModel()
{
}
public BlockModel(string _type, int _x, int _y, int _blockSize = 40)
{
BlockType = _type;
BlockSize = _blockSize;
XPos = _x;
YPos = _y;
}
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
switch (e.PropertyName)
{
case "XPos":
XPosActual = XPos * BlockSize;
break;
case "YPos":
YPosActual = YPos * BlockSize;
break;
}
}
}using System.ComponentModel;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using WPFSudokuSolver.Models;
namespace WPFSudokuSolver.ViewModels;
public partial class MainViewModel : ObservableObject
{
[ObservableProperty] private int _blockSize;
[ObservableProperty] private BindingList<BlockModel> _originalBlocks;
[ObservableProperty] private BindingList<BlockModel> _solvedBlocks;
[ObservableProperty] private int _steps;
private readonly char[,] matrix;
public MainViewModel()
{
Steps = 0;
matrix = new char[9, 9];
BlockSize = 40;
OriginalBlocks = new BindingList<BlockModel>();
SolvedBlocks = new BindingList<BlockModel>();
for (var i = 0; i < 9; i++)
for (var j = 0; j < 9; j++)
{
var oblock = new BlockModel(string.Empty, i, j, BlockSize);
var sblock = new BlockModel(string.Empty, i, j, BlockSize);
OriginalBlocks.Add(oblock);
SolvedBlocks.Add(sblock);
}
}
[RelayCommand]
public async Task SolveAsync()
{
for (var i = 0; i < 9; i++)
for (var j = 0; j < 9; j++)
foreach (var oblock in OriginalBlocks)
if (oblock.XPos == i && oblock.YPos == j)
matrix[i, j] = oblock.BlockType.Length > 0 ? oblock.BlockType[0] : '.';
await Task.Run(() =>
{
var solver = new SudokuSolver();
solver.Solve(matrix);
Steps = solver.steps;
});
for (var i = 0; i < 9; i++)
for (var j = 0; j < 9; j++)
foreach (var sblock in SolvedBlocks)
if (sblock.XPos == i && sblock.YPos == j)
sblock.BlockType = matrix[i, j].ToString();
}
}
internal class SudokuSolver
{
public int steps;
public bool Solve(char[,] board)
{
for (var row = 0; row < 9; row++)
for (var col = 0; col < 9; col++)
if (board[row, col] == '.')
{
for (var num = '1'; num <= '9'; num++)
{
steps++;
if (IsValid(board, row, col, num))
{
board[row, col] = num;
if (Solve(board))
return true;
board[row, col] = '.'; // 回溯
}
}
return false; // 当前情况无解
}
return true; // 数独已解答
}
private bool IsValid(char[,] board, int row, int col, char num)
{
for (var i = 0; i < 9; i++)
{
if (board[i, col] != '.' && board[i, col] == num)
return false;
if (board[row, i] != '.' && board[row, i] == num)
return false;
var boxRow = 3 * (row / 3) + i / 3;
var boxCol = 3 * (col / 3) + i % 3;
if (board[boxRow, boxCol] != '.' && board[boxRow, boxCol] == num)
return false;
}
return true;
}
}登录后方可回帖