【C#】【Windowsフォームアプリケーション】5年ぶりに数独を解く Part 3

はじめに

今回は「検証ボタン」と「新規入力ボタン」を実装します。

「検証ボタン」は入力された問題が適切がどうか検証するためのものです。

問題を解く前に実行するようにします。

C#コード

まずはGUIのためのファイル(settings.cs)に以下を追加しました。

newBtn.Click += New_Click;
kensyoBtn.Click += Kensyo_Click;
solveBtn.Enabled = false;



最終的にはsettings.csはこのようになっています。

using System;
using System.Drawing;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        FlowLayoutPanel flp1 = new FlowLayoutPanel();
        TableLayoutPanel tlp1 = new TableLayoutPanel();
        Button[] numberBtn = new Button[81];
        Button dummyBtn = new Button();
        Button newBtn = new Button();
        Button kensyoBtn = new Button();
        Button solveBtn = new Button();

        private void Form1_load(object sender, EventArgs e)
        {
            int[] btn_position = { 0, 1, 2, 4, 5, 6, 8, 9, 10 };

            Text = "solver";

            for (int i = 0; i < 3; i++)
            {
                tlp1.RowStyles.Add(new RowStyle(SizeType.Percent, 11f));
                tlp1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 11f));
            }
            tlp1.RowStyles.Add(new RowStyle(SizeType.Percent, .5f));
            tlp1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, .5f));
            for (int i = 0; i < 3; i++)
            {
                tlp1.RowStyles.Add(new RowStyle(SizeType.Percent, 11f));
                tlp1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 11f));
            }
            tlp1.RowStyles.Add(new RowStyle(SizeType.Percent, .5f));
            tlp1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, .5f));
            for (int i = 0; i < 3; i++)
            {
                tlp1.RowStyles.Add(new RowStyle(SizeType.Percent, 11f));
                tlp1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 11f));
            }
            tlp1.Size = new Size(TLPSize, TLPSize);

            for (int i = 0; i < 81; i++)
            {
                numberBtn[i] = new Button();
                numberBtn[i].Text = "";
                numberBtn[i].Dock = DockStyle.Fill;
                numberBtn[i].Margin = new Padding(0);
                numberBtn[i].Font = buttonFont;
                numberBtn[i].Click += ClicknumberBtn;
                tlp1.Controls.Add(numberBtn[i], btn_position[i % 9], btn_position[i / 9]);
            }
            SetClientSizeCore(TLPSize + FLPWidth, TLPSize);

            Controls.Add(tlp1);

            flp1.Width = FLPWidth;
            flp1.Dock = DockStyle.Right;
            flp1.FlowDirection = FlowDirection.BottomUp;

            Controls.Add(flp1);

            dummyBtn.Size = new Size(flp1.Width, 0);

            newBtn.AutoSize = true;
            newBtn.Font = buttonFont;
            newBtn.Text = "新規入力";
            newBtn.Width = (int)(flp1.Width * 0.9);
            newBtn.Anchor = AnchorStyles.None;
            newBtn.Click += New_Click;

            kensyoBtn.AutoSize = true;
            kensyoBtn.Font = buttonFont;
            kensyoBtn.Text = "検証";
            kensyoBtn.Width = newBtn.Width;
            kensyoBtn.Anchor = AnchorStyles.None;
            kensyoBtn.Click += Kensyo_Click;

            solveBtn.AutoSize = true;
            solveBtn.Font = buttonFont;
            solveBtn.Text = "実行";
            solveBtn.Width = newBtn.Width;
            solveBtn.Anchor = AnchorStyles.None;
            solveBtn.Enabled = false;

            flp1.Controls.Add(dummyBtn);
            flp1.Controls.Add(newBtn);
            flp1.Controls.Add(solveBtn);
            flp1.Controls.Add(kensyoBtn);
        }
    }
}



いよいよクリックイベントの中身を実装していきます。


コードはメインファイル(Form1.cs)に書きました。


まずは以下を追加しました。

using System.Linq;
private readonly int[] box_start = { 0, 3, 6, 27, 30, 33, 54, 57, 60 };
private readonly int[] box_offset = { 0, 1, 2, 9, 10, 11, 18, 19, 20 };
int[] kazu = new int[81];

検証ボタンの実装

private void Kensyo_Click(object sender, EventArgs e)
{
    int d;
    for (int i = 0; i < 81; i++)
    {
        int.TryParse(numberBtn[i].Text, out d);
        kazu[i] = d;
    }
    if (Kensyo_do())
    {
        solveBtn.Enabled = true;
        kensyoBtn.Enabled = false;
        foreach (Button btn in numberBtn)
        {
            btn.Enabled = false;
        }
    }
    else
    {
        MessageBox.Show("入力が不適です", "結果"
            , MessageBoxButtons.OK, MessageBoxIcon.Information);
    }
}
private bool Kensyo_do()
{
    int[] box_test = new int[9];
    int[] row_test = new int[9];
    int[] col_test = new int[9];

    for (int i = 0; i < 9; i++)
    {
        for (int ii = 0; ii < 9; ii++)
        {
            box_test[ii] = kazu[box_start[i] + box_offset[ii]];
            row_test[ii] = kazu[i * 9 + ii];
            col_test[ii] = kazu[i + ii * 9];
        }
        if (box_test.Where(c => c > 0).Count() != box_test.Where(c => c > 0).Distinct().Count())
        {
            return false;
        }
        if (row_test.Where(c => c > 0).Count() != row_test.Where(c => c > 0).Distinct().Count())
        {
            return false;
        }
        if (col_test.Where(c => c > 0).Count() != col_test.Where(c => c > 0).Distinct().Count())
        {
            return false;
        }
    }
    return true;
}

新規入力ボタンの実装

private void New_Click(object sender, EventArgs e)
{
    foreach (Button btn in numberBtn)
    {
        btn.Enabled = true;
        btn.Text = "";
    }
    kensyoBtn.Enabled = true;
    solveBtn.Enabled = false;
}



最終的にはForm1.csはこのようになっています。

using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        private const int TLPSize = 400;
        private const int FLPWidth = 150;
        public static Font buttonFont = new Font("游ゴシック", 12);
        private readonly int[] box_start = { 0, 3, 6, 27, 30, 33, 54, 57, 60 };
        private readonly int[] box_offset = { 0, 1, 2, 9, 10, 11, 18, 19, 20 };

        int[] kazu = new int[81];

        public Form1()
        {
            Load += Form1_load;
        }
        private void ClicknumberBtn(object sender, EventArgs e)
        {
            if (((Button)sender).Text == "")
            {
                InputForm input = new InputForm();
                int Form1_x = Left;
                int Form1_y = Top;
                int x_min = ((Button)sender).Left;
                int y_min = ((Button)sender).Top;
                int width_half = ((Button)sender).Width / 2;

                input.Left = Form1_x + x_min + width_half;
                input.Top = Form1_y + y_min + width_half;
                input.StartPosition = FormStartPosition.Manual;
                input.ShowDialog();

                ((Button)sender).Text = input.result;
                input.Dispose();
            }
            else
            {
                ((Button)sender).Text = "";
            }
        }
        private void Kensyo_Click(object sender, EventArgs e)
        {
            int d;
            for (int i = 0; i < 81; i++)
            {
                int.TryParse(numberBtn[i].Text, out d);
                kazu[i] = d;
            }
            if (Kensyo_do())
            {
                solveBtn.Enabled = true;
                kensyoBtn.Enabled = false;
                foreach (Button btn in numberBtn)
                {
                    btn.Enabled = false;
                }
            }
            else
            {
                MessageBox.Show("入力が不適です", "結果"
                    , MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }
        private bool Kensyo_do()
        {
            int[] box_test = new int[9];
            int[] row_test = new int[9];
            int[] col_test = new int[9];

            for (int i = 0; i < 9; i++)
            {
                for (int ii = 0; ii < 9; ii++)
                {
                    box_test[ii] = kazu[box_start[i] + box_offset[ii]];
                    row_test[ii] = kazu[i * 9 + ii];
                    col_test[ii] = kazu[i + ii * 9];
                }
                if (box_test.Where(c => c > 0).Count() != box_test.Where(c => c > 0).Distinct().Count())
                {
                    return false;
                }
                if (row_test.Where(c => c > 0).Count() != row_test.Where(c => c > 0).Distinct().Count())
                {
                    return false;
                }
                if (col_test.Where(c => c > 0).Count() != col_test.Where(c => c > 0).Distinct().Count())
                {
                    return false;
                }
            }
            return true;
        }
        private void New_Click(object sender, EventArgs e)
        {
            foreach (Button btn in numberBtn)
            {
                btn.Enabled = true;
                btn.Text = "";
            }
            kensyoBtn.Enabled = true;
            solveBtn.Enabled = false;
        }
    }
}



これで後は問題を解くためのコードを書くのみとなりました。

前回までの記事

【C#】【Windowsフォームアプリケーション】5年ぶりに数独を解く Part 1
【C#】【Windowsフォームアプリケーション】5年ぶりに数独を解く Part 2

つづきの記事

【C#】【Windowsフォームアプリケーション】5年ぶりに数独を解く Part 4