Ejemplo n.º 1
0
        private void MakeMove(Node node, int i)
        {
            Move move    = node.Moves[i];
            bool toEmpty = move.Type == MoveType.Basic && WorkingTableau[move.To].Count == 0;

            MoveStack.Clear();
            for (int next = move.HoldingNext; next != -1; next = node.SupplementaryList[next].Next)
            {
                Move holdingMove = node.SupplementaryList[next];
                WorkingTableau.Move(new Move(MoveType.Basic, MoveFlags.Holding, holdingMove.From, holdingMove.FromRow, holdingMove.To));
                int undoTo = holdingMove.From == move.From ? move.To : move.From;
                MoveStack.Push(new Move(MoveType.Basic, MoveFlags.UndoHolding, holdingMove.To, -holdingMove.ToRow, undoTo));
            }
            WorkingTableau.Move(new Move(move.Type, move.From, move.FromRow, move.To, move.ToRow));
            if (!toEmpty)
            {
                while (MoveStack.Count > 0)
                {
                    Move holdingMove = MoveStack.Pop();
                    if (!WorkingTableau.IsValid(holdingMove))
                    {
                        break;
                    }
                    WorkingTableau.Move(holdingMove);
                }
            }
        }
Ejemplo n.º 2
0
        private void DepthFirstSearch(int depth)
        {
            if (depth == 0)
            {
                return;
            }

            Algorithm.FindMoves(WorkingTableau);
            Node node = new Node(new MoveList(Candidates), new MoveList(SupplementaryList));

            for (int i = 0; i < node.Moves.Count; i++)
            {
                int checkPoint = WorkingTableau.CheckPoint;

                MakeMove(node, i);

                bool continueSearch = ProcessNode();
                if (NodesSearched >= MaxNodes)
                {
                    WorkingTableau.Revert(checkPoint);
                    return;
                }
                if (continueSearch)
                {
                    DepthFirstSearch(depth - 1);
                }
                WorkingTableau.Revert(checkPoint);
                if (NodesSearched >= MaxNodes)
                {
                    return;
                }
            }
        }
        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);
                }
            }
        }
        private void RestoreWorkingState()
        {
            // Restore state of the working tableau prior to intermediate move.
            WorkingTableau.Revert(tableauCheckPoint);

            // Restore state of supplementary moves prior to intermediate move.
            while (SupplementaryMoves.Count > supplementaryMovesCount)
            {
                SupplementaryMoves.RemoveAt(SupplementaryMoves.Count - 1);
            }
        }
        private bool TryAddOneRunMove(int oneRun, int target)
        {
            Pile oneRunPile = WorkingTableau[oneRun];

            if (oneRunPile.Count == 0)
            {
                return(false);
            }
            Card oneRunRootCard = oneRunPile[0];

            // Check whether the one run pile matches the target pile.
            Card targetCard = WorkingTableau.GetCard(target);

            if (!oneRunRootCard.IsSourceFor(targetCard))
            {
                return(false);
            }

            // Check whether we can make the move.
            int oneRunSuits         = oneRunPile.CountSuits();
            int oneRunMaxExtraSuits = ExtraSuits(GetNumberOfSpacesLeft());

            HoldingStack.Clear();
            if (oneRunSuits - 1 > oneRunMaxExtraSuits)
            {
                oneRunSuits -= FindHolding(WorkingTableau, HoldingStack, false, oneRunPile, oneRun, 0, oneRunPile.Count, target, oneRunMaxExtraSuits);
                if (oneRunSuits - 1 > oneRunMaxExtraSuits)
                {
                    // Not enough spaces and/or holding piles.
                    return(false);
                }
            }

            // Handle the messy cases.
            if (Offload.IsEmpty || Offload.SinglePile && FindTableau.GetDownCount(oneRun) == 0)
            {
                // Save working state.
                SaveWorkingState();

                // Found a home for the one run pile.
                AddSupplementaryMove(new Move(oneRun, 0, target), oneRunPile, HoldingStack.Set, true);

                if (AddMove(order + GetOrder(targetCard, oneRunRootCard)))
                {
                    return(true);
                }

                // Restore working state.
                RestoreWorkingState();
            }

            return(false);
        }
Ejemplo n.º 6
0
 private void BreadthFirstSearch(ref Node parent)
 {
     if (parent.Moves == null)
     {
         Algorithm.FindMoves(WorkingTableau);
         parent.Moves             = new AllocatedList <Move>(MoveAllocator, Candidates);
         parent.SupplementaryList = new AllocatedList <Move>(MoveAllocator, SupplementaryList);
         parent.Nodes             = new AllocatedList <Node>(NodeAllocator, parent.Moves.Count, parent.Moves.Count);
         for (int i = 0; i < parent.Moves.Count; i++)
         {
             int checkPoint = WorkingTableau.CheckPoint;
             MakeMove(parent, i);
             if (ProcessNode())
             {
                 parent.Nodes[i] = new Node(true);
             }
             WorkingTableau.Revert(checkPoint);
             if (NodesSearched >= MaxNodes)
             {
                 return;
             }
         }
     }
     else
     {
         for (int i = 0; i < parent.Moves.Count; i++)
         {
             Node child = parent.Nodes[i];
             if (child.ContinueSearch)
             {
                 int checkPoint = WorkingTableau.CheckPoint;
                 MakeMove(parent, i);
                 BreadthFirstSearch(ref child);
                 WorkingTableau.Revert(checkPoint);
                 if (NodesSearched >= MaxNodes)
                 {
                     return;
                 }
             }
             parent.Nodes[i] = child;
         }
     }
 }
Ejemplo n.º 7
0
        private bool ProcessNode()
        {
            int hashKey = WorkingTableau.GetUpPilesHashKey();

            if (TranspositionTable.Contains(hashKey))
            {
                return(false);
            }
            TranspositionTable.Add(hashKey);

            NodesSearched++;
            double score = CalculateSearchScore();

            if (score > Score)
            {
                Score = score;
                Moves.Copy(WorkingTableau.Moves);
            }

            return(true);
        }
Ejemplo n.º 8
0
        public MoveList SearchMoves()
        {
            WorkingTableau.Variation = Variation;
            WorkingTableau.Clear();
            WorkingTableau.CopyUpPiles(Tableau);
            WorkingTableau.BlockDownPiles(Tableau);

            MoveAllocator.Clear();
            NodeAllocator.Clear();

            if (UseDepthFirst)
            {
                StartSearch();
                DepthFirstSearch(MaxDepth);
                if (NodesSearched >= MaxNodes)
                {
                    int maxNodesSearched = 0;
                    for (int depth = 1; depth < MaxDepth; depth++)
                    {
                        StartSearch();
                        DepthFirstSearch(depth);
                        if (NodesSearched == maxNodesSearched)
                        {
                            break;
                        }
                        maxNodesSearched = NodesSearched;
                        if (maxNodesSearched >= MaxNodes)
                        {
                            break;
                        }
                    }
                }
            }
            else
            {
                StartSearch();
                Node root = new Node();
                while (true)
                {
                    int lastNodesSearched = NodesSearched;
                    BreadthFirstSearch(ref root);
                    if (NodesSearched == lastNodesSearched || NodesSearched >= MaxNodes)
                    {
                        break;
                    }
                }
            }

            if (TraceSearch)
            {
                Print();
                Utils.WriteLine("search: score = {0}", Score);
                for (int i = 0; i < Moves.Count; i++)
                {
                    Utils.WriteLine("search: move[{0}] = {1}", i, Moves[i]);
                }
                Utils.WriteLine("Nodes searched: {0}", NodesSearched);
            }
            if (Diagnostics)
            {
                Utils.WriteLine("search: score = {0}", Score);
                for (int i = 0; i < Moves.Count; i++)
                {
                    Utils.WriteLine("search: move[{0}] = {1}", i, Moves[i]);
                }
            }

            return(Moves);
        }
        private void CheckOffload(int to)
        {
            if (Offload.IsEmpty)
            {
                // No offload to check.
                return;
            }

            Pile offloadPile = WorkingTableau[Offload.To];

            if (offloadPile.Count == 0)
            {
                // A discard emptied the offload pile.
                Offload = OffloadInfo.Empty;
                return;
            }

            Card     offloadRootCard      = offloadPile[0];
            int      offloadSuits         = offloadPile.CountSuits();
            int      offloadMaxExtraSuits = ExtraSuits(GetNumberOfSpacesLeft());
            MoveType offloadType          = Offload.SinglePile ? MoveType.Basic : MoveType.Reload;

            // Check whether offload matches from pile.
            Card fromCard = WorkingTableau.GetCard(from);

            if (offloadRootCard.IsSourceFor(fromCard))
            {
                // Check whether we can make the move.
                bool canMove = true;
                HoldingStack.Clear();
                if (Offload.SinglePile && offloadSuits - 1 > offloadMaxExtraSuits)
                {
                    // Not enough spaces.
                    offloadSuits -= FindHolding(WorkingTableau, HoldingStack, false, offloadPile, Offload.To, 0, offloadPile.Count, from, offloadMaxExtraSuits);
                    if (offloadSuits - 1 > offloadMaxExtraSuits)
                    {
                        // Not enough spaces and/or holding piles.
                        canMove = false;
                    }
                }

                if (canMove)
                {
                    // Save working state.
                    SaveWorkingState();

                    // Offload matches from pile.
                    AddSupplementaryMove(new Move(offloadType, Offload.To, 0, from), offloadPile, HoldingStack.Set, true);

                    // Add the intermediate move.
                    AddMove(order + GetOrder(fromCard, offloadRootCard));

                    // Restore working state.
                    RestoreWorkingState();
                }
            }

            // Check whether offoad matches to pile.
            Card toCard = WorkingTableau.GetCard(to);

            if (offloadRootCard.IsSourceFor(toCard))
            {
                // Check whether we can make the move.
                bool canMove = true;
                HoldingStack.Clear();
                if (Offload.SinglePile && offloadSuits - 1 > offloadMaxExtraSuits)
                {
                    // Not enough spaces.
                    offloadSuits -= FindHolding(WorkingTableau, HoldingStack, false, offloadPile, Offload.To, 0, offloadPile.Count, to, offloadMaxExtraSuits);
                    if (offloadSuits - 1 > offloadMaxExtraSuits)
                    {
                        // Not enough spaces and/or holding piles.
                        canMove = false;
                    }
                }

                if (canMove)
                {
                    // Record the order improvement.
                    order += GetOrder(toCard, offloadRootCard);

                    // Found a home for the offload.
                    AddSupplementaryMove(new Move(offloadType, Offload.To, 0, to), offloadPile, HoldingStack.Set, true);

                    // Update the state.
                    Offload = OffloadInfo.Empty;
                }
            }
        }
        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);
        }