예제 #1
0
        // 1. Drawing
        private void drawDbg(gamestate state, Font font, String text, SolidBrush brush)
        {
            int x = state.Column;
            int y = state.Row;

            int xx = 8 + x * state.squares[x, y].SizeH;
            int yy = 8 + y * state.squares[x, y].SizeV;

            String score = "";

            if (Math.Abs(state.AIValue) == gameboard.WINNING_SCORE)
            {
                if (state.AIValue == -gameboard.WINNING_SCORE)
                {
                    score = "WIN 2";
                }
                else
                {
                    score = "WIN 1";
                }
            }
            else
            {
                score = state.AIValue.ToString();
            }

            device.DrawString(score + text, font, brush, xx, yy);

            dbgStateArray[x, y] = state;
        }
예제 #2
0
        //Constructors
        public gamestate(gamestate ParentState, int column, int sizeW, int sizeH)
        {
            // Set parent state
            parent = ParentState;

            //Set ID
            id  = parent.ID;
            id += "-";
            id += column.ToString();

            // Set squares
            squares = new Square[sizeW, sizeH];

            for (int x = 0; x < sizeW; x++)
            {
                for (int y = 0; y < sizeH; y++)
                {
                    squares[x, y] = new Square(60, ParentState.squares[x, y].Owner);
                }
            }

            // Set columns used
            columnused = column;

            rowused = 0;
            while (rowused < sizeH)
            {
                if (squares[columnused, rowused].Owner != 0)
                {
                    break;
                }
                rowused++;
            }
            rowused--;
        }  // Used to set a state based on a parent
예제 #3
0
        public void DumpState(gamestate state)
        {
            Bitmap   bmp    = new Bitmap(widthPixels + 2 * this.spacer, heightPixels + 2 * this.spacer);
            Graphics device = Graphics.FromImage(bmp);

            draw(device);

            gamestate  currState = state;
            Font       font      = new Font("Arial", 30);
            String     fileName  = "";
            SolidBrush sb1       = new SolidBrush(Color.Red);
            SolidBrush sb2       = new SolidBrush(Color.Blue);

            int cnt = 1;

            while (currState != null)
            {
                currState = currState.Parent;
                cnt++;
            }

            currState = state;
            while (currState != null)
            {
                //device.FillEllipse(SquareBrush, , , this.squares[x, y].SizeH - 16, this.squares[x, y].SizeV - 16);
                int x = currState.Column;
                int y = 0;
                while (y < sizeHeight)
                {
                    if (currState.squares[x, y].Owner != 0)
                    {
                        break;
                    }
                    y++;
                }

                int        xx = this.Spacer + 8 + x * this.squares[x, y].SizeH;
                int        yy = this.Spacer + 8 + y * this.squares[x, y].SizeV;
                SolidBrush sb;
                if (currState.squares[x, y].Owner == 1)
                {
                    sb = sb1;
                }
                else
                {
                    sb = sb2;
                }
                device.DrawString((cnt - 1).ToString(), font, sb, xx, yy);

                fileName += currState.Column.ToString();

                currState = currState.Parent;

                cnt--;
            }

            bmp.Save("A" + fileName + ".png");
            bmp.Dispose();
        }
예제 #4
0
 //1.2 Supportive function that clears all AIStates.
 public void ClearAIStates(gamestate state)
 {
     for (int i = 0; i < state.children.Count; i++)
     {
         ClearAIStates(state.children[i]);
     }
     state.children.Clear();
 }
예제 #5
0
        //C1. Supportive function that checks all moves in a gamestate
        // public List<int> GenerateListOfMoves(gamestate StateOfBoard)
        // {

        // return list;
        //}

        //C2. Supportive function that returns the first empty gamestate on a given depth

        //C3. Supportive function that places the token in the new Gamestate
        public void PlaceToken(gamestate Board, int Column, int Player)
        {
            for (int i = sizeHeight - 1; i >= 0; i--)
            {
                if (Board.squares[Column, i].Owner == 0)
                {
                    Board.squares[Column, i].Owner = Player;
                    break;
                }
            }
        }
예제 #6
0
 private void cbDebug_CheckedChanged(object sender, EventArgs e)
 {
     if (cbDebug.Checked)
     {
         currentDbgState = gameboard.AIRootState;
         if (dbgStateArray == null)
         {
             dbgStateArray = new gamestate[gameboard.Width, gameboard.Height];
         }
     }
     drawall();
 }
예제 #7
0
        //=============================//
        //          AI Methods         //
        //=============================//

        //1. The general movement function, just places the square and times the thinking time.
        public void placeSquareAI(Label label1, int ColumnUsed, int MaxDepth)
        {
            //Start timer
            Stopwatch Timer = new Stopwatch();

            Timer.Start();

            //Check if moves can be made
            if (checkFull())
            {
                MessageBox.Show("Table is full!");
            }
            else
            {
                // Clear created gamestates
                if (AIRootState != null)
                {
                    ClearAIStates(AIRootState);
                }

                //determine column

                //  Create gamestate
                AIRootState = new gamestate(squares, ColumnUsed, sizeWidth, sizeHeight);

                //  Determine AI move
                AIMove AI = new AIMove();
                AI = RecursiveMiniMaxAI(0, MaxDepth, AIRootState, 2); //Recursive Mini Max Move

                //Place token
                int row = placeTokenAI(AI.Move);

                //Check win
                if (checkWin(AI.Move, row, activeplayer, squares, 3))
                {
                    gamewon();
                }

                //Change player
                activeplayer = 1;
            }

            Timer.Stop();
            label1.Text = "Time elapsed: " + Timer.ElapsedMilliseconds.ToString() + " ms";
            Timer.Reset();
        }
예제 #8
0
        private void pnlMain_MouseClick(object sender, MouseEventArgs e)
        {
            if (gameboard == null)
            {
                return;
            }

            decimal X = (e.X) / gameboard.squares[0, 0].SizeH;
            decimal Y = (e.Y) / gameboard.squares[0, 0].SizeV;

            X = Math.Floor(X);
            Y = Math.Floor(Y);

            int xSquare = Convert.ToInt32(X);
            int ySquare = Convert.ToInt32(Y);

            if (cbDebug.Checked)
            {
                if (dbgStateArray[xSquare, ySquare] != null)
                {
                    currentDbgState = dbgStateArray[xSquare, ySquare];
                }
            }
            else if (gameboard.gameRun)
            {
                //Check Correct click
                if (gameboard.CheckCorrectClick(xSquare))
                {
                    gameboard.placeSquare(xSquare, ySquare, gameboard.activePlayer);

                    //Player 2 moves (AI move)
                    if (gameboard.activePlayer == 2)
                    {
                        gameboard.placeSquareAI(label1, xSquare, (int)nudMaxDepth.Value);
                    }
                    button2.Enabled = true;
                }
            }
            drawall();
        }
예제 #9
0
        //C4. Evaluates the board for a given gamestate
        public int EvaluateBoard(gamestate Board, int ColumnUsed)
        {
            //Determine the highest placed fiche and call checkwin on that fiche
            for (int y = 0; y < sizeHeight; y++)
            {
                if (Board.squares[ColumnUsed, y].Owner != 0)
                {
                    int score = GetScore(ColumnUsed, y, Board.squares[ColumnUsed, y].Owner, Board.squares);

                    if (Board.squares[ColumnUsed, y].Owner == 1)
                    {
                        return(score);
                    }
                    else
                    {
                        return(-score);
                    }
                }
            }

            return(0);
        }
예제 #10
0
        //C. AI movement three, recursive minimax
        public AIMove RecursiveMiniMaxAI(int Depth, int MaxDepth, gamestate StateOfBoard, int Player)
        {
            AIMove ReturnMove = new AIMove();

            //BestScore & Move
            AIMove BestMove = new AIMove(-1, 0);

            if (Player == 2) // Minimizing
            {
                BestMove.Score = 99999;
            }
            else
            {
                BestMove.Score = -99999;
            }

            if (Depth == MaxDepth)
            //We are at the bottom of the search space and evaluate this level
            {
                ReturnMove.Score = EvaluateBoard(StateOfBoard, StateOfBoard.Column);
                ReturnMove.Move  = StateOfBoard.Column;
            }

            else
            {
                int score = EvaluateBoard(StateOfBoard, StateOfBoard.Column);

                if (Math.Abs(score) == WINNING_SCORE)
                {
                    ReturnMove.Score = score;
                    ReturnMove.Move  = StateOfBoard.Column;
                }
                else
                {
                    //Check for possible moves
                    List <int>    MoveList         = new List <int>();
                    List <AIMove> EqualGoodReturns = new List <AIMove>();
                    for (int column = 0; column < squares.GetLength(0); column++)
                    {
                        if (StateOfBoard.squares[column, 0].Owner == 0)
                        {
                            MoveList.Add(column);
                        }
                    }

                    //Execute a minimax on each child
                    for (int k = 0; k < MoveList.Count; k++)
                    {
                        //Make a move and create a new gamestate
                        gamestate newState = new gamestate(StateOfBoard, MoveList[k], sizeWidth, sizeHeight);
                        StateOfBoard.children.Add(newState);

                        //Place a token in the new Gamestate
                        PlaceToken(newState, MoveList[k], Player);

                        //Call minimax on the child
                        ReturnMove = RecursiveMiniMaxAI(Depth + 1, MaxDepth, newState, Player == 1 ? 2 : 1);

                        newState.AIValue = ReturnMove.Score;

                        if (Player == 2)  // Minimizing
                        {
                            if (ReturnMove.Score < BestMove.Score)
                            {
                                EqualGoodReturns.Clear();
                                EqualGoodReturns.Add(new AIMove(MoveList[k], ReturnMove.Score));
                                BestMove.Score = ReturnMove.Score;
                                BestMove.Move  = MoveList[k]; //Changed this from ReturnMove
                            }
                            else if (ReturnMove.Score == BestMove.Score)
                            {
                                EqualGoodReturns.Add(new AIMove(MoveList[k], ReturnMove.Score));
                            }
                        }
                        else
                        {
                            //Evaluate return
                            if (ReturnMove.Score > BestMove.Score)
                            {
                                EqualGoodReturns.Clear();
                                EqualGoodReturns.Add(new AIMove(MoveList[k], ReturnMove.Score));
                                BestMove.Score = ReturnMove.Score;
                                BestMove.Move  = MoveList[k]; //Changed this from ReturnMove
                            }
                            else if (ReturnMove.Score == BestMove.Score)
                            {
                                EqualGoodReturns.Add(new AIMove(MoveList[k], ReturnMove.Score));
                            }
                        }
                    }
                    if (EqualGoodReturns.Count == 1 || EqualGoodReturns.Count == 0)
                    {
                        ReturnMove = BestMove;
                    }
                    else
                    {
                        Random rnd = new Random();
                        ReturnMove = EqualGoodReturns[rnd.Next(EqualGoodReturns.Count)];
                    }
                }
            }

            //string Data2;
            //Data2 = ReturnMove.Score.ToString();
            //Data2 += "/";
            //Data2 += ReturnMove.Move.ToString();
            //Trace.WriteLine("ReturnScore & Move: " + Data2 + " || At Depth " + Depth.ToString());

            if (writeDbg)
            {
                if (Depth == MaxDepth && ReturnMove.Score != 0)
                {
                    //for (int i = 0; i < Depth; i++)
                    //    dbgText += "\t";
                    gamestate currState = StateOfBoard;
                    while (currState != null)
                    {
                        dbgText  += "AI[" + currState.AIValue + "] COL[" + currState.Column + "]\t";
                        currState = currState.Parent;
                    }
                    //dbgText += Environment.NewLine;
                    dbgText += "P:" + Player.ToString() + "  Col:" + StateOfBoard.Column.ToString() + "  BestMove:" + ReturnMove.Move.ToString() + "  BestScore:" + ReturnMove.Score.ToString() + Environment.NewLine;

                    if (ReturnMove.Score > 100 && false)
                    {
                        DumpState(StateOfBoard);
                    }
                }
            }

            return(ReturnMove);
        }