示例#1
0
        public Action GetActionFromRule(MinesweeperRule mr)
        {
            height = mr.height;
            width  = mr.width;
            booms  = mr.booms;
            int[][]         curState      = mr.GetCurrentState();
            int[][]         aiView        = new int[height][];
            List <Position> blankList     = new List <Position>();
            List <Position> numberList    = new List <Position>();
            List <Position> blankBoundary = new List <Position>();
            List <Position> unknownBlank  = new List <Position>();
            Dictionary <Position, List <Position> > numberNearBlank = new Dictionary <Position, List <Position> >();
            Dictionary <Position, List <Position> > blankNearNumber = new Dictionary <Position, List <Position> >();
            int    remainBoom = mr.booms - mr.totalFlag;
            Random rd         = new Random();

            for (int i = 0; i < height; i++)
            {
                aiView[i] = new int[width];
                for (int j = 0; j < width; j++)
                {
                    if (curState[i][j] == MinesweeperRule.MS_blank || curState[i][j] == MinesweeperRule.MS_bombquestion)
                    {
                        aiView[i][j] = AI_blank;
                        blankList.Add(new Position(i, j));
                    }
                    else if (curState[i][j] >= MinesweeperRule.MS_open0 && curState[i][j] <= MinesweeperRule.MS_open8)
                    {
                        numberList.Add(new Position(i, j));
                        int boomAround = curState[i][j] - MinesweeperRule.MS_open0 - mr.CountBoomAround(i, j, curState, MinesweeperRule.MS_bombflagged);
                        if (boomAround > 0)
                        {
                            aiView[i][j] = boomAround;
                        }
                        else
                        {
                            aiView[i][j] = AI_open0;
                        }
                    }
                    else
                    {
                        aiView[i][j] = AI_wall;
                    }
                }
            }

            if (blankList.Count == height * width)
            {
                return(new Action {
                    x = rd.Next(height), y = rd.Next(width), mouse = 0
                });
            }

            if (blankList.Count == 0)
            {
                return(new Action {
                    x = 0, y = 0, mouse = -1
                });
            }

            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    if (aiView[i][j] == AI_blank)
                    {
                        Position        curPos      = new Position(i, j);
                        List <Position> nearNumbers = new List <Position>();

                        Position pos;
                        if (numberList.Contains(pos = new Position(i - 1, j - 1)))
                        {
                            nearNumbers.Add(pos);
                        }
                        if (numberList.Contains(pos = new Position(i - 1, j)))
                        {
                            nearNumbers.Add(pos);
                        }
                        if (numberList.Contains(pos = new Position(i - 1, j + 1)))
                        {
                            nearNumbers.Add(pos);
                        }
                        if (numberList.Contains(pos = new Position(i, j - 1)))
                        {
                            nearNumbers.Add(pos);
                        }
                        if (numberList.Contains(pos = new Position(i, j + 1)))
                        {
                            nearNumbers.Add(pos);
                        }
                        if (numberList.Contains(pos = new Position(i + 1, j - 1)))
                        {
                            nearNumbers.Add(pos);
                        }
                        if (numberList.Contains(pos = new Position(i + 1, j)))
                        {
                            nearNumbers.Add(pos);
                        }
                        if (numberList.Contains(pos = new Position(i + 1, j + 1)))
                        {
                            nearNumbers.Add(pos);
                        }

                        if (nearNumbers.Count > 0)
                        {
                            blankBoundary.Add(curPos);
                            numberNearBlank[curPos] = nearNumbers;
                            foreach (Position num in nearNumbers)
                            {
                                if (!blankNearNumber.ContainsKey(num))
                                {
                                    List <Position> nearBlanks = new List <Position>();
                                    if (blankList.Contains(pos = new Position(num.x - 1, num.y - 1)))
                                    {
                                        nearBlanks.Add(pos);
                                    }
                                    if (blankList.Contains(pos = new Position(num.x - 1, num.y)))
                                    {
                                        nearBlanks.Add(pos);
                                    }
                                    if (blankList.Contains(pos = new Position(num.x - 1, num.y + 1)))
                                    {
                                        nearBlanks.Add(pos);
                                    }
                                    if (blankList.Contains(pos = new Position(num.x, num.y - 1)))
                                    {
                                        nearBlanks.Add(pos);
                                    }
                                    if (blankList.Contains(pos = new Position(num.x, num.y + 1)))
                                    {
                                        nearBlanks.Add(pos);
                                    }
                                    if (blankList.Contains(pos = new Position(num.x + 1, num.y - 1)))
                                    {
                                        nearBlanks.Add(pos);
                                    }
                                    if (blankList.Contains(pos = new Position(num.x + 1, num.y)))
                                    {
                                        nearBlanks.Add(pos);
                                    }
                                    if (blankList.Contains(pos = new Position(num.x + 1, num.y + 1)))
                                    {
                                        nearBlanks.Add(pos);
                                    }

                                    blankNearNumber[num] = nearBlanks;
                                }
                            }
                        }
                        else
                        {
                            unknownBlank.Add(new Position(i, j));
                        }
                    }
                }
            }

            foreach (var pos in blankBoundary)
            {
                foreach (var num in numberNearBlank[pos])
                {
                    if (blankNearNumber[num].Count == aiView[num.x][num.y])
                    {
                        return(new Action {
                            x = pos.x, y = pos.y, mouse = 1
                        });                                                    // right click to pos
                    }
                    else if (AI_open0 == aiView[num.x][num.y])
                    {
                        return(new Action {
                            x = pos.x, y = pos.y, mouse = 0
                        });                                                    // left click to pos
                    }
                }
            }

            Dictionary <Position, double> estimations  = blankBoundary.ToDictionary(x => x, x => 0.0);
            List <List <Position> >       groupPosList = new List <List <Position> >();
            List <Position>  posList     = new List <Position>();
            Queue <Position> groupPosQue = new Queue <Position>();

            if (blankBoundary.Count > 0)
            {
                groupPosQue.Enqueue(blankBoundary.First());
            }
            while (blankBoundary.Count > 0 && groupPosQue.Count > 0)
            {
                var pos = groupPosQue.Dequeue();
                posList.Add(pos);
                blankBoundary.Remove(pos);
                foreach (var num in numberNearBlank[pos])
                {
                    foreach (var blank in blankNearNumber[num])
                    {
                        if (blankBoundary.Contains(blank) && !groupPosQue.Contains(blank))
                        {
                            groupPosQue.Enqueue(blank);
                        }
                    }
                }

                if (groupPosQue.Count == 0)
                {
                    groupPosList.Add(posList);
                    posList = new List <Position>();
                    if (blankBoundary.Count > 0)
                    {
                        groupPosQue.Enqueue(blankBoundary.First());
                    }
                }
            }

            double placedFlag = 0;
            double alpha      = 0.1;
            double epsilon    = 0.05;
            double addition   = 0;
            double max        = -1000;
            double est        = 0;
            double gama       = 0.9;

            foreach (var groupPos in groupPosList)
            {
                List <Position> numList = new List <Position>();
                foreach (var pos in groupPos)
                {
                    foreach (var num in numberNearBlank[pos])
                    {
                        if (!numList.Contains(num))
                        {
                            numList.Add(num);
                        }
                    }
                }

                List <double> placedFlagList = new List <double>();

                int enchos = groupPos.Count * 20;
                for (int count = 0; count < enchos; count++)
                {
                    if (count < enchos * 3 / 4)
                    {
                        epsilon = 0.05;
                    }
                    else
                    {
                        epsilon = 0;
                    }

                    List <Position>            tempGroupPos     = groupPos.ToList();
                    Dictionary <Position, int> actions          = groupPos.ToDictionary(x => x, x => 0); // 1: place flag, -1: don't place flag, 0: not yet action
                    List <Position>            positiveAction   = new List <Position>();
                    Dictionary <Position, int> numOfBlankAround = blankNearNumber.ToDictionary(x => x.Key, x => x.Value.Count);
                    int[][] tempAiView = aiView.Select(x => x.ToArray()).ToArray();
                    bool    isFirst    = true;

                    while (true)
                    {
                        bool checkWrong = false;
                        for (int i = 0; i < numList.Count; i++)
                        {
                            if (tempAiView[numList[i].x][numList[i].y] < 0 || tempAiView[numList[i].x][numList[i].y] > numOfBlankAround[numList[i]])
                            {
                                checkWrong = true;
                                break;
                            }
                        }
                        if (checkWrong)
                        {
                            gama = 1;
                            // update estimatios when wrong
                            for (int i = 0; i < positiveAction.Count; i++)
                            {
                                var pos = positiveAction[i];
                                estimations[pos] += alpha * gama * ((-1) * actions[pos] - estimations[pos]);
                                gama             *= 0.8;
                            }

                            break;
                        }
                        if (!actions.Values.Contains(0))
                        {
                            // update estimatios when success
                            int hs = 1;
                            if (estimations.Values.Where(x => x == 1).Count() > remainBoom)
                            {
                                hs = -1;
                            }

                            gama = 1;
                            for (int i = 0; i < positiveAction.Count; i++)
                            {
                                var pos = positiveAction[i];
                                estimations[pos] += alpha * gama * (hs * actions[pos] - estimations[pos]);
                                gama             *= 0.8;
                            }

                            placedFlagList.Add(actions.Values.Where(x => x == 1).Count());

                            break;
                        }

                        List <Position> needNoFlagList = new List <Position>();
                        foreach (var num in numList)
                        {
                            if (tempAiView[num.x][num.y] == 0)
                            {
                                foreach (var blank in blankNearNumber[num])
                                {
                                    if (actions[blank] == 0 && !needNoFlagList.Contains(blank))
                                    {
                                        needNoFlagList.Add(blank);
                                    }
                                }
                            }
                        }

                        if (needNoFlagList.Count > 0)
                        {
                            foreach (var blank in needNoFlagList)
                            {
                                actions[blank] = -1;
                                tempGroupPos.Remove(blank);
                                foreach (var num in numberNearBlank[blank])
                                {
                                    numOfBlankAround[num]--;
                                }
                            }
                            continue;
                        }

                        List <Position> needFlagList = new List <Position>();
                        foreach (var num in numList)
                        {
                            if (tempAiView[num.x][num.y] == numOfBlankAround[num])
                            {
                                foreach (var blank in blankNearNumber[num])
                                {
                                    if (actions[blank] == 0 && !needFlagList.Contains(blank))
                                    {
                                        needFlagList.Add(blank);
                                    }
                                }
                            }
                        }

                        if (needFlagList.Count > 0)
                        {
                            foreach (var blank in needFlagList)
                            {
                                actions[blank] = 1;
                                tempGroupPos.Remove(blank);
                                foreach (var num in numberNearBlank[blank])
                                {
                                    numOfBlankAround[num]--;
                                    tempAiView[num.x][num.y]--;
                                }
                            }
                            continue;
                        }

                        if (isFirst)
                        {
                            Position pos = groupPos[rd.Next(groupPos.Count)];
                            int      act = rd.Next(2) * 2 - 1;
                            actions[pos] = act;
                            tempGroupPos.Remove(pos);
                            positiveAction.Add(pos);
                            foreach (var num in numberNearBlank[pos])
                            {
                                numOfBlankAround[num]--;
                                if (act == 1)
                                {
                                    tempAiView[num.x][num.y]--;
                                }
                            }
                            isFirst = false;
                        }
                        else
                        {
                            if (rd.NextDouble() < epsilon)
                            {
                                Position pos = tempGroupPos[rd.Next(tempGroupPos.Count)];
                                int      act = rd.Next(2) * 2 - 1;
                                actions[pos] = act;
                                tempGroupPos.Remove(pos);
                                positiveAction.Add(pos);
                                foreach (var num in numberNearBlank[pos])
                                {
                                    numOfBlankAround[num]--;
                                    if (act == 1)
                                    {
                                        tempAiView[num.x][num.y]--;
                                    }
                                }
                            }
                            else
                            {
                                List <Position> bestChoiceList = new List <Position>();
                                max = -1000;
                                foreach (var pos in tempGroupPos)
                                {
                                    est = estimations[pos] < 0 ? -estimations[pos] : estimations[pos];
                                    if (est > max)
                                    {
                                        max            = est;
                                        bestChoiceList = new List <Position>();
                                        bestChoiceList.Add(pos);
                                    }
                                    else if (est == max)
                                    {
                                        bestChoiceList.Add(pos);
                                    }
                                }

                                Position bestChoice = bestChoiceList[rd.Next(bestChoiceList.Count)];
                                int      act        = estimations[bestChoice] >= 0 ? 1 : -1;
                                actions[bestChoice] = act;
                                tempGroupPos.Remove(bestChoice);
                                positiveAction.Add(bestChoice);
                                foreach (var num in numberNearBlank[bestChoice])
                                {
                                    numOfBlankAround[num]--;
                                    if (act == 1)
                                    {
                                        tempAiView[num.x][num.y]--;
                                    }
                                }
                            }
                        }
                    }
                }

                if (placedFlagList.Count > 0)
                {
                    placedFlag += placedFlagList.Sum() * 1.0 / placedFlagList.Count;
                }
                else
                {
                    addition += groupPos.Count;
                }
            }

            List <Position> bestPosList = new List <Position>();

            max = -1000;
            foreach (var pos in estimations.Keys)
            {
                est = estimations[pos] < 0 ? -estimations[pos] : estimations[pos];
                if (est > max)
                {
                    max         = est;
                    bestPosList = new List <Position>();
                    bestPosList.Add(pos);
                }
                else if (est == max)
                {
                    bestPosList.Add(pos);
                }
            }

            Position bestPos = new Position(0, 0);

            if (bestPosList.Count > 0)
            {
                bestPos = bestPosList[rd.Next(bestPosList.Count)];
            }

            est = 0;
            if (unknownBlank.Count > 0)
            {
                est = (remainBoom - placedFlag) * 1.0 / (unknownBlank.Count + addition) * 2 - 1;
                foreach (var blk in unknownBlank)
                {
                    estimations[blk] = est;
                }
            }

            if (max < 0.9 && est > max)
            {
                bestPos = unknownBlank[rd.Next(unknownBlank.Count)];
            }

            return(new Action {
                x = bestPos.x, y = bestPos.y, mouse = estimations[bestPos] >= 0 ? 1 : 0
            });
        }