数独を解く(別解:バックトラック法)

Form1.cs

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

namespace 数独バックトラック法
{
    public partial class Form1 : Form
    {
        Button[] IDbutton = new Button[81];
        Button kensyo = new Button();
        Button zikko = new Button();
        Button newGame = new Button();

        int[] kazu = new int[81];
        readonly int[] next_position = { 0, 1, 2, 9, 10, 11, 18, 19, 20 };
        readonly int[] start_position = { 0, 3, 6, 27, 30, 33, 54, 57, 60 };

        public Form1()
        {
            InitializeComponent();
        }

        private void kensyo_Click(object sender, EventArgs e)
        {
            //数字の拾い出し
            int d;
            for (int i = 0; i < 81; i++)
            {
                int.TryParse(IDbutton[i].Text, out d);
                kazu[i] = d;
            }
            //検証を実行
            if (kensyo_do())
            {
                zikko.Enabled = true;
                kensyo.Enabled = false;
                foreach (Button a in IDbutton)
                {
                    a.Enabled = false;
                }
            }
            else
            {
                MessageBox.Show("入力が不適です", Application.ProductName
                    , MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }
        private bool kensyo_do()
        {
            int[] box_kensyo = new int[9];
            int[] tate_kensyo = new int[9];
            int[] yoko_kensyo = new int[9];

            for (int i = 0; i < 9; i++)
            {
                for (int ii = 0; ii < 9; ii++)
                {
                    //3×3の検証
                    box_kensyo[ii] = kazu[start_position[i] + next_position[ii]];
                    //横の検証
                    yoko_kensyo[ii] = kazu[i * 9 + ii];
                    //縦の検証
                    tate_kensyo[ii] = kazu[i + ii * 9];
                }
                if (box_kensyo.Where(c => c > 0).Count() != box_kensyo.Where(c => c > 0).Distinct().Count()) return false;
                if (yoko_kensyo.Where(c => c > 0).Count() != yoko_kensyo.Where(c => c > 0).Distinct().Count()) return false;
                if (tate_kensyo.Where(c => c > 0).Count() != tate_kensyo.Where(c => c > 0).Distinct().Count()) return false;
            }
            return true;
        }
        private void newGame_Click(object sender, EventArgs e)
        {
            foreach (Button a in IDbutton)
            {
                a.Text = "";
                a.Enabled = true;
            }
            kensyo.Enabled = true;
            zikko.Enabled = false;
        }
        private void IDbutton_Click(object sender, EventArgs e)
        {
            if (((Button)sender).Text == "")
            {
                input inputform = new input();
                inputform.ShowDialog();
                ((Button)sender).Text = inputform.num;
                inputform.Dispose();
            }
            else
            {
                ((Button)sender).Text = "";
            }
        }
        private void zikko_Click(object sender, EventArgs e)
        {
            Try(kazu);
        }
        private void Try(int[] x)
        {
            //0(空欄)を探す→存在しない場合には-1を返す
            int blank = Array.IndexOf(kazu, 0);
            if (blank != -1)
            {
                for (int i = 1; i < 10; i++)
                {
                    if (isOK(blank,i,kazu))
                    {
                        kazu[blank] = i;
                        Try(kazu);
                        kazu[blank] = 0;
                    }
                }
            }
            else
            {
                for (int i = 0; i < 81; i++)
                {
                    IDbutton[i].Text = kazu[i].ToString();
                }
            }
        }
        private bool isOK(int x, int y, int[] z)
        {
            int yoko; int tate; int box;
            yoko = x / 9;
            tate = x % 9;
            box = (yoko / 3) * 3 + tate / 3;
            for (int i = 0; i < 9; i++)
            {
                if (z[yoko * 9 + i] == y) return false;
                if (z[tate + i * 9] == y) return false;
                if (z[start_position[box] + next_position[i]] == y) return false;
            }
            return true;
        }
    }
}

GUI.cs

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

namespace 数独バックトラック法
{
    public partial class Form1 : Form
    {
        private void Form1_Load(object sender, EventArgs e)
        {
            this.SuspendLayout();
            //Form1の設定
            this.Height = 382; this.Width = 530;
            this.MinimizeBox = false; this.MaximizeBox = false;
            this.Text = "数独ソルバー(バックトラック法)";
            this.FormBorderStyle = FormBorderStyle.FixedSingle;
            //
            //IDbuttonの設定
            int[] gyo = { 10, 45, 80, 120, 155, 190, 230, 265, 300 };

            for (int i = 0; i < 81; i++)
            {
                IDbutton[i] = new Button();
                IDbutton[i].Text = "";
                IDbutton[i].Size = new Size(35, 35);
                IDbutton[i].Font = new Font("Arial", 14);
                IDbutton[i].Location = new Point(gyo[i % 9], gyo[i / 9]);
                IDbutton[i].Click += IDbutton_Click;
            }
            this.Controls.AddRange(IDbutton);
            //
            //新規、検証、実行ボタンの設定
            newGame.Text = "新規入力"; kensyo.Text = "検証"; zikko.Text = "実行";
            newGame.Size = new Size(150, 40);
            kensyo.Size = new Size(150, 40);
            zikko.Size = new Size(150, 40);
            newGame.Location = new Point(350, 190);
            kensyo.Location = new Point(350, 240);
            zikko.Location = new Point(350, 290);
            zikko.Enabled = false;
            newGame.Click += newGame_Click;
            kensyo.Click += kensyo_Click;
            zikko.Click += zikko_Click;
            this.Controls.AddRange(new Control[] { newGame, kensyo, zikko });
            //
            this.ResumeLayout();
        }
    }
}

input.cs

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

namespace 数独バックトラック法
{
    public partial class input : Form
    {
        Button[] button = new Button[9];
        public string num;

        public input()
        {
            InitializeComponent();
            this.StartPosition = FormStartPosition.CenterParent;
        }

        private void input_Load(object sender, EventArgs e)
        {
            this.SuspendLayout();
            this.FormBorderStyle = FormBorderStyle.None;
            this.Height = 250; this.Width = 250;

            int[] position = { 10, 90, 170 };
            for (int i = 0; i < 9; i++)
            {
                button[i] = new Button();
                button[i].Size = new Size(70, 70);
                button[i].Text = (i + 1).ToString();
                button[i].Font = new Font("Arial", 20);
                button[i].Location = new Point(position[i % 3], position[i / 3]);
                button[i].Click += button_Click;
            }
            this.Controls.AddRange(button);
            this.ResumeLayout();
        }
        private void button_Click(object sender, EventArgs e)
        {
            num = ((Button)sender).Text;
            this.Close();
        }
    }
}