private bool IsSetLegal(int sourceColumn, int sourceRow, Card topOfHandCard) { Card sourceCard = topOfHandCard == null ? table[sourceColumn][sourceRow] : topOfHandCard; //in the foundation column of the same suit, is the value of the current card there 1 less than the source card if (sourceCard.value != 0) { int desiredColumnCount = foundation[sourceCard.suit].Count; if (desiredColumnCount == 0) { ConsoleMessages.DisplayMessage($"Cannot set {sourceCard.GetReadableCombined(true)} onto the empty foundation column.", true, ConsoleColor.Red); return(false); } else if (desiredColumnCount != sourceCard.value) { ConsoleMessages.DisplayMessage($"Cannot set {sourceCard.GetReadableCombined(true)} onto {foundation[sourceCard.suit][desiredColumnCount-1].GetReadableCombined(true)}", true, ConsoleColor.Red); return(false); } } // Attempting to set a card with other cards on top of it. if (sourceColumn >= 0 && sourceRow != 0 && table[sourceColumn].Count - 1 > sourceRow) { ConsoleMessages.DisplayMessage("Cannot set a card with other cards on top of it.", true, ConsoleColor.Red); return(false); } return(true); }
public void DisplayFoundation() { Console.Write("\nFoundation: "); int i = 0; foreach (List <Card> suitPile in foundation) { if (suitPile.Count == 0) { Console.Write("---- "); } else { string message = ""; string topCard = suitPile[suitPile.Count - 1].GetReadableCombined(); if (topCard.Length == 2) { message += "-"; } message += suitPile[suitPile.Count - 1].GetReadableCombined(true) + "-"; ConsoleMessages.DisplayMessage(message, false, suitPile[0].color == "black" ? ConsoleColor.Black : ConsoleColor.Red, ConsoleColor.White); Console.Write(" "); } i++; } Console.WriteLine(); }
static bool NewGame(bool startupSequence) { autoCompleteOption = true; if (!startupSequence) { while (true) { ConsoleMessages.DisplayMessage("Do you want to start a new game? y/n or yes/no", true); string confirmationInput = Console.ReadLine(); if (confirmationInput == "n" || confirmationInput == "no") { return(false); } else if (confirmationInput == "y" || confirmationInput == "yes") { break; } else { ConsoleMessages.DisplayMessage("Invalid input", true, ConsoleColor.Red); } } } Console.WriteLine("Choose a mode: Draw 1 or Draw 3: (Type '1' or '3'):"); while (true) { string input = Console.ReadLine(); if (input == "1") { drawThreeMode = false; gameDataFilePath = draw1GameDataFilePath; break; } else if (input == "3") { drawThreeMode = true; gameDataFilePath = draw3GameDataFilePath; break; } else { ConsoleMessages.DisplayMessage("Error: Please type '1' or '3' to choose the mode.", true, ConsoleColor.Red); } } Console.WriteLine(); deck = new Deck(); table = new Table(deck); startTime = DateTime.UtcNow; timeOfLastMove = startTime; moveCounter = 0; score = 0; return(true); }
/// <summary> /// Print the table in the standard solitaire layout. /// </summary> public void PrintTable() { int row = 0; // Loop all rows while (true) { bool cardFoundInRow = false; // Loop all columns for (int column = 0; column < table.Count; column++) { // Add some space before each column except for the first. if (column != 0) { Console.Write(" "); } // If there is nothing in a column at this row, write some empty space and move to the next column. if (table[column].Count <= row) { Console.Write(" "); continue; } // If the card is faceup, display the suit and value. if (table[column][row].faceup) { string message = ""; if (table[column][row].GetReadableValue().Length == 1) { message += "-"; } message += table[column][row].GetReadableValue() + table[column][row].GetReadableSuit(true) + "-"; // Last parameter: appendEmptySpaceToEnd. Only true when iterating the last column in the table ConsoleMessages.DisplayMessage(message, false, table[column][row].color == "black" ? ConsoleColor.Black : ConsoleColor.Red, ConsoleColor.White, (column == table.Count - 1 && row == table[column].Count - 1)); } // If the card is facedown, display lines. else { Console.Write("----"); } cardFoundInRow = true; } Console.WriteLine(); row++; // If we've reached a row with no cards (i.e. the 8th row in the initial game), // then we've finished displaying the cards. Break from the loop and the method. if (!cardFoundInRow) { break; } } }
private static void ShowBestTime() { TimeSpan?bestTime = GetBestTime(); if (bestTime.HasValue) { ConsoleMessages.DisplayMessage($"Current best time: {GetTimeString(bestTime.Value)}.", true); } else { ConsoleMessages.DisplayMessage("No best time recorded.", true, ConsoleColor.Red); } }
private static void ShowHighScore() { int?highScore = GetHighScore(); if (highScore.HasValue) { ConsoleMessages.DisplayMessage($"Current high score: {highScore}.", true); } else { ConsoleMessages.DisplayMessage("No high score recorded.", true, ConsoleColor.Red); } }
private void PrintFirstTwoVisibleCards() { if (cards.Count > 2 && visibleHandCount > 2) { cards[2].faceup = true; ConsoleMessages.DisplayMessage(cards[2].GetReadableCombined(true), false, cards[2].color == "black" ? ConsoleColor.Black : ConsoleColor.Red, ConsoleColor.Gray); Console.Write(" "); } if (cards.Count > 1 && visibleHandCount > 1) { cards[1].faceup = true; ConsoleMessages.DisplayMessage(cards[1].GetReadableCombined(true), false, cards[1].color == "black" ? ConsoleColor.Black : ConsoleColor.Red, ConsoleColor.Gray); Console.Write(" "); } }
private static void CheckForAutoComplete() { if (!autoCompleteOption) { return; } if (!drawThreeMode && table.AllCardsFlipped()) { bool autocomplete = false; //Prompt user for autocomplete option: while (true) { ConsoleMessages.DisplayMessage("\n Would you like this game to auto-complete? (yes (y) or no (n))", true); string response = Console.ReadLine().ToLower(); if (response == "y" || response == "yes") { autocomplete = true; break; } else if (response == "n" || response == "no") { break; } else { ConsoleMessages.DisplayMessage("Error, invalid input", true, ConsoleColor.Red); } } //If user says yes: if (autocomplete) { while (table.RemainingCardCount() != 0 || deck.RemainingCardCount() != 0) { table.Autocomplete(deck); System.Threading.Thread.Sleep(500); Console.WriteLine("\n======================================================================\n"); Display(); } } else { //turn off autocomplete option flag autoCompleteOption = false; } } //TODO: DrawThree mode autocomplete }
private static void HighScoreMessage() { int?highScore = GetHighScore(); Console.WriteLine(); if (!highScore.HasValue || score > highScore.Value) { ConsoleMessages.DisplayMessage($"New High Score!: {score}", true, ConsoleColor.Green); recordedHighScore = score; } else { ConsoleMessages.DisplayMessage($"High Score: {highScore.Value}", true); recordedHighScore = highScore.Value; } }
private (bool isMoveLegal, bool continueSearcing) IsMoveLegal(int sourceColumn, int sourceRow, int destinationColumn, int destinationRow, bool fromHand = false) { //Card already in place. if (sourceColumn == destinationColumn && sourceRow == destinationRow + 1) { ConsoleMessages.DisplayMessage("Error: Source card already in requested destination.", true, ConsoleColor.Red); return(false, false); } if (!fromHand && sourceColumn == -1) { ConsoleMessages.DisplayMessage("Error: Source card not available", true, ConsoleColor.Red); return(false, true); } if (destinationColumn == -1) { ConsoleMessages.DisplayMessage("Error: Destination card not available", true, ConsoleColor.Red); return(false, true); } return(true, true); }
/// <summary> /// Prints the best time and sets the new best time if it was faster than the current best time /// </summary> private static void BestTimeMessage() { TimeSpan?bestTime = GetBestTime(); TimeSpan time = (DateTime.UtcNow - startTime); Console.WriteLine(); //if there is no current best time or if time is better than best time: if (!bestTime.HasValue || time < bestTime.Value) { ConsoleMessages.DisplayMessage($"New Best Time!: {GetTimeString(time)}", true, ConsoleColor.Green); recordedBestTime = time; } else { //Print exisiting best time message ConsoleMessages.DisplayMessage($"Best Time: {GetTimeString(bestTime.Value)}", true); recordedBestTime = bestTime.Value; } }
public void DecrementVisibleHandCount(bool drawThreeMode) { if (visibleHandCount > 1) { visibleHandCount--; } else { visibleHandCount = Math.Min(cards.Count, 3); if (cards.Count == 0) { cards = new List <Card>(cycledHandCards); cycledHandCards.Clear(); FlipAllCardsDown(); ConsoleMessages.DisplayMessage("End of deck. All hand cards played", true, ConsoleColor.Green); if (drawThreeMode) { visibleHandCount = 3; } } } }
static void Main(string[] args) { Console.SetWindowSize(70, 30); NewGame(true); Display(); while (true) { CheckForAutoComplete(); if (table.CheckForWin()) { ConsoleMessages.DisplayMessage("Game Over.", true, ConsoleColor.Green); HandleHighScoreAndBestTime(); if (!NewGame(false)) { break; } } GetUserCommand(); Display(); } }
static void GetUserCommand() { Console.WriteLine("\n======================================================================\n"); Console.WriteLine("Enter a command. Type 'Help' to see a list of possible commands."); string input = Console.ReadLine().ToLower(); Console.WriteLine(); if (!ValidateInput(input)) { Console.WriteLine("\n======================================================================\n\n"); return; } string[] inputStrings = input.Split(' '); string firstString = inputStrings[0]; //Move command if (firstString == "move" || firstString == "m") { string sourceCard = inputStrings[1]; string destination = inputStrings[3]; if (!VerifyMove(sourceCard, destination)) { return; } // search in table (bool foundCard, bool continueLooking) = table.MoveCard(sourceCard, destination, ref score); if (foundCard && !continueLooking) { moveCounter++; } else if (!foundCard && continueLooking) { // not found in table, search in hand if (deck.GetTopOfHandName().ToLower() == sourceCard) { Card topCard = deck.RemoveTopCard(); if (table.MoveFromHand(sourceCard, destination, topCard.suit, topCard.value)) { deck.deductPointsForCycle(drawThreeMode, ref score); deck.DecrementVisibleHandCount(drawThreeMode); score += 5; moveCounter++; } } else { if (!table.MoveFromFoundation(sourceCard, destination)) { ConsoleMessages.DisplayMessage("Error: " + sourceCard.ToUpper() + " not available.", true, ConsoleColor.Red); } else { score -= 15; moveCounter++; } } } } //Set Command else if (firstString == "set" || firstString == "s") { string[] strings = input.Split(' '); string sourceCard = strings[1]; table.SetCard(sourceCard, deck, ref score, ref moveCounter, drawThreeMode); } else if (input == "help" || input == "h") { ShowPossibleCommands(); } else if (input == "next" || input == "n") { if (deck.NextCardInHand(drawThreeMode)) { score = drawThreeMode ? Math.Max(score - 20, 0) : Math.Max(score - 100, 0); } } else if (input == "new game" || input == "ng") { NewGame(false); } else if (input == "scoring") { ShowScoringRules(); } else if (input == "show hand") { } else if (input == "undo" || input == "u") { Undo(); } else if (input == "high score" || input == "hs") { ShowHighScore(); } else if (input == "best time" || input == "bt") { ShowBestTime(); } Console.WriteLine("\n======================================================================\n\n"); }
static bool ValidateInput(string input) { string[] strings = input.Split(' '); string error = ""; if (strings.Length == 0) { error = "Error: Invalid input. Type 'help' to see acceptable input."; return(false); } string firstWord = strings[0]; if (firstWord == "move" || firstWord == "m") { //check input word count and second word is "to" if (strings.Length != 4 || strings[2] != "to") { error = "Error: Invalid move input. Type 'help' to see acceptable input."; } //check source and destination length else if (strings[1].Length < 2 || strings[1].Length > 3 || strings[3].Length < 2 || (strings[3].Length > 3 && strings[3] != "empty")) { error = "Error: Source card value must be 2 or 3 characters long. Example: AS or 10D"; } //check valid source card value else if (strings[1][0] != 'a' && strings[1][0] != '2' && strings[1][0] != '3' && strings[1][0] != '4' && strings[1][0] != '5' && strings[1][0] != '6' && strings[1][0] != '7' && strings[1][0] != '8' && strings[1][0] != '9' && strings[1][0] != 'j' && strings[1][0] != 'q' && strings[1][0] != 'k' && (strings[1][0] == '1' && strings[1][1] != '0')) { error = "Error: Invalid source card value. Must be A, J, Q, K, or a value between 2 and 10"; } //check valid source card suit else if (strings[1][strings[1].Length - 1] != 's' && strings[1][strings[1].Length - 1] != 'd' && strings[1][strings[1].Length - 1] != 'c' && strings[1][strings[1].Length - 1] != 'h') { error = "Error: Invalid source card suit. Must be S, D, C, or H. (spades, diamonds, clubs, or hearts)"; } //check valid destination card value else if (strings[3] != "empty" && strings[3][0] != 'a' && strings[3][0] != '2' && strings[3][0] != '3' && strings[3][0] != '4' && strings[3][0] != '5' && strings[3][0] != '6' && strings[3][0] != '7' && strings[3][0] != '8' && strings[3][0] != '9' && strings[3][0] != 'j' && strings[3][0] != 'q' && strings[3][0] != 'k' && (strings[3][0] == '1' && strings[3][1] != '0')) { error = "Error: Invalid destination card value. Must be A, J, Q, K, a value between 2 and 10, or 'empty'"; } //check valid destination card suit else if (strings[3] != "empty" && strings[3][strings[3].Length - 1] != 's' && strings[3][strings[3].Length - 1] != 'd' && strings[3][strings[3].Length - 1] != 'c' && strings[3][strings[3].Length - 1] != 'h') { error = "Error: Invalid destination card suit. Must be S, D, C, or H. (spades, diamonds, clubs, or hearts), destination may also simply be 'empty'"; } } else if (firstWord == "set" || firstWord == "s") { if (strings.Length != 2) { error = "Error: Invalid set input. Type 'help' to see acceptable input."; } } else if (firstWord == "help" || firstWord == "h") { if (strings.Length != 1) { error = "Error: Invalid help input. Type 'help' to see acceptable input."; } } else if (firstWord == "next" || firstWord == "n") { if (strings.Length != 1) { error = "Error: Invalid next input. Type 'help' to see acceptable input."; } } else if (firstWord == "new" || firstWord == "ng") { if (firstWord == "new" && (strings.Length != 2 || strings[1] != "game")) { error = "Error: Invalid input. Type 'help' to see acceptable input."; } } else if (firstWord == "high" || firstWord == "hs") { if (firstWord == "high" && (strings.Length != 2 || strings[1] != "score")) { error = "Error: Invalid input. Type 'help' to see acceptable input."; } } else if (firstWord == "best" || firstWord == "bt") { if (firstWord == "best" && (strings.Length != 2 || strings[1] != "time")) { error = "Error: Invalid input. Type 'help' to see acceptable input."; } } else if (firstWord == "scoring") { if (strings.Length > 1) { error = "Error: Invalid scoring input. Type 'help' to see acceptable input."; } } else if (firstWord == "show") { if (strings.Length != 2 || strings[1] != "hand") { error = "Error: Invalid input. Type 'help' to see acceptable input."; } } else if (firstWord == "undo" || firstWord == "u") { if (strings.Length > 1) { error = "Error: Invalid undo input. Type 'help' to see acceptable input."; } } else { error = "Error: \"" + input + "\" is not a valid command. Type \"Help\" to see a list of valid commands."; } if (error != "") { ConsoleMessages.DisplayMessage(error, true, ConsoleColor.Red); return(false); } return(true); }
public void SetCard(string sourceCardName, Deck deck, ref int score, ref int moveCounter, bool drawThreeMode) { bool fromHand = false; (int sourceColumn, int sourceRow) = GetSourceIndices(sourceCardName); //could not find in table, check in hand if (sourceColumn == -1) { //check that the top of the hand is the source card, else print source card not found and return. if (deck.GetTopOfHandName().ToLower() == sourceCardName) { fromHand = true; } else { ConsoleMessages.DisplayMessage("Source card " + sourceCardName.ToUpper() + " not available", true, ConsoleColor.Red); return; } } if (!IsSetLegal(sourceColumn, sourceRow, fromHand ? deck.GetTopHandCard() : null)) { return; } Card sourceCard; bool canMove = true; if (fromHand) { sourceCard = deck.RemoveTopCard(); deck.deductPointsForCycle(drawThreeMode, ref score); deck.DecrementVisibleHandCount(drawThreeMode); } else { sourceCard = table[sourceColumn][sourceRow]; table[sourceColumn].RemoveAt(sourceRow); } //flip new card if available if (!fromHand && sourceRow != 0 && table[sourceColumn][sourceRow - 1].faceup == false) { table[sourceColumn][sourceRow - 1].faceup = true; score += 5; } if (foundation[sourceCard.suit].Count > 0) { Card topSuitCard = foundation[sourceCard.suit][foundation[sourceCard.suit].Count - 1]; if (sourceCard.suit != topSuitCard.suit || topSuitCard.value + 1 != sourceCard.value) { canMove = false; } } else if (sourceCard.value != 0) { canMove = false; } if (canMove) { foundation[sourceCard.suit].Add(sourceCard); score += 10; moveCounter++; } else { ConsoleMessages.DisplayMessage("Cannot set " + sourceCard.GetReadableCombined(), true, ConsoleColor.Red); } }
public bool NextCardInHand(bool drawThreeMode = false) { bool dockPointsForCycle = false; int cardsToMove = 0; foreach (Card card in cards) { if (card.faceup) { cardsToMove++; } else { break; } } for (int i = 0; i < cardsToMove; i++) { if (cards.Count > 1) { FlipTopCard(); cycledHandCards.Add(cards[0]); cards.RemoveAt(0); if (cards.Count > 0 && (i == cardsToMove - 1)) { if (drawThreeMode) { FlipNextThreeCards(); } else { FlipTopCard(); } } } else if (cards.Count == 0) { if (cycledHandCards.Count == 0) { ConsoleMessages.DisplayMessage("End of deck. All hand cards played", true, ConsoleColor.Green); } else { dockPointsForCycle = drawThreeMode ? cycledCount > 3 : cycledCount > 0; cycledCount++; ConsoleMessages.DisplayMessage("End of deck. Starting from beginning.", true, ConsoleColor.Green); cards = new List <Card>(cycledHandCards); FlipTopCard(); cycledHandCards.Clear(); } } else { dockPointsForCycle = drawThreeMode ? cycledCount > 3 : cycledCount > 0; cycledCount++; ConsoleMessages.DisplayMessage("End of deck. Starting from beginning.", true, ConsoleColor.Green); FlipTopCard(); Card lastCard = cards[0]; cards = new List <Card>(cycledHandCards); cards.Add(lastCard); FlipTopCard(); cycledHandCards.Clear(); if (drawThreeMode) { SetFaceupForCycledDeck(); } else { FlipAllCardsDown(); } } } visibleHandCount = Math.Min(cards.Count, 3); return(dockPointsForCycle); }
static bool VerifyMove(string source, string destination) { //TODO: Leading white space should be acceptable input. string error = ""; char sourceSuit = source.Length >= 2 ? source[source.Length - 1] : 'n'; char destSuit = destination.Length >= 2 ? destination[destination.Length - 1] : 'n'; string sourceValue = source.Substring(0, source.Length - 1); string destValue = destination != "empty" ? destination.Substring(0, destination.Length - 1) : destination; if (sourceValue == "k") { if (destination != "empty") { error = "Error: Invalid move. Can only move a k to \"empty\""; } } else if (sourceSuit == 'n') { error = "Error: invalid source card."; } else if (destSuit == 'n') { error = "Error: invalid destination card."; } else if ((sourceSuit == 's' || sourceSuit == 'c') && (destSuit != 'd' && destSuit != 'h')) { error = "Error: Invalid move. Cannot move suit " + sourceSuit + " to suit " + destSuit; } else if ((sourceSuit == 'd' || sourceSuit == 'h') && (destSuit != 's' && destSuit != 'c')) { error = "Error: Invalid move. Cannot move suit " + sourceSuit + " to suit " + destSuit; } else if (sourceValue == "a") { if (destValue != "2") { error = "Error: Invalid move. Cannot move an a to a " + destValue; } } else if (sourceValue == "j") { if (destValue != "q") { error = "Error: Invalid move. Cannot move a j to a " + destValue; } } else if (sourceValue == "q") { if (destValue != "k") { error = "Error: Invalid move. Cannot move a q to a " + destValue; } } else if (sourceValue == "10") { if (destValue != "j") { error = "Error: Invalid move. Cannot move a 10 to a " + destValue; } } //TODO: Typed 'move q0s to jh' accidentally and caused an exception here else if (Int32.Parse(sourceValue) != Int32.Parse(destValue) - 1) { error = "Error: Invalid move. Cannot move a " + sourceValue + " to a " + destValue; } if (error != "") { ConsoleMessages.DisplayMessage(error, true, ConsoleColor.Red); Console.WriteLine("\n======================================================================\n\n"); return(false); } return(true); }