예제 #1
0
        // plays randomly
        private Board Random_Bot(Board b)
        {
            while (true)
            {
                Random rnd = new Random();
                if (b.AddPiece(2, rnd.Next(0, 7)))
                {
                    break;
                }
            }

            return(b);
        }
예제 #2
0
        // helper for minimax alg, recursively determines move strength
        private int moveStrength(Board b, int move, int depth)
        {
            int   currentPlayer = b.Turn;
            Board copy          = (Board)b.Copy();

            if (copy.AddPiece(copy.Turn, move))
            {
                // if this move would spell an immediate win for either player
                int winner = copy.Winner();
                if (winner != 0)
                {
                    // return the id of the current player * 10, with depth added
                    return((currentPlayer * 100) + depth);
                    //return (currentPlayer * 10);
                }
            }
            // if the move is illegal, return -1
            else
            {
                return(-1);
            }

            // base case: if depth has hit 0 (and no immediate win after this move established by previous step)
            if (depth == 0)
            {
                return(0);
            }
            // otherwise, begin searching further through moves
            else
            {
                bool tieAvailable          = false;
                int  strongestMoveStrength = 0;
                int  bestBadMoveStrength   = 0;

                for (int c = 0; c < 7; c++)
                {
                    int nextMoveStrength = moveStrength(copy, c, depth - 1);
                    // if the next move will ultimately result in a loss for currentPlayer, mark it as such
                    if ((nextMoveStrength / 100) == copy.Turn && nextMoveStrength > strongestMoveStrength)
                    {
                        strongestMoveStrength = nextMoveStrength;
                    }
                    // if at least one of the next moves will continue towards a potential victory for currentPlayer
                    else if (nextMoveStrength == 0)
                    {
                        tieAvailable = true;
                    }
                    else if (nextMoveStrength > bestBadMoveStrength)
                    {
                        bestBadMoveStrength = nextMoveStrength;
                    }
                }
                if (strongestMoveStrength > 0)
                {
                    return(strongestMoveStrength);
                }
                else if (tieAvailable)
                {
                    return(0);
                }
                else
                {
                    return(bestBadMoveStrength);
                }
            }
        }
예제 #3
0
        // Same minimax algorithm but optimized with multithreading
        private Board FasterMiniMax_Bot(Board b, int depth)
        {
            Array.Fill(strengths, -1);

            Console.WriteLine("\nthinking...\n");

            int bestWinningMove         = -1;
            int bestWinningMoveStrength = 0;

            int bestAlternateMove         = -1;
            int bestAlternateMoveStrength = 1000;

            depth += (7 - b.ValidMoveCount());

            Console.WriteLine("Searching at depth " + depth + "...");

            List <Thread> threads = new List <Thread>();

            for (int i = 0; i < 7; i++)
            {
                Thread   t    = new Thread(new ParameterizedThreadStart(MeasureStrength));
                MoveData data = new MoveData(b, i, depth);
                t.Start(data);
                threads.Add(t);
            }
            foreach (var thread in threads)
            {
                thread.Join();
            }

            for (int move = 0; move < 7; move++)
            {
                //int strength = moveStrength(b, move, depth);
                if (strengths[move] != -1)
                {
                    Console.WriteLine("Strength of move " + move + ": " + strengths[move]);

                    if ((strengths[move] / 100) == 2 && strengths[move] > bestWinningMoveStrength)
                    {
                        bestWinningMove         = move;
                        bestWinningMoveStrength = strengths[move];
                    }
                    else if (strengths[move] == 0 || ((strengths[move] / 100) == 1 && strengths[move] < bestAlternateMoveStrength))
                    {
                        bestAlternateMove         = move;
                        bestAlternateMoveStrength = strengths[move];
                    }
                }
            }

            if (bestWinningMove != -1)   // if there is a winning move to play, play the strongest one
            {
                //Console.WriteLine("\npursuing winning move: " + bestWinningMove);
                b.AddPiece(2, bestWinningMove);
                return(b);
            }
            else                        // if there is no winning move, play the optimal alternate one
            {
                //Console.WriteLine("\npursuing optimal alternate move: " + bestAlternateMove + " (strength " + bestAlternateMoveStrength + ")");
                b.AddPiece(2, bestAlternateMove);
                return(b);
            }
        }
예제 #4
0
        // uses a more intuitive approach in combination with minimax algorithm to search for the strongest move
        private Board BetterMiniMax_Bot(Board b)
        {
            Console.WriteLine("thinking...");

            int bestWinningMove         = -1;
            int bestWinningMoveStrength = 0;

            int bestAlternateMove         = -1;
            int bestAlternateMoveStrength = 1000;

            List <int> tieMoves = new List <int> {
            };

            for (int move = 0; move < 7; move++)
            {
                // hardcoded depth of 6 move lookahead
                int strength = moveStrength(b, move, 6);
                if (strength != -1)
                {
                    //Console.WriteLine("Strength of move " + move + ": " + strength);

                    if ((strength / 100) == 2 && strength > bestWinningMoveStrength)
                    {
                        bestWinningMove         = move;
                        bestWinningMoveStrength = strength;
                    }
                    else if (strength == 0 || ((strength / 100) == 1 && strength < bestAlternateMoveStrength))
                    {
                        bestAlternateMove         = move;
                        bestAlternateMoveStrength = strength;
                        if (strength == 0)
                        {
                            tieMoves.Add(move);
                        }
                    }
                }
            }

            if (bestWinningMove != -1)   // if there is a winning move to play, play the strongest one
            {
                Console.WriteLine("Pursuing CPU win");
                b.AddPiece(2, bestWinningMove);
                return(b);
            }
            else if (bestAlternateMoveStrength > 0)    // if all moves are losing, play the optimal LEAST WEAK move
            {
                Console.WriteLine("Pursuing optimal losing move");
                b.AddPiece(2, bestAlternateMove);
                return(b);
            }


            ////////////////////////////////////////////////////////////////////////////////
            // ----- Otherwise, some moves suggest tie, so play more intuitively... ----- //
            ////////////////////////////////////////////////////////////////////////////////


            Console.WriteLine("moves to consider:");
            printIntList(tieMoves);

            // if only one move is not losing, play it
            if (tieMoves.Count == 1)
            {
                b.AddPiece(2, tieMoves[0]);
                return(b);
            }

            // Otherwise, determine which of tying moves is optimal

            // ideal columns to have pieces in, ordered from most ideal to least ideal
            int[] idealColumns = { 3, 2, 4, 1, 5, 0, 6 };

            for (int i = 0; i < idealColumns.Length; i++)
            {
                if (tieMoves.Contains(idealColumns[i]))
                {
                }
            }

            // placeholder, just play first available tie move
            b.AddPiece(2, tieMoves[0]);
            return(b);
        }
예제 #5
0
        // Continues to prompt users to play until a win or save occurs
        // Returns a "w" for win or a "s" for save
        public string PlayGame(Board b, int saveTurn)
        {
            bool   win    = false;
            bool   placed = false;
            string x;
            int    VarCol;
            int    VarRow;

            //Initialize the players
            Player player = new Player()
            {
                piece      = 'X',
                turnNumber = 0
            };
            Player playerTwo = new Player()
            {
                piece      = '0',
                turnNumber = 1
            };
            int turn = saveTurn;

            //Loops through a series of asking player one and two to input a location
            //Assumes the location input is always formatted as 'row# col#' w/o error checking
            do
            {
                //Player One plays
                if (turn == 0)
                {
                    b.DisplayBoard();
                    Console.WriteLine("Player One choose your location, row then column, or input save to save game");
                    Console.WriteLine("(for row 1 column 1 put: 1 1)");
                    x = SaveGame(Console.ReadLine(), b, player);
                    if (x == "save")
                    {
                        return("s");
                    }

                    // Try to get input
                    try
                    {
                        VarRow = Convert.ToInt32(x.Split(' ')[0]);
                        VarCol = Convert.ToInt32(x.Split(' ')[1]);
                        placed = b.AddPiece(VarRow, VarCol, player, b);
                        turn   = 1;
                    }

                    //Catch any incorrect input and continue playing
                    catch (Exception)
                    {
                        Console.WriteLine("Invalid location: try again");
                        PlayGame(b, turn);
                    }

                    // If location was input correctly but is occupied
                    while (placed == false)
                    {
                        Console.WriteLine("Player One invalid location choose another location, row then column");
                        x = Console.ReadLine();
                        try
                        {
                            VarRow = Convert.ToInt32(x.Split(' ')[0]);
                            VarCol = Convert.ToInt32(x.Split(' ')[1]);
                            placed = b.AddPiece(VarRow, VarCol, player, b);
                            turn   = 1;
                        }
                        catch (Exception)
                        {
                            Console.WriteLine("Invalid location: try again");
                            PlayGame(b, turn);
                        }
                    }
                    win = b.CheckWin(b, player);

                    // if Player One won
                    if (win == true)
                    {
                        b.DisplayBoard();
                        break;
                    }
                }

                //Player Two plays
                if (turn == 1)
                {
                    b.DisplayBoard();
                    Console.WriteLine("Player Two choose your location, row then column, or input save to save game");
                    x = SaveGame(Console.ReadLine(), b, playerTwo);
                    if (x == "save")
                    {
                        return("s");
                    }

                    // Try to get input
                    try
                    {
                        VarRow = Convert.ToInt32(x.Split(' ')[0]);
                        VarCol = Convert.ToInt32(x.Split(' ')[1]);
                        placed = b.AddPiece(VarRow, VarCol, playerTwo, b);
                        turn   = 0;
                    }

                    //Catch any incorrect input and continue playing
                    catch (Exception)
                    {
                        Console.WriteLine("Invalid location: try again");
                        PlayGame(b, turn);
                    }

                    // If location was input correctly but is occupied
                    while (placed == false)
                    {
                        Console.WriteLine("Player Two invalid location choose another location");
                        x = Console.ReadLine();
                        try
                        {
                            VarRow = Convert.ToInt32(x.Split(' ')[0]);
                            VarCol = Convert.ToInt32(x.Split(' ')[1]);
                            placed = b.AddPiece(VarRow, VarCol, playerTwo, b);
                            turn   = 0;
                        }
                        catch (Exception)
                        {
                            Console.WriteLine("Invalid location: try again");
                            PlayGame(b, turn);
                        }
                    }
                    win = b.CheckWin(b, playerTwo);

                    if (win == true)
                    {
                        b.DisplayBoard();
                    }
                }
            } while (win == false);

            return("w");
        }