打ち上げと禁じ手

石の打ち上げと禁じ手の判定です。

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

プログラムの説明

  1. 石の打ち上げと禁じ手を調べます。
    囲碁のルールは簡単で、19×19の盤上のどこにでも置けるのですが、それでも禁じ手があります。
    禁じ手は石の打ち上げと関連があるので、合わせて判定します。
    次の図を見て下さい。

    黒石が*に打たれると、白石は周囲を囲まれて活力が無くなり打ち上げられます。(左の図)
    また×の場所に白石を置いた場合は、置くと同時に活力が無くなります。(中央と右の図)
    これが囲碁の禁じ手で、×には打つことが出来ません。
    もう一つ、囲碁にはコウのルールがあるのですが、対局はしないので今回は判定しません。
    禁じ手と石の打ち上げのチェックには、プログラムテクニックが必要です。
  2. 禁じ手を調べる Taboo() 関数です。
    座標 x,y に石を打てるとき true を、禁じ手のとき false をリターンします。
    黒番でプログラムしていますが、白番でも同じです。
    m_Ban[,] をコピーした m_W[,] を作業領域として使っています。
    調べた場所には「2」を置きます。
    この関数は打ち上げの判定と共通で、打ち上げる石には「3」を設定します。
    m_W[x, y] = 3; の一行を追加するだけで、打ち上げる石をマークすることが出来ます。
    Taboo() 関数の中から Taboo() 関数を呼んでいることに注目して下さい。
    再起のプログラムは見ただけでは良くわかりません。
    実際に動かしてみて下さい。
    再起のサンプルは 迷路探索のプログラム を参考にして下さい。
        private bool Taboo(int x, int y, short kuro)
        {   int siro;
    
            siro = 0 - kuro;
            if (XY(x, y)==false)    return false;   // 盤の外
            if (m_W[x, y]==0)       return true;    // OK
            if (m_W[x, y]==siro)    return false;   // 白の壁
            if (m_W[x, y]==kuro)
            {
                m_W[x, y] = 2;
                if (Taboo(x + 1, y, kuro)) return true;
                if (Taboo(x, y + 1, kuro)) return true;
                if (Taboo(x - 1, y, kuro)) return true;
                if (Taboo(x, y - 1, kuro)) return true;
            }
            m_W[x, y] = 3;  // 打ち上げの石
            return false;   // 禁じ手(詰まっている)
        }
    
  3. X,Y の座標チェックする XY() 関数です。
        private bool XY(int x, int y)
        {
            if (x < 0 || x > 18) return false;
            if (y < 0 || y > 18) return false;
            return true;
        }
    
  4. 石の打ち上げを判定する Utiage() 関数です。
    打ち上げは、置いた石の上下左右の相手方の石を調べて、Taboo() の状態になっていることで判定できます。
        int[]       m_x = { 1, -1, 0, 0 };      // 上下左右の隣接定数
        int[]       m_y = { 0, 0, 1, -1 };
    
        private bool Utiage(int x, int y, short kuro)
        {   short   siro;
            bool    rc;
            int     wx, wy, k, i, j;
    
            siro = (short)(0 - kuro);
            rc = false;
    
            for(k=0; k<4; k++)       // 上下左右に隣接する石を調べる
            {
                m_W = (short[,])m_Ban.Clone();
                m_W[x, y] = kuro;
                wx = x+m_x[k];
                wy = y+m_y[k];
                if (XY(wx, wy) && m_W[wx, wy] == siro && Taboo(wx, wy, siro) == false)
                {
                    for (i = 0; i < 19; i++)
                        for (j = 0; j < 19; j++)
                            if (m_W[i, j] == 3) m_Ban[i, j] = 0;
                    rc = true;
                }
            }
            return rc;
        }
    
  5. 禁じ手と打ち上げを考慮した OnMyMouseDown() 関数です。
    Check() 関数で、禁じ手と打ち上げを調べます。
        private void OnMyMouseDown(object sender, MouseEventArgs e)
        {
            short   teban = 1;
            Point   pos = new Point(e.X, e.Y);
            if (ClickPos(ref pos) == false) return;
    
            if (e.Button == MouseButtons.Right) teban = -1;
            switch(Check(pos, teban))
            {
                case 0:
                    m_Ban[pos.X, pos.Y] = teban;
                    break;
                case 1:         // 打ち上げです
                    m_Ban[pos.X, pos.Y] = teban;
                    break;
                case 2:         // 手番の石です
                    m_Ban[pos.X, pos.Y] = 0;
                    break;
                case 3:         // 相手の石です
                    break;
                case 4:
                    MessageBox.Show("禁じ手です");
                    break;
            }
            Invalidate();
        }
    
  6. 座標の石をチェックする Check() 関数です。
    Taboo() 関数を呼び出すときは m_Ban[,] を m_W[,] にコピーします。
        private int Check(Point pos, short kuro)
        {   int siro;
    
            if (kuro == 0) return 0;
            siro = 0 - kuro;
            if (m_Ban[pos.X, pos.Y]==kuro)  return 2;   // 手番の石
            if (m_Ban[pos.X, pos.Y]==siro)  return 3;   // 相手の石
            if (Utiage(pos.X,pos.Y,kuro))   return 1;   // 打ち上げ
            m_W = (short[,])m_Ban.Clone();
            m_W[pos.X, pos.Y] = kuro;
            if (Taboo(pos.X,pos.Y,kuro))    return 0;   // OK
            return 4;                                   // 禁じ手
        }
    

[Next Chapter ↓] SGF ファイルを入力
[Previous Chapter ↑] クリックで石を置く

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