C# WPF 数独求解器

By jerryxjr1220 at 2023-10-27 • 0人收藏 • 312人看过

原来写过的数独算法,套了个WPF的框,方便数独输入和输出。

屏幕截图 2023-10-27 164752.png

<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;
    }
}


登录后方可回帖

登 录
信息栏
 私人小站

本站域名

ChengXu.XYZ

投诉联系:  popdes@126.com



快速上位机开发学习,本站主要记录了学习过程中遇到的问题和解决办法及上位机代码分享

这里主要专注于学习交流和经验分享.
纯私人站,当笔记本用的,学到哪写到哪.
如果侵权,联系 Popdes@126.com

友情链接
Aardio官方
Aardio资源网


才仁机械


网站地图SiteMap

Loading...