Beispiel #1
0
 public bool IsReversible(Move move)
 {
     int from = move.From;
     int fromRow = move.FromRow;
     int to = move.To;
     int toRow = move.ToRow;
     Pile fromPile = FindTableau[from];
     Pile toPile = FindTableau[to];
     bool isSwap = move.Type == MoveType.Swap;
     Card fromParent = fromRow != 0 ? fromPile[fromRow - 1] : Card.Empty;
     Card fromChild = fromPile[fromRow];
     Card toParent = toRow != 0 ? toPile[toRow - 1] : Card.Empty;
     Card toChild = toRow != toPile.Count ? toPile[toRow] : Card.Empty;
     int oldOrderFrom = GetOrder(fromParent, fromChild);
     int newOrderFrom = GetOrder(toParent, fromChild);
     int oldOrderTo = isSwap ? GetOrder(toParent, toChild) : 0;
     int newOrderTo = isSwap ? GetOrder(fromParent, toChild) : 0;
     return oldOrderFrom != 0 && (!isSwap || oldOrderTo != 0);
 }
Beispiel #2
0
        public double Calculate(Move move)
        {
            if (move.IsEmpty)
            {
                return Move.RejectScore;
            }

            ScoreInfo score = new ScoreInfo(Coefficients, Group0);

            int from = move.From;
            int fromRow = move.FromRow;
            int to = move.To;
            int toRow = move.ToRow;

            if (move.Type == MoveType.CompositeSinglePile)
            {
                return CalculateCompositeSinglePileScore(move);
            }
            Pile fromPile = FindTableau[from];
            Pile toPile = FindTableau[to];
            if (toPile.Count == 0)
            {
                return CalculateLastResortScore(move);
            }
            bool isSwap = move.Type == MoveType.Swap;
            Card fromParent = fromRow != 0 ? fromPile[fromRow - 1] : Card.Empty;
            Card fromChild = fromPile[fromRow];
            Card toParent = toRow != 0 ? toPile[toRow - 1] : Card.Empty;
            Card toChild = toRow != toPile.Count ? toPile[toRow] : Card.Empty;
            int oldOrderFrom = GetOrder(fromParent, fromChild);
            int newOrderFrom = GetOrder(toParent, fromChild);
            int oldOrderTo = isSwap ? GetOrder(toParent, toChild) : 0;
            int newOrderTo = isSwap ? GetOrder(fromParent, toChild) : 0;
            score.Order = newOrderFrom - oldOrderFrom + newOrderTo - oldOrderTo;
            if (score.Order < 0)
            {
                return Move.RejectScore;
            }
            score.Reversible = oldOrderFrom != 0 && (!isSwap || oldOrderTo != 0);
            score.Uses = CountUses(move);
            score.OneRunDelta = !isSwap ? RunFinder.GetOneRunDelta(oldOrderFrom, newOrderFrom, move) : 0;
            int faceFrom = (int)fromChild.Face;
            int faceTo = isSwap ? (int)toChild.Face : 0;
            score.FaceValue = Math.Max(faceFrom, faceTo);
            bool wholePile = fromRow == 0 && toRow == toPile.Count;
            int netRunLengthFrom = RunFinder.GetNetRunLength(newOrderFrom, from, fromRow, to, toRow);
            int netRunLengthTo = isSwap ? RunFinder.GetNetRunLength(newOrderTo, to, toRow, from, fromRow) : 0;
            score.NetRunLength = netRunLengthFrom + netRunLengthTo;
            #if true
            int newRunLengthFrom = RunFinder.GetNewRunLength(newOrderFrom, from, fromRow, to, toRow);
            int newRunLengthTo = isSwap ? RunFinder.GetNewRunLength(newOrderTo, to, toRow, from, fromRow) : 0;
            score.Discards = newRunLengthFrom == 13 || newRunLengthTo == 13;
            #endif
            score.DownCount = FindTableau.GetDownCount(from);
            score.TurnsOverCard = wholePile && score.DownCount != 0;
            score.CreatesSpace = wholePile && score.DownCount == 0;
            score.NoSpaces = FindTableau.NumberOfSpaces == 0;
            if (score.Order == 0 && score.NetRunLength < 0)
            {
                return Move.RejectScore;
            }
            int delta = 0;
            if (score.Order == 0 && score.NetRunLength == 0)
            {
                if (!isSwap && oldOrderFrom == 1 && newOrderFrom == 1)
                {
                    delta = RunFinder.GetRunDelta(from, fromRow, to, toRow);
                }
                if (delta <= 0)
                {
                    return Move.RejectScore;
                }
            }
            score.IsCompositeSinglePile = false;

            return score.Score;
        }
Beispiel #3
0
        private int CountUses(Move move)
        {
            if (move.FromRow == 0 || move.ToRow != FindTableau[move.To].Count)
            {
                // No exposed card, no uses.
                return 0;
            }

            int uses = 0;

            Pile fromPile = FindTableau[move.From];
            Card fromCard = fromPile[move.FromRow];
            Card exposedCard = fromPile[move.FromRow - 1];
            if (!exposedCard.IsTargetFor(fromCard))
            {
                // Check whether the exposed card will be useful.
                int numberOfSpaces = FindTableau.NumberOfSpaces - 1;
                int maxExtraSuits = ExtraSuits(numberOfSpaces);
                int fromSuits = RunFinder.CountSuits(move.From, move.FromRow);
                for (int nextFrom = 0; nextFrom < NumberOfPiles; nextFrom++)
                {
                    if (nextFrom == move.From || nextFrom == move.To)
                    {
                        // Inappropriate column.
                        continue;
                    }
                    Pile nextFromPile = FindTableau[nextFrom];
                    if (nextFromPile.Count == 0)
                    {
                        // Column is empty.
                        continue;
                    }
                    int nextFromRow = nextFromPile.Count - RunFinder.GetRunUpAnySuit(nextFrom);
                    if (!nextFromPile[nextFromRow].IsSourceFor(exposedCard))
                    {
                        // Not the card we need.
                        continue;
                    }
                    int extraSuits = RunFinder.CountSuits(nextFrom, nextFromRow) - 1;
                    if (extraSuits <= maxExtraSuits)
                    {
                        // Card leads to a useful move.
                        uses++;
                    }

                    // Check whether the exposed run will be useful.
                    int upperFromRow = move.FromRow - RunFinder.GetRunUp(move.From, move.FromRow);
                    if (upperFromRow != move.FromRow)
                    {
                        Card upperFromCard = fromPile[upperFromRow];
                        uses += FaceLists[(int)upperFromCard.Face + 1].Count;
                    }
                }
            }
            return uses;
        }
Beispiel #4
0
        private double CalculateLastResortScore(Move move)
        {
            ScoreInfo score = new ScoreInfo(Coefficients, Group1);

            Pile fromPile = FindTableau[move.From];
            Pile toPile = FindTableau[move.To];
            Card fromCard = fromPile[move.FromRow];
            bool wholePile = move.FromRow == 0;
            score.UsesSpace = true;
            score.DownCount = FindTableau.GetDownCount(move.From);
            score.TurnsOverCard = wholePile && score.DownCount != 0;
            score.FaceValue = (int)fromCard.Face;
            score.IsKing = fromCard.Face == Face.King;
            score.Uses = CountUses(move);

            if (wholePile)
            {
                // Only move an entire pile if there
                // are more cards to be turned over.
                if (!score.TurnsOverCard)
                {
                    return Move.RejectScore;
                }
            }
            else if (fromPile[move.FromRow - 1].IsTargetFor(fromCard))
            {
                // No point in splitting consecutive cards
                // unless they are part of a multi-move
                // sequence.
                return Move.RejectScore;
            }

            return score.LastResortScore;
        }
Beispiel #5
0
        private double CalculateCompositeSinglePileScore(Move move)
        {
            ScoreInfo score = new ScoreInfo(Coefficients, Group0);

            score.Order = move.ToRow;
            score.FaceValue = 0;
            score.NetRunLength = 0;
            score.DownCount = FindTableau.GetDownCount(move.From);
            score.TurnsOverCard = move.Flags.TurnsOverCard();
            score.CreatesSpace = move.Flags.CreatesSpace();
            score.UsesSpace = move.Flags.UsesSpace();
            score.Discards = move.Flags.Discards();
            score.IsCompositeSinglePile = true;
            score.NoSpaces = FindTableau.NumberOfSpaces == 0;
            score.OneRunDelta = 0;

            if (score.UsesSpace)
            {
                // XXX: should calculate uses, is king, etc.
                score.Coefficient0 = Group1;
                return score.LastResortScore;
            }
            return score.Score;
        }
Beispiel #6
0
 public void ProcessCandidate(Move move)
 {
     double score = ScoreCalculator.Calculate(move);
     if (score == Move.RejectScore)
     {
         return;
     }
     move.Score = score;
     Candidates.Add(move);
 }
Beispiel #7
0
 public void ProcessMove(Move move)
 {
     MoveProcessor.Process(move);
 }
Beispiel #8
0
 public void PrintMove(Move move)
 {
     Utils.WriteLine(move);
     for (int next = move.Next; next != -1; next = SupplementaryList[next].Next)
     {
         Move nextMove = SupplementaryList[next];
         Utils.WriteLine("    {0}", nextMove);
     }
     for (int holdingNext = move.HoldingNext; holdingNext != -1; holdingNext = SupplementaryList[holdingNext].Next)
     {
         Utils.WriteLine("    holding {0}", SupplementaryList[holdingNext]);
     }
 }
        private void CheckOne(Move uncoveringMove)
        {
            // Prepare data structures.
            order = 0;
            int runs = Roots.Count - 1;
            Offload = OffloadInfo.Empty;
            SupplementaryMoves.Clear();

            // Initialize the pile map.
            WorkingTableau.Clear();
            WorkingTableau.CopyUpPiles(FindTableau);
            WorkingTableau.BlockDownPiles(FindTableau);

            if (!uncoveringMove.IsEmpty)
            {
                // Update the map for the uncovering move but don't
                // include its order contribution so we don't make
                // the uncovering move unless it is really necessary.
                MoveStack.Clear();
                for (int next = uncoveringMove.HoldingNext; next != -1; next = SupplementaryList[next].Next)
                {
                    Move holdingMove = SupplementaryList[next];
                    Move forwardMove = new Move(MoveType.Basic, MoveFlags.Holding, holdingMove.From, holdingMove.FromRow, holdingMove.To);
                    SupplementaryMoves.Add(forwardMove);
                    WorkingTableau.Move(forwardMove);
                    MoveStack.Push(new Move(MoveType.Basic, MoveFlags.UndoHolding, holdingMove.To, -holdingMove.ToRow, uncoveringMove.To));
                }
                SupplementaryMoves.Add(uncoveringMove);
                WorkingTableau.Move(uncoveringMove);
                while (MoveStack.Count > 0)
                {
                    Move holdingMove = MoveStack.Pop();
                    if (!WorkingTableau.IsValid(holdingMove))
                    {
                        break;
                    }
                    SupplementaryMoves.Add(holdingMove);
                    WorkingTableau.Move(holdingMove);
                }
            }

            // Check all the roots.
            int offloads = 0;
            for (int n = 1; n < Roots.Count; n++)
            {
                int rootRow = Roots[n];
                Card rootCard = fromPile[rootRow];
                int runLength = Roots[n - 1] - Roots[n];
                int suits = fromPile.CountSuits(rootRow, rootRow + runLength);
                int maxExtraSuits = ExtraSuits(GetNumberOfSpacesLeft());
                bool suitsMatch = false;
                HoldingStack.Clear();

                // Try to find the best matching target.
                int to = -1;
                for (int i = 0; i < NumberOfPiles; i++)
                {
                    if (i == from)
                    {
                        continue;
                    }
                    Card card = WorkingTableau.GetCard(i);
                    if (card.IsTargetFor(rootCard))
                    {
                        if (!Offload.IsEmpty && to == Offload.To)
                        {
                            to = -1;
                            suitsMatch = false;
                        }
                        if (!suitsMatch && card.Suit == rootCard.Suit)
                        {
                            to = i;
                            suitsMatch = true;
                        }
                        else if (to == -1)
                        {
                            to = i;
                        }
                    }
                }

                MoveType type = MoveType.Basic;
                bool isOffload = false;
                if (to != -1)
                {
                    // Check for inverting.
                    if (!Offload.IsEmpty && to == Offload.To)
                    {
                        if (!Offload.SinglePile)
                        {
                            // Not enough spaces to invert.
                            return;
                        }
                    }

                    // Try to move this run.
                    if (suits - 1 > maxExtraSuits)
                    {
                        // Try using holding piles.
                        suits -= FindHolding(WorkingTableau, HoldingStack, false, fromPile, from, rootRow, rootRow + runLength, to, maxExtraSuits);
                        if (suits - 1 > maxExtraSuits)
                        {
                            // Not enough spaces.
                            return;
                        }
                    }

                    // Record the order improvement.
                    order += GetOrder(true, suitsMatch);
                }
                else
                {
                    if (!Offload.IsEmpty)
                    {
                        // Already have an offload.
                        return;
                    }

                    // It doesn't make sense to offload the last root.
                    if (rootRow == 0)
                    {
                        if (runs - 1 >= 2)
                        {
                            AddMove(order);
                        }
                        return;
                    }

                    // Check for partial offload.
                    if (offloads > 0)
                    {
                        AddMove(order);
                    }

                    // Try to offload this run.
                    if (GetNumberOfSpacesLeft() == 0)
                    {
                        // Not enough spaces.
                        return;
                    }
                    to = WorkingTableau.Spaces[0];
                    int maxExtraSuitsOnePile = ExtraSuits(GetNumberOfSpacesLeft() - 1) + 1;
                    if (suits > maxExtraSuitsOnePile)
                    {
                        // Try using holding piles.
                        suits -= FindHolding(WorkingTableau, HoldingStack, false, fromPile, from, rootRow, rootRow + runLength, to, maxExtraSuits);
                        if (suits > maxExtraSuits)
                        {
                            // Still not enough spaces.
                            return;
                        }
                    }
                    int numberOfSpacesUsed = SpacesUsed(GetNumberOfSpacesLeft(), suits);
                    Offload = new OffloadInfo(to, numberOfSpacesUsed);
                    type = Offload.SinglePile ? MoveType.Basic : MoveType.Unload;
                    isOffload = true;
                    offloads++;
                }

                // Do the move and the holding moves.
                HoldingSet holdingSet = HoldingStack.Set;
                bool undoHolding = !isOffload;
                AddSupplementaryMove(new Move(type, from, rootRow, to), fromPile, holdingSet, undoHolding);

                // Check whether the offload matches the new from or to piles.
                if (!isOffload)
                {
                    CheckOffload(to);
                }

                // Check whether any of the one run piles now match
                // the new from or to piles.
                for (int i = 0; i < OneRunPiles.Count; i++)
                {
                    if (CheckOneRun(to, OneRunPiles[i]))
                    {
                        // Found an emptying move.
                        return;
                    }
                }
            }

            // Check for unload that needs to be reloaded.
            if (!Offload.IsEmpty && !Offload.SinglePile)
            {
                if (FindTableau.GetDownCount(from) != 0)
                {
                    // Can't reload.
                    return;
                }
                else
                {
                    // Reload the offload onto the now empty space.
                    SupplementaryMoves.Add(new Move(MoveType.Reload, Offload.To, 0, from, 0));
                }
            }

            // Add the move.
            AddMove(order);
        }
        private void AddSupplementaryMove(Move move, Pile pile, HoldingSet holdingSet, bool undoHolding)
        {
            // Add moves to the holding piles.
            for (int i = 0; i < holdingSet.Count; i++)
            {
                HoldingInfo holding = holdingSet[i];
                Move holdingMove = new Move(MoveType.Basic, MoveFlags.Holding, move.From, -holding.Length, holding.To);
                WorkingTableau.Move(holdingMove);
                SupplementaryMoves.Add(holdingMove);
            }

            // Add the primary move.
            WorkingTableau.UncheckedMove(new Move(move.From, move.FromRow, move.To));
            SupplementaryMoves.Add(move);

            if (undoHolding)
            {
                // Undo moves from the holding piles.
                for (int i = holdingSet.Count - 1; i >= 0; i--)
                {
                    HoldingInfo holding = holdingSet[i];
                    Move holdingMove = new Move(MoveType.Basic, MoveFlags.UndoHolding, holding.To, -holding.Length, move.To);
                    if (!WorkingTableau.TryMove(holdingMove))
                    {
                        break;
                    }
                    SupplementaryMoves.Add(holdingMove);
                }
            }
        }
Beispiel #11
0
 public void ProcessMove(Move move)
 {
     game.ProcessMove(move);
 }
Beispiel #12
0
 public void PrintMove(Move move)
 {
     game.PrintMove(move);
 }
Beispiel #13
0
 public int GetOneRunDelta(int oldOrder, int newOrder, Move move)
 {
     bool fromFree = tableau.GetDownCount(move.From) == 0;
     bool toFree = tableau.GetDownCount(move.To) == 0;
     bool fromUpper = GetRunUp(move.From, move.FromRow) == move.FromRow;
     bool fromLower = move.HoldingNext == -1;
     bool toUpper = GetRunUp(move.To, move.ToRow) == move.ToRow;
     bool oldFrom = move.FromRow == 0 ?
         (fromFree && fromLower) :
         (fromFree && fromUpper && fromLower && oldOrder == 2);
     bool newFrom = fromFree && fromUpper;
     bool oldTo = toFree && toUpper;
     bool newTo = move.ToRow == 0 ?
         (toFree && fromLower) :
         (toFree && toUpper && fromLower && newOrder == 2);
     int oneRunDelta = (newFrom ? 1 : 0) - (oldFrom ? 1 : 0) + (newTo ? 1 : 0) - (oldTo ? 1 : 0);
     return oneRunDelta > 0 ? 1 : 0;
 }
Beispiel #14
0
        public bool IsViable(Move move)
        {
            int from = move.From;
            int fromRow = move.FromRow;
            int to = move.To;
            int toRow = move.ToRow;

            Pile fromPile = FindTableau[from];
            Pile toPile = FindTableau[to];
            if (toPile.Count == 0)
            {
                if (fromPile.Count == 0 && FindTableau.GetDownCount(from) == 0)
                {
                    return false;
                }
                else if (fromRow != 0 && fromPile[fromRow - 1].IsTargetFor(fromPile[fromRow]))
                {
                    return false;
                }
                return true;
            }
            bool isSwap = move.Type == MoveType.Swap;
            Card fromParent = fromRow != 0 ? fromPile[fromRow - 1] : Card.Empty;
            Card fromChild = fromPile[fromRow];
            Card toParent = toRow != 0 ? toPile[toRow - 1] : Card.Empty;
            Card toChild = toRow != toPile.Count ? toPile[toRow] : Card.Empty;
            int oldOrderFrom = GetOrder(fromParent, fromChild);
            int newOrderFrom = GetOrder(toParent, fromChild);
            int oldOrderTo = isSwap ? GetOrder(toParent, toChild) : 0;
            int newOrderTo = isSwap ? GetOrder(fromParent, toChild) : 0;
            int order = newOrderFrom - oldOrderFrom + newOrderTo - oldOrderTo;
            if (order < 0)
            {
                return false;
            }
            int netRunLengthFrom = RunFinder.GetNetRunLength(newOrderFrom, from, fromRow, to, toRow);
            int netRunLengthTo = isSwap ? RunFinder.GetNetRunLength(newOrderTo, to, toRow, from, fromRow) : 0;
            int netRunLength = netRunLengthFrom + netRunLengthTo;
            if (order == 0 && netRunLength < 0)
            {
                return false;
            }
            int delta = 0;
            if (order == 0 && netRunLength == 0)
            {
                if (!isSwap && oldOrderFrom == 1 && newOrderFrom == 1)
                {
                    delta = RunFinder.GetRunDelta(from, fromRow, to, toRow);
                }
                if (delta <= 0)
                {
                    return false;
                }
            }

            return true;
        }
Beispiel #15
0
 public void ProcessCandidate(Move move)
 {
     if (IsViable(move))
     {
         Candidates.Add(move);
     }
 }