Beispiel #1
0
 /// <summary>
 /// Returns the possible bonus cards for the specified board.
 /// </summary>
 public static void GetPossibleBonusCardIndexes(ulong maxCardIndex, ref ByteList12 cardIndexes)
 {
     byte maxBonusCardIndex = (byte)(maxCardIndex - 3);
     for(byte cardIndex = 4; cardIndex <= maxBonusCardIndex; cardIndex++)
         cardIndexes.Add(cardIndex);
 }
        /// <summary>
        /// Returns the quality value for shifting the specified board in the specified direction.
        /// Returns null if shifting in that direction is not possible.
        /// </summary>
        private unsafe float?EvaluateMoveForBoard(FastBoard board, FastDeck deck, ulong knownNextCardIndex, ShiftDirection dir, int recursionsLeft, ref long movesEvaluated)
        {
            FastBoard    shiftedBoard = board;
            IntVector2D *newCardCells = stackalloc IntVector2D[4];

            if (shiftedBoard.ShiftInPlace(dir, newCardCells))
            {
                float totalQuality = 0;
                float totalWeight  = 0;

                if (knownNextCardIndex == ulong.MaxValue)                // Special value for bonus card.
                {
                    ByteList12 indexes = new ByteList12();
                    Game.GetPossibleBonusCardIndexes(board.GetMaxCardIndex(), ref indexes);
                    for (int i = 0; i < indexes.Count; i++)
                    {
                        ulong cardIndex = indexes.Items[i];
                        for (int j = 0; j < 4; j++)
                        {
                            IntVector2D cell = newCardCells[j];
                            if (cell.X < 0)
                            {
                                continue;
                            }

                            FastBoard newBoard = shiftedBoard;
                            newBoard.SetCardIndex(cell, cardIndex);

                            float quality;
                            if (recursionsLeft == 0 || GetBestMoveForBoard(newBoard, deck, 0, recursionsLeft - 1, out quality, ref movesEvaluated) == null)
                            {
                                quality = _evaluator(newBoard);
                                movesEvaluated++;
                            }

                            totalQuality += quality;
                            totalWeight  += 1;
                        }
                    }
                }
                else if (knownNextCardIndex > 0)
                {
                    FastDeck newDeck = deck;
                    newDeck.Remove(knownNextCardIndex);
                    for (int i = 0; i < 4; i++)
                    {
                        IntVector2D cell = newCardCells[i];
                        if (cell.X < 0)
                        {
                            continue;
                        }

                        FastBoard newBoard = shiftedBoard;
                        newBoard.SetCardIndex(cell, knownNextCardIndex);

                        float quality;
                        if (recursionsLeft == 0 || GetBestMoveForBoard(newBoard, newDeck, 0, recursionsLeft - 1, out quality, ref movesEvaluated) == null)
                        {
                            quality = _evaluator(newBoard);
                            movesEvaluated++;
                        }

                        totalQuality += quality;
                        totalWeight  += 1;
                    }
                }
                else if (_moveSearchDepth - recursionsLeft - 1 < _cardCountDepth)
                {
                    if (deck.Ones > 0)
                    {
                        FastDeck newDeck = deck;
                        newDeck.RemoveOne();
                        for (int i = 0; i < 4; i++)
                        {
                            IntVector2D cell = newCardCells[i];
                            if (cell.X < 0)
                            {
                                continue;
                            }

                            FastBoard newBoard = shiftedBoard;
                            newBoard.SetCardIndex(cell, 1);

                            float quality;
                            if (recursionsLeft == 0 || GetBestMoveForBoard(newBoard, newDeck, 0, recursionsLeft - 1, out quality, ref movesEvaluated) == null)
                            {
                                quality = _evaluator(newBoard);
                                movesEvaluated++;
                            }

                            totalQuality += quality * deck.Ones;
                            totalWeight  += deck.Ones;
                        }
                    }

                    if (deck.Twos > 0)
                    {
                        FastDeck newDeck = deck;
                        newDeck.RemoveTwo();
                        for (int i = 0; i < 4; i++)
                        {
                            IntVector2D cell = newCardCells[i];
                            if (cell.X < 0)
                            {
                                continue;
                            }

                            FastBoard newBoard = shiftedBoard;
                            newBoard.SetCardIndex(cell, 2);

                            float quality;
                            if (recursionsLeft == 0 || GetBestMoveForBoard(newBoard, newDeck, 0, recursionsLeft - 1, out quality, ref movesEvaluated) == null)
                            {
                                quality = _evaluator(newBoard);
                                movesEvaluated++;
                            }

                            totalQuality += quality * deck.Twos;
                            totalWeight  += deck.Twos;
                        }
                    }

                    if (deck.Threes > 0)
                    {
                        FastDeck newDeck = deck;
                        newDeck.RemoveThree();
                        for (int i = 0; i < 4; i++)
                        {
                            IntVector2D cell = newCardCells[i];
                            if (cell.X < 0)
                            {
                                continue;
                            }

                            FastBoard newBoard = shiftedBoard;
                            newBoard.SetCardIndex(cell, 3);

                            float quality;
                            if (recursionsLeft == 0 || GetBestMoveForBoard(newBoard, newDeck, 0, recursionsLeft - 1, out quality, ref movesEvaluated) == null)
                            {
                                quality = _evaluator(newBoard);
                                movesEvaluated++;
                            }

                            totalQuality += quality * deck.Threes;
                            totalWeight  += deck.Threes;
                        }
                    }

                    // Note that we're not taking the chance of getting a bonus card into consideration. That would be way too expensive at not much benefit.
                }
                else
                {
                    float quality;
                    if (recursionsLeft == 0 || GetBestMoveForBoard(shiftedBoard, deck, 0, recursionsLeft - 1, out quality, ref movesEvaluated) == null)
                    {
                        quality = _evaluator(shiftedBoard);
                        movesEvaluated++;
                    }

                    totalQuality += quality;
                    totalWeight  += 1;
                }

                return(totalQuality / totalWeight);
            }
            else
            {
                return(null);
            }
        }