예제 #1
0
        private static int GetStrongestOpponent(IEnumerable <IOpponent> opponents) // Get opponent with lowest pile height
        {
            int strongest           = -1;
            int strongestPileHeight = 1000;

            foreach (IOpponent opponent in opponents)
            {
                int pileHeight = BoardHelper.GetPileMaxHeight(opponent.Board);
                if (pileHeight < strongestPileHeight)
                {
                    strongestPileHeight = pileHeight;
                    strongest           = opponent.PlayerId;
                }
            }
            return(strongest);
        }
예제 #2
0
        private static int GetWeakestOpponent(IEnumerable <IOpponent> opponents) // Get opponent with highest pile height
        {
            int weakest           = -1;
            int weakestPileHeight = -1000;

            foreach (IOpponent opponent in opponents)
            {
                int pileHeight = BoardHelper.GetPileMaxHeight(opponent.Board);
                if (pileHeight > weakestPileHeight)
                {
                    weakest           = opponent.PlayerId;
                    weakestPileHeight = pileHeight;
                }
            }
            return(weakest);
        }
예제 #3
0
        private static double EvaluteMove(IBoard board, IPiece piece)
        {
            int pieceMinX;
            int pieceMinY;
            int pieceMaxX;
            int pieceMaxY;

            piece.GetAbsoluteBoundingRectangle(out pieceMinX, out pieceMinY, out pieceMaxX, out pieceMaxY);

            int totalHeight              = BoardHelper.GetTotalCellHeight(board);
            int completedRows            = BoardHelper.GetTotalCompletedRows(board);
            int totalHoles               = Enumerable.Range(1, board.Width).Aggregate(0, (i, i1) => i + BoardHelper.GetBuriedHolesForColumn(board, i1));
            int totalBlockades           = Enumerable.Range(1, board.Width).Aggregate(0, (i, i1) => i + BoardHelper.GetBlockadesForColumn(board, i1));
            int edgeTouchingAnotherBlock = 0; // TODO
            int edgeTouchingWall         = 0; // TODO
            int edgeTouchingFloor        = 0;

            //double rating = 0;
            //rating += -0.03 * totalHeight;
            //rating += -7.5 * totalHoles;
            //rating += -3.5 * totalBlockades;
            //rating += 8.0 * completedRows;
            //rating += 3.0 * edgeTouchingAnotherBlock;
            //rating += 2.5 * edgeTouchingWall;
            //rating += 5.0 * edgeTouchingFloor;
            //double rating = 0;
            //rating += -3.78 * totalHeight;
            //rating += -2.31 * totalHoles;
            //rating += -0.59 * totalBlockades;
            //rating += 1.6 * completedRows;
            //rating += 3.97 * edgeTouchingAnotherBlock;
            //rating += 6.52 * edgeTouchingWall;
            //rating += 0.65 * edgeTouchingFloor;
            double rating = 0;

            rating += -0.868099 * totalHeight;
            rating += -2.45402 * totalHoles;
            rating += -0.236702 * totalBlockades;
            rating += 3.59764 * completedRows;
            rating += 5.33378 * edgeTouchingAnotherBlock;
            rating += 8.20521 * edgeTouchingWall;
            rating += 0.00 * edgeTouchingFloor;

            return(rating);
        }
예제 #4
0
        private static int GetStrongestOpponentWithNukeSwitchGravity(IEnumerable <IOpponent> opponents) // Search among opponents which one has a nuke/switch/gravity and the lowest board
        {
            int id = -1;
            int lowestPileHeight = 1000;

            foreach (IOpponent opponent in opponents)
            {
                if (opponent.Board.Cells.Any(x => CellHelper.GetSpecial(x) == Specials.SwitchFields || CellHelper.GetSpecial(x) == Specials.NukeField || CellHelper.GetSpecial(x) == Specials.BlockGravity))
                {
                    int pileHeight = BoardHelper.GetPileMaxHeight(opponent.Board);
                    if (pileHeight < lowestPileHeight)
                    {
                        id = opponent.PlayerId;
                        lowestPileHeight = pileHeight;
                    }
                }
            }
            return(id);
        }
예제 #5
0
        private static int GetStrongestOpponentWithBomb(IEnumerable <IOpponent> opponents) // Search among opponents which one has a bomb and the lowest board
        {
            int id = -1;
            int lowestPileHeight = 1000;

            foreach (IOpponent opponent in opponents)
            {
                if (opponent.Board.Cells.Any(x => CellHelper.IsSpecial(x) && CellHelper.GetSpecial(x) == Specials.BlockBomb))
                {
                    int pileHeight = BoardHelper.GetPileMaxHeight(opponent.Board);
                    if (pileHeight < lowestPileHeight)
                    {
                        id = opponent.PlayerId;
                        lowestPileHeight = pileHeight;
                    }
                }
            }
            return(id);
        }
예제 #6
0
        private static int GetStrongestOpponentWithBombOnBottomLine(IEnumerable <IOpponent> opponents) // Search among opponents which one has a bomb on bottom line and the lowest board
        {
            int id = -1;
            int lowestPileHeight = 1000;

            foreach (IOpponent opponent in opponents)
            {
                for (int x = 1; x <= opponent.Board.Width; x++)
                {
                    Specials cellSpecial = CellHelper.GetSpecial(opponent.Board[x, 0]);
                    if (cellSpecial == Specials.BlockBomb)
                    {
                        int pileHeight = BoardHelper.GetPileMaxHeight(opponent.Board);
                        if (pileHeight < lowestPileHeight)
                        {
                            id = opponent.PlayerId;
                            lowestPileHeight = pileHeight;
                        }
                        break;
                    }
                }
            }
            return(id);
        }
예제 #7
0
        public bool GetBestMove(IBoard board, IPiece current, IPiece next, out int bestRotationDelta, out int bestTranslationDelta, out bool rotationBeforeTranslation)
        {
            int    currentBestTranslationDelta = 0;
            int    currentBestRotationDelta    = 0;
            double currentBestRating           = -1.0e+20; // Really bad!

            //if (current.PosY == board.Height) // TODO: put current totally in board before trying to get best move
            //    current.Translate(0, -1);

            IBoard tempBoard = board.Clone();
            IPiece tempPiece = current.Clone();

            //Log.Default.WriteLine(LogLevels.Debug, "Get Best Move for Piece {0} {1}", tempPiece.Value, tempPiece.Index);

            // Consider all possible rotations
            for (int trialRotationDelta = 0; trialRotationDelta < current.MaxOrientations; trialRotationDelta++)
            {
                // Copy piece
                tempPiece.CopyFrom(current);
                // Rotate
                tempPiece.Rotate(trialRotationDelta);

                // Get translation range
                bool isMovePossible;
                int  minDeltaX;
                int  maxDeltaX;
                BoardHelper.GetAccessibleTranslationsForOrientation(board, tempPiece, out isMovePossible, out minDeltaX, out maxDeltaX);

                //Log.Default.WriteLine(LogLevels.Debug, "Accessible translation {0} {1} {2} {3} {4}  {5} {6}", minDeltaX, maxDeltaX, trialRotationDelta, current.PosX, current.PosY, tempPiece.Value, tempPiece.Index);

                //StringBuilder sb = new StringBuilder();
                //for (int i = 1; i <= tempPiece.TotalCells; i++)
                //{
                //    int x, y;
                //    tempPiece.GetCellAbsolutePosition(i, out x, out y);
                //    sb.Append(String.Format("[{0}->{1},{2}]", i, x - tempPiece.PosX, y - tempPiece.PosY));
                //}
                //Log.Log.Default.WriteLine("{0} {1} -> {2}  {3}", trialRotationDelta, minDeltaX, maxDeltaX, sb.ToString());
                if (isMovePossible)
                {
                    // Consider all allowed translations
                    for (int trialTranslationDelta = minDeltaX; trialTranslationDelta <= maxDeltaX; trialTranslationDelta++)
                    {
                        // Evaluate this move

                        // Copy piece
                        tempPiece.CopyFrom(current);
                        // Rotate
                        tempPiece.Rotate(trialRotationDelta);
                        // Translate
                        tempPiece.Translate(trialTranslationDelta, 0);

                        // Check if move is acceptable
                        if (board.CheckNoConflict(tempPiece))
                        {
                            // Copy board
                            tempBoard.CopyFrom(board);
                            // Drop piece
                            tempBoard.DropAndCommit(tempPiece);

                            // Evaluate
                            double trialRating = EvaluteMove(tempBoard, tempPiece);

                            //Log.Log.Default.WriteLine("R:{0:0.0000} P:{1} R:{2} T:{3}", trialRating, trialRotationDelta, trialTranslationDelta);

                            // Check if better than previous best
                            if (trialRating > currentBestRating)
                            {
                                currentBestRating           = trialRating;
                                currentBestTranslationDelta = trialTranslationDelta;
                                currentBestRotationDelta    = trialRotationDelta;
                            }
                        }
                    }
                }
            }

            // Commit to this move
            rotationBeforeTranslation = true;
            bestTranslationDelta      = currentBestTranslationDelta;
            bestRotationDelta         = currentBestRotationDelta;

            // Log.Default.WriteLine(LogLevels.Debug, "{0} {1} {2:0.000}", bestRotationDelta, bestTranslationDelta, currentBestRating);

            return(true);
        }
예제 #8
0
        // The following evaluation function was adapted from Pascal code submitted by:
        // Pierre Dellacherie (France).  (E-mail : [email protected])
        //
        // This amazing one-piece algorithm completes an average of roughly 600 000
        // rows, and often attains 2 000 000 or 2 500 000 rows.  However, the algorithm
        // sometimes completes as few as 15 000 rows.  I am fairly certain that this
        // is NOT due to statistically abnormal patterns in the falling piece sequence.
        //
        // Pierre Dellacherie corresponded with me via e-mail to help me with the
        // conversion of his Pascal code to C++.
        //
        // WARNING:
        //     If there is a single board and piece combination with the highest
        //     'rating' value, it is the best combination.  However, among
        //     board and piece combinations with EQUAL 'rating' values,
        //     the highest 'priority' value wins.
        //
        //     So, the complete rating is: { rating, priority }.
        private static void EvaluteMove(IBoard board, IPiece piece, out double rating, out int priority)
        {
            int pieceMinX;
            int pieceMinY;
            int pieceMaxX;
            int pieceMaxY;

            piece.GetAbsoluteBoundingRectangle(out pieceMinX, out pieceMinY, out pieceMaxX, out pieceMaxY);

            // Landing Height (vertical midpoint)
            double landingHeight = 0.5 * (pieceMinY + pieceMaxY);

            //
            int completedRows          = BoardHelper.GetTotalCompletedRows(board);
            int erodedPieceCellsMetric = 0;

            if (completedRows > 0)
            {
                // Count piece cells eroded by completed rows before doing collapse on pile.
                int countPieceCellsEliminated = BoardHelper.CountPieceCellsEliminated(board, piece, true);

                // Now it's okay to collapse completed rows
                board.CollapseCompletedRows();

                // Weight eroded cells by completed rows
                erodedPieceCellsMetric = (completedRows * countPieceCellsEliminated);
            }

            //
            int pileHeight = BoardHelper.GetPileMaxHeight(board);

            // Each empty row (above pile height) has two (2) "transitions"
            // (We could call ref_Board.GetTransitionCountForRow( y ) for
            // these unoccupied rows, but this is an optimization.)
            int boardRowTransitions = 2 * (board.Height - pileHeight);

            // Only go up to the pile height, and later we'll account for the
            // remaining rows transitions (2 per empty row).
            for (int y = 1; y <= pileHeight; y++)
            {
                boardRowTransitions += BoardHelper.GetTransitionCountForRow(board, y);
            }

            //
            int boardColumnTransitions = 0;
            int boardBuriedHoles       = 0;
            int boardWells             = 0;

            for (int x = 1; x <= board.Width; x++)
            {
                boardColumnTransitions += BoardHelper.GetTransitionCountForColumn(board, x);
                boardBuriedHoles       += BoardHelper.GetBuriedHolesForColumn(board, x);
                boardWells             += BoardHelper.GetAllWellsForColumn(board, x);
            }

            // Final rating
            //   [1] Punish landing height
            //   [2] Reward eroded piece cells
            //   [3] Punish row    transitions
            //   [4] Punish column transitions
            //   [5] Punish buried holes (cellars)
            //   [6] Punish wells

            rating  = 0.0;
            rating += -1.0 * landingHeight;
            rating += 1.0 * erodedPieceCellsMetric;
            rating += -1.0 * boardRowTransitions;
            rating += -1.0 * boardColumnTransitions;
            rating += -4.0 * boardBuriedHoles;
            rating += -1.0 * boardWells;

            // PRIORITY:
            //   Priority is further differentiation between possible moves.
            //   We further rate moves accoding to the following:
            //            * Reward deviation from center of board
            //            * Reward pieces to the left of center of the board
            //            * Punish rotation
            //   Priority is less important than the rating, but among equal
            //   ratings we select the option with the greatest priority.
            //   In principle we could simply factor priority in to the rating,
            //   as long as the priority was less significant than the smallest
            //   variations in rating, but for large board widths (>100), the
            //   risk of loss of precision in the lowest bits of the rating
            //   is too much to tolerate.  So, this priority is stored in a
            //   separate variable.

            int absoluteDistanceX = Math.Abs(piece.PosX - board.PieceSpawnX);

            priority  = 0;
            priority += (100 * absoluteDistanceX);
            if (piece.PosX < board.PieceSpawnX)
            {
                priority += 10;
            }
            priority -= piece.Orientation - 1;
        }
예제 #9
0
        private double EvaluteMove(IBoard board, IPiece piece, out int bestRotationDelta, out int bestTranslationDelta)
        {
            int    currentBestTranslationDelta = 0;
            int    currentBestRotationDelta    = 0;
            double currentBestRating           = -1.0e+20; // Really bad!
            int    currentBestPriority         = 0;

            //current.Translate(0, -1);

            IBoard tempBoard = board.Clone();
            IPiece tempPiece = piece.Clone();

            // Consider all possible rotations
            for (int trialRotationDelta = 0; trialRotationDelta < piece.MaxOrientations; trialRotationDelta++)
            {
                // Copy piece
                tempPiece.CopyFrom(piece);
                // Rotate
                tempPiece.Rotate(trialRotationDelta);

                // Get translation range
                bool isMovePossible;
                int  minDeltaX;
                int  maxDeltaX;
                BoardHelper.GetAccessibleTranslationsForOrientation(board, tempPiece, out isMovePossible, out minDeltaX, out maxDeltaX);

                //StringBuilder sb = new StringBuilder();
                //for (int i = 1; i <= tempPiece.TotalCells; i++)
                //{
                //    int x, y;
                //    tempPiece.GetCellAbsolutePosition(i, out x, out y);
                //    sb.Append(String.Format("[{0}->{1},{2}]", i, x - tempPiece.PosX, y - tempPiece.PosY));
                //}
                //Log.Log.Default.WriteLine("{0} {1} -> {2}  {3}", trialRotationDelta, minDeltaX, maxDeltaX, sb.ToString());
                if (isMovePossible)
                {
                    // Consider all allowed translations
                    for (int trialTranslationDelta = minDeltaX; trialTranslationDelta <= maxDeltaX; trialTranslationDelta++)
                    {
                        // Evaluate this move

                        // Copy piece
                        tempPiece.CopyFrom(piece);
                        // Rotate
                        tempPiece.Rotate(trialRotationDelta);
                        // Translate
                        tempPiece.Translate(trialTranslationDelta, 0);

                        // Check if move is acceptable
                        if (board.CheckNoConflict(tempPiece))
                        {
                            // Copy board
                            tempBoard.CopyFrom(board);
                            // Drop piece
                            tempBoard.DropAndCommit(tempPiece);

                            tempBoard.CollapseCompletedRows();

                            double trialRating = 0;
                            trialRating += -0.65 * BoardHelper.GetTotalShadowedHoles(board);
                            trialRating += -0.10 * BoardHelper.GetPileHeightWeightedCells(board);
                            trialRating += -0.20 * BoardHelper.GetSumOfWellHeights(board);

                            // Check if better than previous best
                            if (trialRating > currentBestRating)
                            {
                                currentBestRating           = trialRating;
                                currentBestTranslationDelta = trialTranslationDelta;
                                currentBestRotationDelta    = trialRotationDelta;
                            }
                        }
                    }
                }
            }
            // Commit to this move
            bestTranslationDelta = currentBestTranslationDelta;
            bestRotationDelta    = currentBestRotationDelta;

            return(currentBestRating);
        }
예제 #10
0
        public bool MultiplayerMode(IBoard board, List <Specials> inventory, int inventoryMaxSize, IEnumerable <IOpponent> opponents, List <SpecialAdvice> advices)
        {
            // Get strongest opponent
            int strongest = GetStrongestOpponent(opponents);

            // Get current special
            Specials special = inventory[0];

            inventory.RemoveAt(0);

            //
            switch (special)
            {
            // Destroy own board and switch with strongest opponent
            case Specials.SwitchFields:     // TODO:
                Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Keep S for survival");
                // NOP
                break;

            // Wait
            case Specials.BlockGravity:
            case Specials.NukeField:
                Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Keep {0} for survival", special.ToString());
                // NOP
                break;

            // Send to strongest opponent
            case Specials.AddLines:
                Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Use A on strongest {0}", strongest);
                advices.Add(new SpecialAdvice
                {
                    SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseOpponent,
                    OpponentId          = strongest
                });

                break;

            //  Send to strongest opponent with a bomb
            //  If none,
            //      if inventory almost full, drop
            //      else NOP
            case Specials.BlockBomb:
            {
                int bombTarget = GetStrongestOpponentWithBomb(opponents);
                if (bombTarget != -1)
                {
                    Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]use O to {0}", bombTarget);
                    advices.Add(new SpecialAdvice
                        {
                            SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseOpponent,
                            OpponentId          = bombTarget
                        });
                }
                else
                {
                    if (inventory.Count + 2 >= inventoryMaxSize)
                    {
                        Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Discard O, inventory almost full");
                        advices.Add(new SpecialAdvice
                            {
                                SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.Discard,
                            });
                    }
                    else
                    {
                        Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Keep O for later");
                    }
                }
                break;
            }

            //  Send to opponent with Nuke/Gravity/Switch on bottom line
            //  If none, send to opponent with Bomb on bottom line
            //  If none, send to opponent with most specials on bottom line
            //  If none,
            //      if we have Nuke/Gravity/Switch/Bomb on bottom line, drop
            //      else, send to ourself
            case Specials.ClearLines:
            {
                int targetId = GetStrongestOpponentWithNukeSwitchGravityOnBottomLine(opponents);
                if (targetId != -1)
                {
                    Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Use C on opponent with N/G/S on bottom line {0}", targetId);
                    advices.Add(new SpecialAdvice
                        {
                            SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseOpponent,
                            OpponentId          = targetId
                        });
                }
                else
                {
                    targetId = GetStrongestOpponentWithBombOnBottomLine(opponents);
                    if (targetId != -1)
                    {
                        Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Use C on opponent with O on bottom line {0}", targetId);
                        advices.Add(new SpecialAdvice
                            {
                                SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseOpponent,
                                OpponentId          = targetId
                            });
                    }
                    else
                    {
                        targetId = GetOpponentWithMostSpecialsOnBottomLine(opponents);
                        if (targetId != -1)
                        {
                            Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Use C on opponent with most specials on bottom line {0}", targetId);
                            advices.Add(new SpecialAdvice
                                {
                                    SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseOpponent,
                                    OpponentId          = targetId
                                });
                        }
                        else
                        {
                            bool hasValuableSpecialOnBottomLine = HasNukeGravitySwitchOnBottomLine(board);
                            if (hasValuableSpecialOnBottomLine)
                            {
                                Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Discard C, we have N/G/S on bottom line");
                                advices.Add(new SpecialAdvice
                                    {
                                        SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.Discard,
                                    });
                            }
                            else
                            {
                                Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Use C on ourself");
                                advices.Add(new SpecialAdvice
                                    {
                                        SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseSelf,
                                    });
                            }
                        }
                    }
                }
                break;
            }

            //  if we have a Bomb in our board and no Gravity/Nuke in inventory, send to ourself
            //  send to opponent with Nuke/Gravity/Switch
            //  if none,
            //      if second special is Bomb
            //          if an opponent has a bomb,
            //              send to opponent with most specials and no bomb
            //              if none, drop
            //          else
            //              send to opponent with most specials
            //              if none,
            //                  if inventory almost full, drop
            //                  else NOP
            //      else
            //          send to opponent with Bomb
            //          if none, send to opponent with most specials
            //          if none,
            //              if inventory almost full, drop
            //              else NOP
            case Specials.ClearSpecialBlocks:
            {
                bool hasBomb = HasSpecial(board, Specials.BlockBomb);
                if (hasBomb && !inventory.Any(x => x == Specials.NukeField || x == Specials.BlockGravity))
                {
                    Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Use B on ourself, we have O in board and no N/G in inventory");
                    advices.Add(new SpecialAdvice
                        {
                            SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseSelf,
                        });
                }
                else
                {
                    int targetId = GetStrongestOpponentWithNukeSwitchGravity(opponents);
                    if (targetId != -1)
                    {
                        Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Use B on strongest opponent with N/S/G {0}", targetId);
                        advices.Add(new SpecialAdvice
                            {
                                SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseOpponent,
                                OpponentId          = targetId
                            });
                    }
                    else
                    {
                        if (inventory.Any() && inventory[0] == Specials.BlockBomb)
                        {
                            bool hasOpponentWithBomb = HasOpponentWithBomb(opponents);
                            if (hasOpponentWithBomb)
                            {
                                targetId = GetOpponentWithMostSpecialsAndNoBomb(opponents);
                                if (targetId != -1)
                                {
                                    Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Use B on opponent with most specials and no O {0}, we have O in inventory", targetId);
                                    advices.Add(new SpecialAdvice
                                        {
                                            SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseOpponent,
                                            OpponentId          = targetId
                                        });
                                }
                                else
                                {
                                    Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Discard B, no opponents without O and we have O in inventory", targetId);
                                    advices.Add(new SpecialAdvice
                                        {
                                            SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.Discard,
                                        });
                                }
                            }
                            else
                            {
                                targetId = GetOpponentWithMostSpecials(opponents);
                                if (targetId != -1)
                                {
                                    Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Use B on opponent with most specials {0}", targetId);
                                    advices.Add(new SpecialAdvice
                                        {
                                            SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseOpponent,
                                            OpponentId          = targetId
                                        });
                                }
                                else
                                {
                                    if (inventory.Count + 2 >= inventoryMaxSize)
                                    {
                                        Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Discard B, inventory is almost full");
                                        advices.Add(new SpecialAdvice
                                            {
                                                SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.Discard,
                                            });
                                    }
                                    else
                                    {
                                        Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Keep B for later");
                                    }
                                }
                            }
                        }
                        else
                        {
                            targetId = GetStrongestOpponentWithBomb(opponents);
                            if (targetId != -1)
                            {
                                Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Use B on opponent with O {0}, we don't have any O", targetId);
                                advices.Add(new SpecialAdvice
                                    {
                                        SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseOpponent,
                                        OpponentId          = targetId
                                    });
                            }
                            else
                            {
                                targetId = GetOpponentWithMostSpecials(opponents);
                                if (targetId != -1)
                                {
                                    Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Use B on opponent with most specials {0}", targetId);
                                    advices.Add(new SpecialAdvice
                                        {
                                            SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseOpponent,
                                            OpponentId          = targetId
                                        });
                                }
                                else
                                {
                                    if (inventory.Count + 2 >= inventoryMaxSize)
                                    {
                                        Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Discard B, inventory is almost full");
                                        advices.Add(new SpecialAdvice
                                            {
                                                SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.Discard,
                                            });
                                    }
                                    else
                                    {
                                        Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Keep B for later");
                                    }
                                }
                            }
                        }
                    }
                }
                break;
            }

            //  send to opponent with Nuke/Gravity/Switch
            //  if none, send to strongest opponent
            case Specials.RandomBlocksClear:
            {
                int targetId = GetStrongestOpponentWithNukeSwitchGravity(opponents);
                if (targetId != -1)
                {
                    Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Use R on strongest opponent with N/S/G {0}", targetId);
                    advices.Add(new SpecialAdvice
                        {
                            SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseOpponent,
                            OpponentId          = targetId
                        });
                }
                else
                {
                    targetId = GetStrongestOpponent(opponents);
                    if (targetId != -1)
                    {
                        Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Use R on strongest opponent {0}", targetId);
                        advices.Add(new SpecialAdvice
                            {
                                SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseOpponent,
                                OpponentId          = targetId
                            });
                    }
                    else
                    {
                        Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Keep R for later **** SHOULD NEVER HAPPEN");
                    }
                }
                break;
            }

            // send to weakest opponent
            case Specials.Immunity:
            {
                int targetId = GetWeakestOpponent(opponents);
                if (targetId != -1)
                {
                    IBoard lastOpponentBoard = opponents.First(x => x.PlayerId == targetId).Board;
                    if (lastOpponentBoard != null)
                    {
                        int pileHeight = BoardHelper.GetPileMaxHeight(lastOpponentBoard);
                        if (pileHeight >= 10)
                        {
                            Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Use I on weakest opponent (board {0}) {1}", pileHeight, targetId);
                            advices.Add(new SpecialAdvice
                                {
                                    SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseOpponent,
                                    OpponentId          = targetId
                                });
                        }
                        else if (inventory.Count + 2 >= inventoryMaxSize)
                        {
                            Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Discard I, inventory is almost full");
                            advices.Add(new SpecialAdvice
                                {
                                    SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.Discard,
                                });
                        }
                        else
                        {
                            Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Keep I for later");
                        }
                    }
                }
                break;
            }
            // TODO
            //  if first special is Quake,
            //      send to opponent with most towers or strongest opponent [TO BE DEFINED]
            // ClearColumn
            // Darkness
            // Confusion
            // ZebraField

            // Send to strongest opponent
            default:
            {
                int targetId = GetStrongestOpponent(opponents);
                if (targetId != -1)
                {
                    Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Use {0} on strongest opponent {1}", special.ToString(), targetId);
                    advices.Add(new SpecialAdvice
                        {
                            SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseOpponent,
                            OpponentId          = targetId
                        });
                }
                else
                {
                    Log.Default.WriteLine(LogLevels.Debug, "[NORMAL]Keep {0} for later **** SHOULD NEVER HAPPEN", special.ToString());
                }
                break;
            }
            }
            return(true);
        }
예제 #11
0
        public bool PanicMode(List <Specials> inventory, IEnumerable <IOpponent> opponents, List <SpecialAdvice> advices)
        {
            // Survival
            // If Nuke/Gravity/Switch
            if (inventory.Any(x => x == Specials.NukeField || x == Specials.BlockGravity || x == Specials.SwitchFields))
            {
                Log.Default.WriteLine(LogLevels.Debug, "[SURVIVAL] Found N/G/S in inventory");
                bool saved = false;
                while (true)
                {
                    if (!inventory.Any())
                    {
                        break; // Stops when inventory is empty
                    }
                    // Get strongest opponent
                    int strongest = GetStrongestOpponent(opponents);
                    // Get current special
                    Specials special = inventory[0];
                    inventory.RemoveAt(0);
                    switch (special)
                    {
                    case Specials.NukeField:     // Nuke/Gravity -> use it immediately
                    case Specials.BlockGravity:
                        Log.Default.WriteLine(LogLevels.Debug, "[SURVIVAL]Use {0}", special.ToString());
                        advices.Add(new SpecialAdvice
                        {
                            SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseSelf,
                        });
                        saved = true;     // Saved, stop emptying inventory
                        break;

                    case Specials.SwitchFields:     // Switch -> use it only if strongest is really strong, else drop it
                    {
                        IBoard strongestBoard = opponents.First(x => x.PlayerId == strongest).Board;
                        int    pileHeight     = BoardHelper.GetPileMaxHeight(strongestBoard);
                        if (pileHeight <= 10)
                        {
                            Log.Default.WriteLine(LogLevels.Debug, "[SURVIVAL]Use S, found a valid opponent {0} with a pile {1}", strongest, pileHeight);
                            advices.Add(new SpecialAdvice
                                {
                                    SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseOpponent,
                                    OpponentId          = strongest
                                });
                            saved = true;         // Saved, stop emptying inventory
                        }
                        else
                        {
                            Log.Default.WriteLine(LogLevels.Debug, "[SURVIVAL]Discard S, no valid opponent");
                            advices.Add(new SpecialAdvice
                                {
                                    SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.Discard,
                                });
                        }
                        break;
                    }

                    case Specials.ClearLines:     // ClearLine -> use it immediately  TODO ==> this could lead to unwanted behaviour if we are emptying for a switch
                        Log.Default.WriteLine(LogLevels.Debug, "[SURVIVAL]Use C on ourself");
                        advices.Add(new SpecialAdvice
                        {
                            SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseSelf,
                        });
                        break;

                    default:     // Other -> use it on strongest
                        Log.Default.WriteLine(LogLevels.Debug, "[SURVIVAL]Use {0} on strongest opponent {1}", special, strongest);
                        advices.Add(new SpecialAdvice
                        {
                            SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseOpponent,
                            OpponentId          = strongest
                        });

                        break;
                    }

                    if (saved) // If saved or something wrong with UseSpecial, stop loop
                    {
                        break;
                    }

                    System.Threading.Thread.Sleep(10); // delay next special use
                }
                Log.Default.WriteLine(LogLevels.Debug, "[SURVIVAL] Survival mode N/G/S finished. saved:{0}", saved);
            }
            // Nothing could save use, send everything to weakest and pray
            else
            {
                Log.Default.WriteLine(LogLevels.Debug, "[SURVIVAL] No N/G/S found -> use everything on weakest and try to kill him");
                while (true)
                {
                    if (!inventory.Any())
                    {
                        break; // Stops when inventory is empty
                    }
                    // Get strongest opponent
                    int weakest = GetWeakestOpponent(opponents);
                    // Get current special
                    Specials special = inventory[0];
                    inventory.RemoveAt(0);
                    // ClearLine -> use it immediately
                    if (special == Specials.ClearLines)
                    {
                        Log.Default.WriteLine(LogLevels.Debug, "[SURVIVAL]Use C on ourself");
                        advices.Add(new SpecialAdvice
                        {
                            SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseSelf,
                        });
                    }
                    // Other -> use it on weakest
                    else
                    {
                        Log.Default.WriteLine(LogLevels.Debug, "[SURVIVAL]Use {0} on weakest opponent {1}", special.ToString(), weakest);
                        advices.Add(new SpecialAdvice
                        {
                            SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseOpponent,
                            OpponentId          = weakest
                        });
                    }
                }
            }
            return(true);
        }
예제 #12
0
        public bool SoloMode(IBoard board, List <Specials> inventory, int inventoryMaxSize, List <SpecialAdvice> advices)
        {
            //  drop everything except Nuke/Gravity/ClearLines
            //  use clear line if no nuke/gravity on bottom line and board not empty or when reaching top of board or when inventory is full
            //  use nuke when reaching top of board
            //  use gravity when reaching mid-board

            Specials special = inventory.First();

            int maxPile = BoardHelper.GetPileMaxHeight(board);

            switch (special)
            {
            case Specials.NukeField:
                if (maxPile >= 14)
                {
                    advices.Add(new SpecialAdvice
                    {
                        SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseSelf,
                    });
                }
                break;

            case Specials.BlockGravity:
                if (maxPile >= 10)
                {
                    advices.Add(new SpecialAdvice
                    {
                        SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseSelf,
                    });
                }
                break;

            case Specials.ClearLines:
            {
                bool hasValuableBottomLine = HasNukeGravityOnBottomLine(board);
                if ((!hasValuableBottomLine && maxPile > 4) || maxPile >= 14)
                {
                    advices.Add(new SpecialAdvice
                        {
                            SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseSelf,
                        });
                }
                else if (maxPile >= 10 || inventory.Count + 2 >= inventoryMaxSize)
                {
                    advices.Add(new SpecialAdvice
                        {
                            SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseSelf,
                        });
                }
                break;
            }

            default:
                advices.Add(new SpecialAdvice
                {
                    SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.Discard,
                });
                break;
            }
            return(true);
        }
예제 #13
0
        // TODO: helpers should return IOpponent instead of int
        // TODO: when confusion is activated, bot doesn't do anything
        // TODO: immunity

        public bool GetSpecialAdvices(IBoard board, IPiece current, IPiece next, IEnumerable <Specials> inventory, int inventoryMaxSize, IEnumerable <IOpponent> opponents, out List <SpecialAdvice> advices)
        {
            // if solo,
            //  drop everything except Nuke/Gravity/ClearLines
            //  use clear line if no nuke/gravity on bottom line or when reaching top of board or when inventory is full
            //  use nuke when reaching top of board
            //  use gravity when reaching mid-board
            // Survival first:
            //  if we are to high (above 14),
            //      if we have Nuke or Gravity or Switch in inventory, send offensive specials to strongest opponent (lowest board) + send ClearLine to ourself until getting Nuke/Gravity/Switch
            //          use Nuke or Gravity on ourself -> send to ourself ==> saved
            //          use Switch
            //              if strongest opponent board is below 10 -> send to opponent => saved
            //              else drop it and continue to search for a Nuke or Gravity
            //      else,
            //          empty inventory by sending offensive specials to weakest opponent (highest board) + sending ClearLine to ourself -> not saved
            // If we are saved,
            //  if there is only one player left, and we have enough AddLines to kill him, drop everything except AddLines, Quake, Confusion, Darkness and send them to last opponent
            //  if first special is Switch, destroy own board and switch with strongest opponent (TODO)
            //  if first special is Nuke or Gravity, NOP
            //  if first special is AddLines, send to strongest opponent
            //  if first special is Bomb,
            //      send to strongest opponent with a bomb
            //      if none, NOP
            //  if first special is ClearLine,
            //      send to opponent with Nuke/Gravity/Switch on bottom line
            //      if none, send to opponent with Bomb on bottom line
            //      if none, send to opponent with most specials on bottom line
            //      if none,
            //          if we have Nuke/Gravity/Switch/Bomb on bottom line, drop
            //          else, send to ourself
            //  if first special is ClearSpecialBlocks,
            //      if we have a Bomb in our board and no Gravity/Nuke in inventory, send to ourself
            //      send to opponent with Nuke/Gravity/Switch
            //      if none,
            //          if second special is Bomb
            //              if an opponent has a bomb,
            //                  send to opponent with most specials and no bomb
            //                  if none, drop
            //              else
            //                  send to opponent with most specials
            //                  if none, NOP
            //          else
            //              send to opponent with Bomb
            //              if none, send to opponent with most specials
            //              if none, NOP
            //  if first special is RandomBlocksClear,
            //      send to opponent with Nuke/Gravity/Switch
            //      if none, send to strongest opponent
            //  if first special is Quake,
            //      send to opponent with most towers or strongest opponent [TO BE DEFINED]
            //  if first special is Immunity,
            //      send to weakest opponent
            // TODO: zebra, clear column, confusion

            //
            advices = new List <SpecialAdvice>();

            // clone inventory

            List <Specials> internalInventory = inventory.ToList();

            // No inventory
            if (!internalInventory.Any())
            {
                return(false);
            }

            if (!opponents.Any())
            {
                // Solo
                return(SoloMode(board, internalInventory, inventoryMaxSize, advices));
            }
            int maxPile = BoardHelper.GetPileMaxHeight(board);

            if (maxPile >= 14)
            {
                // Survival
                return(PanicMode(internalInventory, opponents, advices));
            }
            else
            {
                // Normal use

                // Check if we can kill last player
                int lastOpponent = GetLastOpponent(opponents);
                if (lastOpponent != -1)
                {
                    IBoard lastOpponentBoard = opponents.First(x => x.PlayerId == lastOpponent).Board;
                    if (lastOpponentBoard != null)
                    {
                        int pileHeight    = BoardHelper.GetPileMaxHeight(lastOpponentBoard);
                        int addLinesCount = internalInventory.Count(x => x == Specials.AddLines);
                        if (addLinesCount > 0 && pileHeight + addLinesCount >= lastOpponentBoard.Height)
                        {
                            // Finish him
                            return(OneOpponentMode(lastOpponent, internalInventory, advices));
                        }
                    }
                }

                return(MultiplayerMode(board, internalInventory, inventoryMaxSize, opponents, advices));
            }


            #region Simple strategy

            ////  if negative special,
            ////      if no other player, drop it
            ////      else, use it on random opponent
            ////  else if switch, drop it
            ////  else, use it on ourself
            //Specials firstSpecial = inventory[0];
            //int specialValue = 0;
            //switch (firstSpecial)
            //{
            //    case Specials.AddLines:
            //        specialValue = -1;
            //        break;
            //    case Specials.ClearLines:
            //        specialValue = +1;
            //        break;
            //    case Specials.NukeField:
            //        specialValue = +1;
            //        break;
            //    case Specials.RandomBlocksClear:
            //        specialValue = -1;
            //        break;
            //    case Specials.SwitchFields:
            //        specialValue = 0;
            //        break;
            //    case Specials.ClearSpecialBlocks:
            //        specialValue = -1;
            //        break;
            //    case Specials.BlockGravity:
            //        specialValue = +1;
            //        break;
            //    case Specials.BlockQuake:
            //        specialValue = -1;
            //        break;
            //    case Specials.BlockBomb:
            //        specialValue = -1;
            //        break;
            //    case Specials.ClearColumn:
            //        specialValue = -1;
            //        break;
            //    case Specials.ZebraField:
            //        specialValue = -1;
            //        break;
            //}
            //if (specialValue == 0)
            //    advices.Add(new SpecialAdvice
            //                            {
            //                                SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.Discard,
            //                            });
            //else if (specialValue > 0)
            //    advices.Add(new SpecialAdvice
            //    {
            //        SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseSelf,
            //    });
            //else
            //{
            //    if (opponents.Any())
            //    {
            //        // Get strongest opponent
            //        int strongest = GetStrongestOpponent(opponents);
            //        advices.Add(new SpecialAdvice
            //        {
            //            SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.UseOpponent,
            //            OpponentId = strongest,
            //        });
            //    }
            //    else
            //        advices.Add(new SpecialAdvice
            //        {
            //            SpecialAdviceAction = SpecialAdvice.SpecialAdviceActions.Discard,
            //        });
            //}

            #endregion
        }
        public bool GetBestMove(IBoard board, IPiece current, IPiece next, out int bestRotationDelta, out int bestTranslationDelta, out bool rotationBeforeTranslation)
        {
            int    currentBestTranslationDelta = 0;
            int    currentBestRotationDelta    = 0;
            double currentBestRating           = -1.0e+20; // Really bad!
            int    currentBestPriority         = 0;

            //current.Translate(0, -1);

            IBoard tempBoard = board.Clone();
            IPiece tempPiece = current.Clone();

            // Consider all possible rotations
            for (int trialRotationDelta = 0; trialRotationDelta < current.MaxOrientations; trialRotationDelta++)
            {
                // Copy piece
                tempPiece.CopyFrom(current);
                // Rotate
                tempPiece.Rotate(trialRotationDelta);

                // Get translation range
                bool isMovePossible;
                int  minDeltaX;
                int  maxDeltaX;
                BoardHelper.GetAccessibleTranslationsForOrientation(board, tempPiece, out isMovePossible, out minDeltaX, out maxDeltaX);

                StringBuilder sb = new StringBuilder();
                for (int i = 1; i <= tempPiece.TotalCells; i++)
                {
                    int x, y;
                    tempPiece.GetCellAbsolutePosition(i, out x, out y);
                    sb.Append(String.Format("[{0}->{1},{2}]", i, x - tempPiece.PosX, y - tempPiece.PosY));
                }
                //Log.Log.Default.WriteLine("{0} {1} -> {2}  {3}", trialRotationDelta, minDeltaX, maxDeltaX, sb.ToString());
                if (isMovePossible)
                {
                    // Consider all allowed translations
                    for (int trialTranslationDelta = minDeltaX; trialTranslationDelta <= maxDeltaX; trialTranslationDelta++)
                    {
                        // Evaluate this move

                        // Copy piece
                        tempPiece.CopyFrom(current);
                        // Rotate
                        tempPiece.Rotate(trialRotationDelta);
                        // Translate
                        tempPiece.Translate(trialTranslationDelta, 0);

                        // Check if move is acceptable
                        if (board.CheckNoConflict(tempPiece))
                        {
                            // Copy board
                            tempBoard.CopyFrom(board);
                            // Drop piece
                            tempBoard.DropAndCommit(tempPiece);

                            // Evaluate
                            double trialRating;
                            int    trialPriority;
                            EvaluteMove(tempBoard, tempPiece, out trialRating, out trialPriority);

                            //Log.Log.Default.WriteLine("R:{0:0.0000} P:{1} R:{2} T:{3}", trialRating, trialPriority, trialRotationDelta, trialTranslationDelta);

                            // Check if better than previous best
                            if (trialRating > currentBestRating || (Math.Abs(trialRating - currentBestRating) < 0.0001 && trialPriority > currentBestPriority))
                            {
                                currentBestRating           = trialRating;
                                currentBestPriority         = trialPriority;
                                currentBestTranslationDelta = trialTranslationDelta;
                                currentBestRotationDelta    = trialRotationDelta;
                            }
                        }
                    }
                }
            }

            // commit to this move
            rotationBeforeTranslation = true;
            bestTranslationDelta      = currentBestTranslationDelta;
            bestRotationDelta         = currentBestRotationDelta;

            //Console.SetCursorPosition(0, _client.Board.Height+1);
            // Console.WriteLine("{0} {1} {2:0.000} {3}", bestRotationDelta, bestTranslationDelta, currentBestRating, currentBestPriority);

            return(true);
        }