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); } } }
public int AddHolding(HoldingSet holdingSet) { if (holdingSet.Count == 0) { return(-1); } int first = SupplementaryList.Count; for (int i = 0; i < holdingSet.Count; i++) { HoldingInfo holding = holdingSet[i]; int holdingNext = i < holdingSet.Count - 1 ? SupplementaryList.Count + 1 : -1; SupplementaryList.Add(new Move(holding.From, holding.FromRow, holding.To, holding.Length, -1, holdingNext)); } return(first); }
public int AddHolding(HoldingSet holdingSet1, HoldingSet holdingSet2) { if (holdingSet1.Count == 0 && holdingSet2.Count == 0) { return(-1); } if (holdingSet1.Count == 0) { return(AddHolding(holdingSet2)); } if (holdingSet2.Count == 0) { return(AddHolding(holdingSet1)); } int first1 = AddHolding(holdingSet1); int first2 = AddHolding(holdingSet2); int last1 = first1 + holdingSet1.Count - 1; Move holdingMove = SupplementaryList[last1]; holdingMove.Next = first2; SupplementaryList[last1] = holdingMove; return(first1); }
private void Check(int from, int fromRow, int extraSuits, int maxExtraSuits) { if (fromRow == 0 && FindTableau.GetDownCount(from) != 0) { // Would turn over a card. return; } Pile fromPile = FindTableau[from]; Card fromCard = fromPile[fromRow]; Card fromCardParent = Card.Empty; bool inSequence = true; if (fromRow != 0) { fromCardParent = fromPile[fromRow - 1]; inSequence = fromCardParent.IsTargetFor(fromCard); } HoldingStack fromHoldingStack = HoldingStacks[from]; for (int to = 0; to < NumberOfPiles; to++) { Pile toPile = FindTableau[to]; if (to == from || toPile.Count == 0) { continue; } int splitRow = toPile.Count - RunFinder.GetRunUpAnySuit(to); int toRow = -1; if (inSequence) { // Try to find from counterpart in the first to run. toRow = splitRow + (int)(toPile[splitRow].Face - fromCard.Face); if (toRow < splitRow || toRow >= toPile.Count) { // Sequence doesn't contain our counterpart. continue; } } else { // Try to swap with both runs out of sequence. toRow = splitRow; if (fromRow != 0 && !fromCardParent.IsTargetFor(toPile[toRow])) { // Cards don't match. continue; } } if (toRow == 0) { if (fromRow == 0) { // No point in swap both entire piles. continue; } if (FindTableau.GetDownCount(to) != 0) { // Would turn over a card. continue; } } else if (!toPile[toRow - 1].IsTargetFor(fromCard)) { // Cards don't match. continue; } int toSuits = RunFinder.CountSuits(to, toRow); if (extraSuits + toSuits <= maxExtraSuits) { // Swap with no holding piles. Algorithm.ProcessCandidate(new Move(MoveType.Swap, from, fromRow, to, toRow)); continue; } HoldingStack toHoldingStack = HoldingStacks[to]; if (extraSuits + toSuits > maxExtraSuits + fromHoldingStack.Suits + toHoldingStack.Suits) { // Not enough spaces. continue; } Used.Clear(); Used.Add(from); Used.Add(to); int fromHoldingCount = 0; int toHoldingCount = 0; int fromHoldingSuits = 0; int toHoldingSuits = 0; while (true) { if (fromHoldingCount < fromHoldingStack.Count && fromHoldingStack[fromHoldingCount].FromRow >= fromRow && !Used.Contains(fromHoldingStack[fromHoldingCount].To)) { Used.Add(fromHoldingStack[fromHoldingCount].To); fromHoldingSuits = fromHoldingStack[fromHoldingCount].Suits; fromHoldingCount++; } else if (toHoldingCount < toHoldingStack.Count && toHoldingStack[toHoldingCount].FromRow >= toRow && !Used.Contains(toHoldingStack[toHoldingCount].To)) { Used.Add(toHoldingStack[toHoldingCount].To); toHoldingSuits = toHoldingStack[toHoldingCount].Suits; toHoldingCount++; } else { // Out of options. break; } if (extraSuits + toSuits > maxExtraSuits + fromHoldingSuits + toHoldingSuits) { // Not enough spaces. continue; } // We've found a legal swap. Debug.Assert(toRow == 0 || toPile[toRow - 1].IsTargetFor(fromCard)); Debug.Assert(fromRow == 0 || fromCardParent.IsTargetFor(toPile[toRow])); HoldingSet fromHoldingSet = new HoldingSet(fromHoldingStack, fromHoldingCount); HoldingSet toHoldingSet = new HoldingSet(toHoldingStack, toHoldingCount); Algorithm.ProcessCandidate(new Move(MoveType.Swap, from, fromRow, to, toRow, AddHolding(fromHoldingSet, toHoldingSet))); break; } } }
public void Find() { Candidates.Clear(); SupplementaryList.Clear(); int numberOfSpaces = FindTableau.NumberOfSpaces; int maxExtraSuits = ExtraSuits(numberOfSpaces); int maxExtraSuitsToSpace = ExtraSuits(numberOfSpaces - 1); for (int from = 0; from < NumberOfPiles; from++) { HoldingStack holdingStack = HoldingStacks[from]; Pile fromPile = FindTableau[from]; holdingStack.Clear(); holdingStack.StartingRow = fromPile.Count; int extraSuits = 0; for (int fromRow = fromPile.Count - 1; fromRow >= 0; fromRow--) { Card fromCard = fromPile[fromRow]; if (fromCard.IsEmpty) { break; } if (fromRow < fromPile.Count - 1) { Card previousCard = fromPile[fromRow + 1]; if (!previousCard.IsSourceFor(fromCard)) { break; } if (fromCard.Suit != previousCard.Suit) { // This is a cross-suit run. extraSuits++; if (extraSuits > maxExtraSuits + holdingStack.Suits) { break; } } } // Add moves to other piles. if (fromCard.Face < Face.King) { PileList piles = FaceLists[(int)fromCard.Face + 1]; for (int i = 0; i < piles.Count; i++) { for (int count = 0; count <= holdingStack.Count; count++) { HoldingSet holdingSet = new HoldingSet(holdingStack, count); if (extraSuits > maxExtraSuits + holdingSet.Suits) { continue; } int to = piles[i]; if (from == to || holdingSet.Contains(from)) { continue; } // We've found a legal move. Pile toPile = FindTableau[to]; Algorithm.ProcessCandidate(new Move(from, fromRow, to, toPile.Count, AddHolding(holdingSet))); // Update the holding pile move. int holdingSuits = extraSuits; if (fromRow > 0 && (!fromPile[fromRow - 1].IsTargetFor(fromCard) || fromCard.Suit != fromPile[fromRow - 1].Suit)) { holdingSuits++; } if (holdingSuits > holdingStack.Suits) { int length = holdingStack.FromRow - fromRow; holdingStack.Push(new HoldingInfo(from, fromRow, to, holdingSuits, length)); } break; } } } // Add moves to an space. for (int i = 0; i < FindTableau.NumberOfSpaces; i++) { int to = FindTableau.Spaces[i]; if (fromRow == 0) { // No point in moving from a full pile // from one open position to another unless // there are more cards to turn over. if (FindTableau.GetDownCount(from) == 0) { continue; } } else { // No point in moving anything less than // as much as possible to an space. Card nextCard = fromPile[fromRow - 1]; if (fromCard.Suit == nextCard.Suit) { if (nextCard.IsTargetFor(fromCard)) { continue; } } } for (int count = 0; count <= holdingStack.Count; count++) { HoldingSet holdingSet = new HoldingSet(holdingStack, count); if (holdingSet.FromRow == fromRow) { // No cards left to move. continue; } if (extraSuits > maxExtraSuitsToSpace + holdingSet.Suits) { // Not enough spaces. continue; } // We've found a legal move. Pile toPile = FindTableau[to]; Algorithm.ProcessCandidate(new Move(from, fromRow, to, toPile.Count, AddHolding(holdingSet))); break; } // Only need to check the first space // since all spaces are the same // except for undealt cards. break; } } } }
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); }
public int AddHolding(HoldingSet holdingSet1, HoldingSet holdingSet2) { if (holdingSet1.Count == 0 && holdingSet2.Count == 0) { return -1; } if (holdingSet1.Count == 0) { return AddHolding(holdingSet2); } if (holdingSet2.Count == 0) { return AddHolding(holdingSet1); } int first1 = AddHolding(holdingSet1); int first2 = AddHolding(holdingSet2); int last1 = first1 + holdingSet1.Count - 1; Move holdingMove = SupplementaryList[last1]; holdingMove.Next = first2; SupplementaryList[last1] = holdingMove; return first1; }
public int AddHolding(HoldingSet holdingSet) { if (holdingSet.Count == 0) { return -1; } int first = SupplementaryList.Count; for (int i = 0; i < holdingSet.Count; i++) { HoldingInfo holding = holdingSet[i]; int holdingNext = i < holdingSet.Count - 1 ? SupplementaryList.Count + 1 : -1; SupplementaryList.Add(new Move(holding.From, holding.FromRow, holding.To, holding.Length, -1, holdingNext)); } return first; }
public int AddHolding(HoldingSet holdingSet1, HoldingSet holdingSet2) { return game.AddHolding(holdingSet1, holdingSet2); }
public int AddHolding(HoldingSet holdingSet) { return game.AddHolding(holdingSet); }
public int AddHolding(HoldingSet holdingSet1, HoldingSet holdingSet2) { return(game.AddHolding(holdingSet1, holdingSet2)); }
public int AddHolding(HoldingSet holdingSet) { return(game.AddHolding(holdingSet)); }