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 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); } } }
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); }