C# winform GDI+ 五子棋 (二):根據博弈算法寫的人機AI(抄的別人的)

白棋是ai,最後ai走贏了。
根據博弈算法的一個AI。遍歷深度6層,下子很慢。其實我是從別人的代碼裏複製的算法,改到自己上面用了。
這個博弈算法
 class GameAI
    {
        /// <summary>
        /// 符合條件的落子點(周圍有棋子)
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        private bool hasne(int x, int y)
        {
            for (int i = (x - 2 > 0 ? x - 2 : 0); i <= x + 2 && i < 18; ++i)
                for (int j = (y - 2 > 0 ? y - 2 : 0); j <= y + 2 && j < 18; ++j)
                   // if (i != 0 || j != 0)
                        if (CheckBoard.ChessPieces[i][j] != 0)
                            return true;
            return false;
        }
        /// <summary>
        /// 生成待分析數組
        /// </summary>
        private void generatepoint()
        {
            CheckBoard.BlankPieces.Clear();
            for (int i = 0; i < 18; ++i)
                for (int j = 0; j < 18; ++j)
                    if (CheckBoard.ChessPieces[i][j] == 0 && hasne(i, j))
                    {
                        CheckBoard.BlankPieces.Add(new Piece(i, j));
                    }
        }
        /// <summary>
        /// 分數評估
        /// </summary>
        /// <param name="number"></param>
        /// <param name="empty1"></param>
        /// <returns></returns>
        private int scoretable(int number, int empty1)
        {
            if (number >= 5) return 100000;
            else if (number == 4)
            {
                if (empty1 == 2) return 10000;//
                else if (empty1 == 1) return 1000;//
            }
            else if (number == 3)
            {
                if (empty1 == 2) return 1000;
                else if (empty1 == 1) return 100;
            }
            else if (number == 2)
            {
                if (empty1 == 2) return 100;
                else if (empty1 == 1) return 10;
            }
            else if (number == 1 && empty1 == 2) return 10;
            return 0;
        }
        /// <summary>
        /// 正斜線、反斜線、橫、豎,均轉成一維數組來計算 
        /// </summary>
        /// <param name="pieces"></param>
        /// <param name="flag"></param>
        /// <returns></returns>
        private int countscore(Piece[] pieces, int flag)
        {
            int scoretmp = 0;
            int empty1 = 0;//死活
            int number = 0;
            //1:黑子 2:白子
            if (pieces[0].Flag == 0) ++empty1;
            else if (pieces[0].Flag == flag) number++;
            for (int i = 1; i < pieces.Length; i++)
            {
                if (pieces[i] == null) break;
                if (pieces[i].Flag == flag)
                {
                    number++;
                }
                else if (pieces[i].Flag == 0)
                {
                    if (number == 0) empty1 = 1;
                    else
                    {
                        scoretmp += scoretable(number, empty1 + 1);
                        empty1 = 1;
                        number = 0;
                    }
                }
                else
                {
                    scoretmp += scoretable(number, empty1);
                    empty1 = 0;
                    number = 0;
                }
            }

            scoretmp += scoretable(number, empty1);
            return scoretmp;

        }

        /// <summary>
        /// 評估函數
        /// </summary>
        /// <returns></returns>
        public int evaluate_minmax_noalphabeta()
        {
            int scorecomputer = 0;
            int scorehumber = 0;

            //橫排們 
            for (int j = 0; j < 18; j++)
            {
                Piece[] pieces = new Piece[18];
                for (int i = 0; i < 18; ++i)
                    pieces[i] = new Piece(i, j);
                scorecomputer += countscore(pieces, 2);
                scorehumber += countscore(pieces, 1);
            }
            //豎排們
            for (int i = 0; i < 18; i++)
            {
                Piece[] pieces = new Piece[18];
                for (int j = 0; j < 18; j++)
                    pieces[j] = new Piece(i, j);
                scorecomputer += countscore(pieces, 2);
                scorehumber += countscore(pieces, 1);
            }

            //上半正斜線們 
            for (int i = 0; i < 18; ++i)
            {
                Piece[] pieces = new Piece[18];
                for (int x = i, y = 0; x < 18 && y < 18; x++, y++)
                    pieces[y] = new Piece(x, y);
                scorecomputer += countscore(pieces, 2);
                scorehumber += countscore(pieces, 1);
            }
            //下半正斜線們
            for (int j = 1; j < 18; ++j)
            {
                Piece[] pieces = new Piece[18];
                for (int x = 0, y = j; x < 18 && y < 18; y++, x++)
                    pieces[x] = new Piece(x, y);
                scorecomputer += countscore(pieces, 2);
                scorehumber += countscore(pieces, 1);
            }
            //上半反斜線們
            for (int i = 0; i < 18; i++)
            {
                Piece[] pieces = new Piece[18];
                for (int y = i, x = 0; y >= 0 && x < 18; y--, x++)
                    pieces[x] = new Piece(x, y);
                scorecomputer += countscore(pieces, 2);
                scorehumber += countscore(pieces, 1);
            }

            //下半反斜線們
            for (int i = 1; i < 18; i++)
            {
                Piece[] pieces = new Piece[18];
                for (int y = i, x = 14; y < 18 && x >= 0; x--, y++)
                    pieces[14 - x] = new Piece(y, x);
                scorecomputer += countscore(pieces, 2);
                scorehumber += countscore(pieces, 1);
            }

            return scorecomputer - scorehumber;
        }

        /// <summary>
        /// 當max(電腦)走步時,max(電腦)應該考慮最好的情況 
        /// </summary>
        /// <param name="depth">遞歸深度</param>
        /// <returns></returns>
        private int max_noalphabeta(int depth)
        {
            int res = evaluate_minmax_noalphabeta();
            int best = res;
            if (depth <= 0)
            {
                return res;
            }
            else
            {
                for (int i = 0; i < CheckBoard.BlankPieces.Count; i++)
                {
                    Piece p = CheckBoard.BlankPieces[i];
                    CheckBoard.ChessPieces[p.X][p.Y] = 1;
                    if (CheckBoard.isover(p.X, p.Y))
                    {
                        CheckBoard.ChessPieces[p.X][ p.Y] = 0;
                        return int.MaxValue;
                    }
                    RemoveBlankPiece(p);
                    int temp = min_noalphabeta(--depth);
                    if (temp > best) best = temp;
                    CheckBoard.BlankPieces.Insert(i, p);
                    CheckBoard.ChessPieces[p.X][ p.Y] = 0;
                }
                return best;
            }
        }

        /// <summary>
        /// 當min(人)走步時,人的最好情況
        /// </summary>
        /// <param name="depth">遞歸深度</param>
        /// <returns></returns>
        private int min_noalphabeta(int depth)
        {
            int res = evaluate_minmax_noalphabeta();
            int best = res;
            if (depth <= 0)
            {
                return res;
            }
            else
            {
                for (int i = 0; i < CheckBoard.BlankPieces.Count; i++)
                {
                    Piece p = CheckBoard.BlankPieces[i];
                    CheckBoard.ChessPieces[p.X][ p.Y] = 1;
                    if (CheckBoard.isover(p.X, p.Y))
                    {
                        CheckBoard.ChessPieces[p.X][p.Y] = 0;
                        return int.MinValue;
                    }
                    RemoveBlankPiece(p);
                    int temp = max_noalphabeta(--depth);
                    if (temp < best) best = temp;
                    CheckBoard.BlankPieces.Insert(i, p);
                    CheckBoard.ChessPieces[p.X][ p.Y] = 0;
                }
                return best;
            }
        }

        /// <summary>
        /// 人機博弈
        /// </summary>
        /// <param name="depth">遞歸深度</param>
        /// <returns></returns>
        public List<Piece> Machine_Man_Game(int depth)
        {
            generatepoint();
            List<Piece> bftPieces = new List<Piece>();
            int AI_best = int.MinValue;
            for (int i = 0; i < CheckBoard.BlankPieces.Count; i++)
            {
                Piece p = CheckBoard.BlankPieces[i];
                CheckBoard.ChessPieces[p.X][p.Y] = 2;
                if (CheckBoard.isover(p.X, p.Y))
                {
                    CheckBoard.ChessPieces[p.X][p.Y] = 0;
                    bftPieces.Add(p);
                    return bftPieces;
                }
                RemoveBlankPiece(p);
                int temp = min_noalphabeta(depth - 1);
                if (temp == AI_best)
                    bftPieces.Add(p);
                if (temp > AI_best)
                {
                    AI_best = temp;
                    bftPieces.Clear();
                    bftPieces.Add(p);
                }
                CheckBoard.BlankPieces.Insert(i, p);
                CheckBoard.ChessPieces[p.X][ p.Y] = 0;
            }
            return bftPieces;
        }
        /// <summary>
        /// 消除空子隊列中的一個
        /// </summary>
        /// <param name="p"></param>
        private void RemoveBlankPiece(Piece p)
        {
            for (int i = 0; i < CheckBoard.BlankPieces.Count; i++)
            {
                if (p.X == CheckBoard.BlankPieces[i].X && p.Y == CheckBoard.BlankPieces[i].Y)
                    CheckBoard.BlankPieces.RemoveAt(i);
            }
        }

    }
View Code

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章