private void FindUncoveringMoves(int maxExtraSuits) { // Find all uncovering moves. UncoveringMoves.Clear(); for (int from = 0; from < NumberOfPiles; from++) { Pile fromPile = FindTableau[from]; int fromRow = fromPile.Count - RunFinder.GetRunUpAnySuit(from); if (fromRow == 0) { continue; } int fromSuits = RunFinder.CountSuits(from, fromRow); Card fromCard = fromPile[fromRow]; PileList faceList = FaceLists[(int)fromCard.Face + 1]; for (int i = 0; i < faceList.Count; i++) { HoldingStack.Clear(); int to = faceList[i]; if (fromSuits - 1 > maxExtraSuits) { int holdingSuits = FindHolding(FindTableau, HoldingStack, false, fromPile, from, fromRow, fromPile.Count, to, maxExtraSuits); if (fromSuits - 1 > maxExtraSuits + holdingSuits) { break; } } Pile toPile = FindTableau[to]; Card toCard = toPile[toPile.Count - 1]; int order = GetOrder(toCard, fromCard); UncoveringMoves.Add(new Move(from, fromRow, to, order, AddHolding(HoldingStack.Set))); } } }
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); }
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; } } }