数独(六)—— UI界面

我的GitHub地址:https://github.com/gmj0301/gmj
请查看前面的博客!

思路简述

功能简述

首先,这个项目我决定有开始游戏提示检查这三个主要的大功能。
(1)开始游戏
点击 “开始游戏” 按键后,出现三个按键 “简单”,“中等”,“难” 三个按键(简单:题目中有 30 - 40 个空;中等:题目中有 40 - 50 个空;难:题目中有 50 - 60 个空)。点击选择难度后,出现数独题目,可以开始填入数字。此时可以点击 “提示” 和 “检查” 按键进行相关功能。再次点击 “开始游戏” ,出现新的数独题目。
(2) 提示
当填入的数字有错误时,出现窗口告知用户 “有出错的数字,请修改!”,该数字所在位置背景变红,窗口关闭后,背景颜色恢复。当填入的数字没有错误时,在第一个空白处自动填入数字,并保证正确。
(3) 检查
点击 “检查” 按键后,如果有空没有填,则出现窗口告知用户 “有出错的数字,请修改!”;如果出现错误,则出现窗口告知用户 “有出错的数字,请修改!”;如果全部正确,则出现窗口告知用户 “有出错的数字,请修改!”
该项目的流程图是:
在这里插入图片描述

设计思路

因为在前面已经实现了生成数独终局与解数独的功能,所以我决定在前面的基础上更改一些,设计思路不变。大致思路如下:
生成数独题目是在生成的数独终局的基础上,随机生成挖空的数目,再随机选择位置挖空。
数独终局和挖空后的题目都保存下来,数独终局作为答案,可以方便设计提示和检查功能。

难点

整个项目会使用 VS 的 Windows 窗体应用以及 C# 语言。难点在于我前面的项目使用的语言是 C 语言,没有使用 C++,没有使用类。而现在我需要再前面已有的代码进行修改,创建类。而且我对于 C# 并不清楚,使用起来需要学习。

实现过程

首先在 VS 中建立了一个 WPF 工程。

处理框架

主要的函数设计如下:

     public partial class Form1 : Form
    {
        TextBox[ , ] textbox = new TextBox[9, 9];
        Sudoku sudoku = new Sudoku();
        bool temp = true;
        int flag = 0;
        public Form1(); //构造函数
       
        void Initial(); //初始化文本框
        public void write(); //写入文本框
        private void Txt_KeyPress(object sender, KeyPressEventArgs e); //设置键入

        private bool Check_fill();     //检查是否每个空都填了
        private bool Check_correct();   //检查是否每个空都填对了
        
        private void button_start_Click(object sender, EventArgs e); //点击 “开始游戏” 按键
        private void button_tishi_Click(object sender, EventArgs e); //点击 “提示” 按键
        private void button_check_Click(object sender, EventArgs e); //点击 “检查” 按键
        
        public void click_dif(); //点击难易程度按键
        //点击“简单”,“中等”,“难” 按键
        private void button_easy_Click(object sender, EventArgs e);
        private void button_middle_Click(object sender, EventArgs e);
        private void button_hard_Click(object sender, EventArgs e);
    }

先搭了基础界面,由功能可知,设计三个按键 “开始游戏”,“提示”,“检查”:
在这里插入图片描述

五个按键的设置

(1)“简单”,“中等”,“难” 三个按键一开始是不可见的,“提示”,“检查” 按键不可用。

        public Form1()
        {
            InitializeComponent();
            button_tishi.Enabled = false;  //禁止使用“下一轮游戏”按键
            button_check.Enabled = false; //禁止使用“检查答案”按键
            //“简单”“中等”“难”三个按键不可见
            button_easy.Visible = false;   
            button_middle.Visible = false;
            button_hard.Visible = false;
        }

(2)点击 “开始游戏” 就可以出现 “简单”,“中等”,“难” 三个按键, “开始游戏” ,“提示”,“检查” 按键不可见。如果是第二次点击,之前出现的文本框需要重新设置不可见。代码同理(1)中。

(3)点击 “简单”,“中等”,“难” 三个按键出现文本框(里面有数独题目),“简单”,“中等”,“难” 三个按键不可见, “开始游戏” ,“提示”,“检查” 按键可见,文本框可见(如果第一次开始,需要初始化文本框)。

        public void click_dif()
        {
            //“开始游戏”“提示”“检查”三个按键可见
            button_tishi.Visible = true;
            button_start.Visible = true;
            button_check.Visible = true;
            //“提示”“检查”三个按键可以使用
            button_tishi.Enabled = true;
            button_check.Enabled = true;
            //“简单”“中等”“难”三个按键不可见
            button_easy.Visible = false;
            button_hard.Visible = false;
            button_middle.Visible = false;
            if (flag == 1 || flag == 2 || flag == 3) //判断到底点的“简单”“中等”“难”三个按键中的哪个
            {                                        //方便生成数独题目使用
                if (temp == false)                   //如果是不是第一次点“开始游戏”,此时文本框不可见
                {
                    for (int i = 0; i < 9; i++)
                        for (int j = 0; j < 9; j++)
                            textbox[i, j].Visible = true;  //重新设置使其可见
                }
                if (temp == true)        //如果是第一次点“开始游戏”
                {
                    Initial();          //初始化文本框
                    temp = false;        //修改判断标识符
                }
                sudoku.create_quzi(flag);   //用flag把题目的难以程度传递,生成符合要求的数独题目
                write();                    //把数独题目写进文本框
            }
        }

初始化文本框的代码如下:

        private void Initial()
        {
            int x = 80, y = 8, w = 40, d = 45;
            for(int i = 0; i < 9; i++)
                for(int j = 0; j < 9; j++)
                {
                    TextBox txt = new TextBox
                    {
                        //输入长度,上,左,宽,高,是否可见,标签
                        MaxLength = 1,  Top = y + i * d, Left = x + j * d, 
                        Width = w, Height = w, Visible = true, Tag = i * 9 + j
                    };
                    
                    txt.Font = new Font("宋体", 25);
                    txt.Text = "";

                    txt.KeyPress += Txt_KeyPress; //建立按键事件
                    textbox[i, j] = txt;
                    this.Controls.Add(txt);
                }
        }

(4)点击 “提示” 按键,可以提示错误;没有错误填入数字;如果都填完,显示正确。通过通过与作为答案的数独终局比较得到。设计参考上面展示的流程图。

(5)点击 “检查” 按键,还有空,提示;有错误,提示;全部正确,提示。通过与作为答案的数独终局比较得到。设计参考上面展示的流程图。

处理数独

大致的设置如下:
在这里插入图片描述
其中生成数独终局可以查看前面的博客,这里不再重复(生成数独终局)。

生成数独题目,使用 create_sudo(int flag) 函数,flag是标志,标志题目难易程度的要求。根据要求,每个数独3×3格子中至少要挖掉两个,并且总共会生成[30,60]个空,所以我们要先随机出一个总空白数,然后先让每个3×3小矩阵中挖掉两个空(置0),然后再在整个数独矩阵上随机挖空。
具体流程如下:
在这里插入图片描述
代码如下:

       public void create_quzi(int flag)        //随机生成题目
       {
           create_sudo();
           Random rdm = new Random();  //一个随机数
           int blank;
           if (flag == 1) blank = rdm.Next(30, 40);  //简单,30 - 40 个空
           else if (flag == 2) blank = rdm.Next(40, 50); //中等,40 - 50 个空
           else blank = rdm.Next(50, 60);  //难,50 - 60 个空

           for (int i = 0; i < 9; i++)
               for (int j = 0; j < 9; j++)
                   answer[i, j] = sudo[i, j];   //先赋值

           for (int i = 0; i < 9 && blank > 0; i++)   //9个九宫格
           {
               for (int j = 0; j < 2 && blank > 0; j++)  //每个九宫格选两个空
               {
                   int position = rdm.Next(9);   //随机生成一个数,来选九宫格里的位置
                   int x = i / 3 * 3 + position / 3;
                   int y = i % 3 * 3 + position % 3;
                   if (answer[x, y] != 0)   //这个位置没被挖空
                   {
                       answer[x, y] = 0;
                       blank--;
                   }
                   else   //这个位置已经是空了
                   {
                       j--;
                       continue;
                   }
               }
           }
           while (blank > 0)  //当还有空时
           {
               int block = rdm.Next(9);  //选择哪个九宫格
               int position = rdm.Next(9);  //九宫格里的哪个位置
               int x = block / 3 * 3 + position / 3;
               int y = block % 3 * 3 + position % 3;
               if (answer[x, y] != 0)  //没有被挖空
               {
                   answer[x, y] = 0;
                   blank--;
               }
               else continue;
           }
       }

结果显示

开始界面

在这里插入图片描述

点击“开始游戏”

在这里插入图片描述

点击“简单”

在这里插入图片描述

点击“提示”

在这里插入图片描述
在这里插入图片描述

点击“检查”

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总结

虽然大体思路很清晰,但是还是出现了很多细节上问题。整个项目做下来,尽管有前面 C 语言代码的基础,依然花费了很长时间,但是整个项目下来,我收获了很多,也学到了很多。当然,这个功能并不是很完善,而且可能会有错误,比如我没有判断生成的数独题目是不是有唯一解,以后有机会会把它继续完善的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值