C# WPF 数独求解器
By
jerryxjr1220
at 2023-10-27 • 0人收藏 • 312人看过
原来写过的数独算法,套了个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; } }
登录后方可回帖