挟んだ駒を裏返す


マウスで「黒,白」の駒を置いて、挟んだ駒を裏返します。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プログラムの説明

  1. C#でオセロゲームを作成します。
    プログラムの実行環境は Windows10 & Visual Studio 2017 です。
    テンプレートのプロジェクトは Form を作成する で上記の実行環境でも問題なく動くようです。
    2020-01 Windows10 & Visual Studio 2005 で若干プログラムを修正しました。
    プロジェクトの起動から *.csproj を選択すると起動出来ます。(*.sln からは起動できません)
    「Form を作成する」を起動して、Form(ウインドウ) の表示を確認して下さい。
    バージョン変換のメッセージが表示されますが、私の場合は問題無く実行されました。
  2. ページ先頭の画像を加工して、オセロ・ゲームで使うリソースを用意して下さい。
    リソース 説明
    ban.gif 512*512 ピクセルの盤です
    koma_b.gif 幅54*高さ56 ピクセルの黒の駒
    koma_w.gif 幅54*高さ56 ピクセルの白の駒
  3. CSForm.cs を次のように修正して下さい。
    マウスで左クリックすると黒が、右クリックすると白の駒が置かれます。
    正しい手を打つと挟んだ駒が裏返されます。
    打つことが出来ないときは MessageBox が表示されます。
    // マウスのクリックでプレイする(左:黒, 右:白)
    using System;
    using System.Drawing;
    using System.Windows.Forms;
    using System.Collections;
    using System.Diagnostics;
    
    public class MyForm : Form
    {
        int[,] m_t = new int[8, 8]
        {{  0,  0,  0,  0,  0,  0,  0,  0 },
         {  0,  0,  0,  0,  0,  0,  0,  0 },
         {  0,  0,  0,  0,  0,  0,  0,  0 },
         {  0,  0,  0,  1, -1,  0,  0,  0 },
         {  0,  0,  0, -1,  1,  0,  0,  0 },
         {  0,  0,  0,  0,  0,  0,  0,  0 },
         {  0,  0,  0,  0,  0,  0,  0,  0 },
         {  0,  0,  0,  0,  0,  0,  0,  0 }};
    
        // Constructor
        public MyForm()
        {
            BackColor = SystemColors.AppWorkspace;
            Width = 560;
            Height = 600;
            Paint += new PaintEventHandler(MyHandler);
            MouseDown += new MouseEventHandler(OnMyMouseDown);
        }
    
        // オセロ盤の描画
        private void MyHandler(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            g.DrawImage(new Bitmap("c:\\data\\test\\ban.gif"), new PointF(10F, 10F));
            for (int y = 0; y < 8; y++)
            {
                for (int x = 0; x < 8; x++)
                {
                    if (m_t[y, x] == 1) g.DrawImage(new Bitmap("c:\\data\\test\\koma_b.gif"), new PointF(x * 61 + 28, y * 61 + 24));
                    if (m_t[y, x] == -1) g.DrawImage(new Bitmap("c:\\data\\test\\koma_w.gif"), new PointF(x * 61 + 28, y * 61 + 24));
                }
            }
            if (Count(0, m_t) == 0)
            {
                string str = "★Game Over  黒:" + Count(1, m_t).ToString() + "  白:" + Count(-1, m_t).ToString();
                MessageBox.Show(str);
            }
        }
    
        // マウスのクリック
        private void OnMyMouseDown(object sender, MouseEventArgs e)
        {
            int     x, y;
            x = (e.X - 28) / 61;
            y = (e.Y - 24) / 61;
            if (e.Button == MouseButtons.Left)
            {
                if (Reverse(1, x, y, m_t) == false) MessageBox.Show("置くことはできません");
            }
            if (e.Button == MouseButtons.Right)
            {
                if (Reverse(-1, x, y, m_t) == false) MessageBox.Show("置くことはできません");
            }
            Invalidate();
        }
    
        // t[y,x] に駒を置いて、挟んだ駒を裏返す
        bool Reverse(int c, int xp, int yp, int[,] t)
        {
            int     i, j, x, y;
            bool    sw = false;
            int     nc = 0-c;
            if (yp > 7 || xp > 7 || yp < 0 || xp < 0 || c == 0 || t[yp, xp] != 0) return false;
            for (i = -1; i < 2; i++)
                for (j = -1; j < 2; j++)
                {
                    y = yp + i;
                    x = xp + j;
                    if (y < 8 && x < 8 && y >= 0 && x >= 0 && t[y, x] == nc)
                    {
                        for (; y < 8 && x < 8 && y >= 0 && x >= 0 && t[y, x] == nc; y += i, x += j) ;
                        if (y < 8 && x < 8 && y >= 0 && x >= 0 && t[y, x] == c)
                        {
                            for (; y != yp || x != xp; y -= i, x -= j) t[y, x] = c;
                            sw = true;
                        }
                    }
                }
            if (sw == false) return false;
            t[yp, xp] = c;
            return true;
        }
    
        // 駒のカウント
        int Count(int c, int[,] t)
        {
            int cnt= 0;
            for (int y = 0; y < 8; y++)
            {
                for (int x = 0; x < 8; x++)
                    if (t[y, x] == c) cnt++;
            }
            return cnt;
        }
    
        void t_Log(int sz, int[,] t)
        {
            string str = "";
            for (int y = 0; y < sz; y++)
            {
                for (int x = 0; x < sz; x++)
                {
                    if (t[y, x] == 0) str = str + ".";
                    if (t[y, x] == 1) str = str + "X";
                    if (t[y, x] == -1) str = str + "O";
                }
                str = str + "\n";
            }
            Debug.Write(str);
        }
    }
    
    class osero
    {
        public static void Main()
        {
            MyForm mf = new MyForm();
            Application.Run(mf);
        }
    }
    
  4. プログラムは Main() 関数から始まります。
    new MyForm() で MyForm Class を生成して、Application.Run() で起動するのは Windows Program の常套手段です。
        public static void Main()
        {
            MyForm mf = new MyForm();
            Application.Run(mf);
        }
    
  5. m_t[8,8] が駒の配置を定義する二次元配列です。
    空白を 0 で、黒の駒を 1 で、白の駒を -1 で表します。
    オセロゲームの最初の局面を設定してみました。
    public class MyForm : Form
    {
        int[,] m_t = new int[8, 8]
        {{  0,  0,  0,  0,  0,  0,  0,  0 },
         {  0,  0,  0,  0,  0,  0,  0,  0 },
         {  0,  0,  0,  0,  0,  0,  0,  0 },
         {  0,  0,  0,  1, -1,  0,  0,  0 },
         {  0,  0,  0, -1,  1,  0,  0,  0 },
         {  0,  0,  0,  0,  0,  0,  0,  0 },
         {  0,  0,  0,  0,  0,  0,  0,  0 },
         {  0,  0,  0,  0,  0,  0,  0,  0 }};
    
  6. MyForm() はコンストラクタです。
    ウインドウサイズの設定と描画関数の呼び出しとマウスがクリックされたときに呼び出す関数を定義します。
        public MyForm()
        {
            BackColor = SystemColors.AppWorkspace;
            Width = 560;
            Height = 600;
            Paint += new PaintEventHandler(MyHandler);
            MouseDown += new MouseEventHandler(OnMyMouseDown);
        }
    
  7. MyHandler() は画面を描画する関数です 。
    私は画像を "c:\\data\\test\\" に置いて開発しています。
    ban.gif でオセロの盤を描画してから、m_t[8,8] に従って黒と白の駒を描画します。
    8*8=64の盤に駒が置かれたら、黒,白をカウントして終了です。
    (黒,白どちらも置けない場合があるので、この終了判定は不完全です)
        private void MyHandler(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            g.DrawImage(new Bitmap("c:\\data\\test\\ban.gif"), new PointF(10F, 10F));
            for (int y = 0; y < 8; y++)
            {
                for (int x = 0; x < 8; x++)
                {
                    if (m_t[y, x] == 1) g.DrawImage(new Bitmap("c:\\data\\test\\koma_b.gif"), new PointF(x * 61 + 28, y * 61 + 24));
                    if (m_t[y, x] == -1) g.DrawImage(new Bitmap("c:\\data\\test\\koma_w.gif"), new PointF(x * 61 + 28, y * 61 + 24));
                }
            }
            if (Count(0, m_t) == 0)
            {
                string str = "★Game Over  黒:" + Count(1, m_t).ToString() + "  白:" + Count(-1, m_t).ToString();
                MessageBox.Show(str);
            }
        }
    
  8. OnMyMouseDown() はマウスをクリックしたときに呼び出されます 。
    左クリックでは黒の駒を、右クリックでは白の駒を打ちます。
    Reverse() 関数で挟んだ駒を反転するのですが、置けない時は false を返します。
    Invalidate() で新しく更新した m_t[8,8] でオセロ盤を描画します。
        private void OnMyMouseDown(object sender, MouseEventArgs e)
        {
            int     x, y;
            x = (e.X - 28) / 61;
            y = (e.Y - 24) / 61;
            if (e.Button == MouseButtons.Left)
            {
                if (Reverse(1, x, y, m_t) == false) MessageBox.Show("置くことはできません");
            }
            if (e.Button == MouseButtons.Right)
            {
                if (Reverse(-1, x, y, m_t) == false) MessageBox.Show("置くことはできません");
            }
            Invalidate();
        }
    
  9. Reverse() 関数は駒を置いて、挟んだ駒を裏返す関数です。
    駒を裏返すことが出来なければ false をリターンします。
        bool Reverse(int c, int xp, int yp, int[,] t)
        {
            int     i, j, x, y;
            bool    sw = false;
            int     nc = 0-c;
            if (yp > 7 || xp > 7 || yp < 0 || xp < 0 || c == 0 || t[yp, xp] != 0) return false;
            for (i = -1; i < 2; i++)
                for (j = -1; j < 2; j++)
                {
                    y = yp + i;
                    x = xp + j;
                    if (y < 8 && x < 8 && y >= 0 && x >= 0 && t[y, x] == nc)
                    {
                        for (; y < 8 && x < 8 && y >= 0 && x >= 0 && t[y, x] == nc; y += i, x += j) ;
                        if (y < 8 && x < 8 && y >= 0 && x >= 0 && t[y, x] == c)
                        {
                            for (; y != yp || x != xp; y -= i, x -= j) t[y, x] = c;
                            sw = true;
                        }
                    }
                }
            if (sw == false) return false;
            t[yp, xp] = c;
            return true;
        }
    
  10. c で渡された駒をカウントする Count() 関数です。
        int Count(int c, int[,] t)
        {
            int cnt= 0;
            for (int y = 0; y < 8; y++)
            {
                for (int x = 0; x < 8; x++)
                    if (t[y, x] == c) cnt++;
            }
            return cnt;
        }
    
  11. オセロゲームは Java や Javascript や Windows でも作成しています。
    詳しい説明はこれらを参照して下さい。

[Next Chapter ↓] プラットホーム

超初心者のプログラム入門(C# Frame Work)