C# winform GDI+ 五子棋 (二):根据博弈算法写的人机AI(抄的别人的)

2022/7/31 14:25:35

本文主要是介绍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

 



这篇关于C# winform GDI+ 五子棋 (二):根据博弈算法写的人机AI(抄的别人的)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程