mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2026-01-05 01:27:42 -08:00
add C# Acey Ducey by Adam Dawes
This commit is contained in:
8
01 Acey Ducey/csharp/AceyDucey.csproj
Normal file
8
01 Acey Ducey/csharp/AceyDucey.csproj
Normal file
@@ -0,0 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
25
01 Acey Ducey/csharp/AceyDucey.sln
Normal file
25
01 Acey Ducey/csharp/AceyDucey.sln
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30709.132
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AceyDucey", "AceyDucey.csproj", "{A8FE2F04-3DFE-4254-BD5B-281DC8E30B1C}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{A8FE2F04-3DFE-4254-BD5B-281DC8E30B1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A8FE2F04-3DFE-4254-BD5B-281DC8E30B1C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A8FE2F04-3DFE-4254-BD5B-281DC8E30B1C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A8FE2F04-3DFE-4254-BD5B-281DC8E30B1C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {F620B340-EB7A-48C1-B12F-9D3D94AE7771}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
326
01 Acey Ducey/csharp/Game.cs
Normal file
326
01 Acey Ducey/csharp/Game.cs
Normal file
@@ -0,0 +1,326 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace AceyDucey
|
||||
{
|
||||
/// <summary>
|
||||
/// The main class that implements all the game logic
|
||||
/// </summary>
|
||||
internal class Game
|
||||
{
|
||||
/// <summary>
|
||||
/// Our Random number generator object
|
||||
/// </summary>
|
||||
private Random Rnd { get; } = new Random();
|
||||
|
||||
/// <summary>
|
||||
/// A line of underscores that we'll print between turns to separate them from one another on screen
|
||||
/// </summary>
|
||||
private string SeparatorLine { get; } = new string('_', 70);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Main game loop function. This will play the game endlessly until the player chooses to quit.
|
||||
/// </summary>
|
||||
internal void GameLoop()
|
||||
{
|
||||
// First display instructions to the player
|
||||
DisplayIntroText();
|
||||
|
||||
// We'll loop for each game until the player decides not to continue
|
||||
do
|
||||
{
|
||||
// Play a game!
|
||||
PlayGame();
|
||||
|
||||
// Play again?
|
||||
} while (TryAgain());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Play the game
|
||||
/// </summary>
|
||||
private void PlayGame()
|
||||
{
|
||||
GameState state = new GameState();
|
||||
|
||||
// Clear the display
|
||||
Console.Clear();
|
||||
// Keep looping until the player has no money left
|
||||
do
|
||||
{
|
||||
// Play the next turn. Pass in our state object so the turn can see the money available,
|
||||
// can update it after the player makes a bet, and can update the turn count.
|
||||
PlayTurn(state);
|
||||
|
||||
// Keep looping until the player runs out of money
|
||||
} while (state.Money > 0);
|
||||
|
||||
// Looks like the player is bankrupt, let them know how they did.
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
Console.WriteLine("");
|
||||
Console.WriteLine($"Sorry, friend, but you blew your wad. Your game is over after {state.TurnCount} {(state.TurnCount == 1 ? "turn" : "turns")}. Your highest balance was ${state.MaxMoney}.");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Play a turn
|
||||
/// </summary>
|
||||
/// <param name="state">The current game state</param>
|
||||
private void PlayTurn(GameState state)
|
||||
{
|
||||
// Let the player know what's happening
|
||||
Console.WriteLine("");
|
||||
Console.WriteLine(SeparatorLine);
|
||||
Console.WriteLine("");
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
Console.WriteLine("");
|
||||
Console.WriteLine("Here are your next two cards:");
|
||||
|
||||
// Generate two random cards
|
||||
int firstCard = GetCard();
|
||||
int secondCard = GetCard();
|
||||
|
||||
// If the second card is lower than the first card, swap them over
|
||||
if (secondCard < firstCard)
|
||||
{
|
||||
(firstCard, secondCard) = (secondCard, firstCard);
|
||||
}
|
||||
|
||||
// Display the cards
|
||||
DisplayCard(firstCard);
|
||||
DisplayCard(secondCard);
|
||||
|
||||
// Ask the player what they want to do
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
Console.WriteLine("");
|
||||
Console.Write("You currently have ");
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
Console.Write($"${state.Money}");
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
Console.WriteLine(". How much would you like to bet?");
|
||||
|
||||
// Read the bet amount
|
||||
int betAmount = PlayTurn_GetBetAmount(state.Money);
|
||||
|
||||
// Display a summary of their inpout
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
Console.WriteLine("");
|
||||
Console.WriteLine($"You choose to {(betAmount == 0 ? "pass" : $"bet {betAmount}")}.");
|
||||
|
||||
// Generate and display the final card
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
Console.WriteLine("");
|
||||
Console.WriteLine("The next card is:");
|
||||
|
||||
int thirdCard = GetCard();
|
||||
DisplayCard(thirdCard);
|
||||
Console.WriteLine("");
|
||||
|
||||
// Was the third card between the first two cards?
|
||||
if (thirdCard > firstCard && thirdCard < secondCard)
|
||||
{
|
||||
// It was! Inform the player and add to their money
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
Console.WriteLine("You win!");
|
||||
if (betAmount == 0)
|
||||
{
|
||||
Console.WriteLine("(It's just a shame you chose not to bet!)");
|
||||
}
|
||||
else
|
||||
{
|
||||
state.Money += betAmount;
|
||||
// If their money exceeds the MaxMoney, update that too
|
||||
state.MaxMoney = Math.Max(state.Money, state.MaxMoney);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Oh dear, the player lost. Let them know the bad news and take their bet from their money
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
Console.WriteLine("You lose!");
|
||||
if (betAmount == 0)
|
||||
{
|
||||
Console.WriteLine("(It's lucky you chose not to bet!)");
|
||||
}
|
||||
else
|
||||
{
|
||||
state.Money -= betAmount;
|
||||
}
|
||||
}
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
Console.Write("You now have ");
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
Console.Write($"${state.Money}");
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
Console.WriteLine(".");
|
||||
|
||||
// Update the turn count now that another turn has been played
|
||||
state.TurnCount += 1;
|
||||
|
||||
// Ready for the next turn...
|
||||
Console.ForegroundColor = ConsoleColor.DarkGreen;
|
||||
Console.WriteLine("");
|
||||
Console.WriteLine("Press any key to continue...");
|
||||
Console.ReadKey(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prompt the user for their bet amount and validate their input
|
||||
/// </summary>
|
||||
/// <param name="currentMoney">The player's current money</param>
|
||||
/// <returns>Returns the amount the player chooses to bet</returns>
|
||||
private int PlayTurn_GetBetAmount(int currentMoney)
|
||||
{
|
||||
int betAmount;
|
||||
// Loop until the user enters a valid value
|
||||
do
|
||||
{
|
||||
// Move this to a separate function...
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
Console.Write("> $");
|
||||
string input = Console.ReadLine();
|
||||
|
||||
// Is this a valid number?
|
||||
if (!int.TryParse(input, out betAmount))
|
||||
{
|
||||
// No
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine("Sorry, I didn't understand. Please enter how much you would like to bet.");
|
||||
// Continue looping
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the amount between 0 and their available money?
|
||||
if (betAmount < 0 || betAmount > currentMoney)
|
||||
{
|
||||
// No
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine($"Please enter a bet amount between $0 and ${currentMoney}.");
|
||||
// Continue looping
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have a valid bet, stop looping
|
||||
break;
|
||||
} while (true);
|
||||
|
||||
// Return whatever the player entered
|
||||
return betAmount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a new random card.
|
||||
/// </summary>
|
||||
/// <returns>Will return a value between 2 and 14, inclusive.</returns>
|
||||
/// <remarks>Values 2 to 10 are their face values. 11 represents a Jack, 12 is a Queen, 13 a King and 14 an Ace.
|
||||
/// Even though this is a slightly offset sequence, it allows us to perform a simple greater-than/less-than
|
||||
/// comparison with the card values, treating an Ace as a high card.</remarks>
|
||||
private int GetCard()
|
||||
{
|
||||
return Rnd.Next(2, 15);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display the card number on screen, translating values 11 through to 14 into their named equivalents.
|
||||
/// </summary>
|
||||
/// <param name="card"></param>
|
||||
private void DisplayCard(int card)
|
||||
{
|
||||
string cardText;
|
||||
switch (card)
|
||||
{
|
||||
case 11:
|
||||
cardText = "Jack";
|
||||
break;
|
||||
case 12:
|
||||
cardText = "Queen";
|
||||
break;
|
||||
case 13:
|
||||
cardText = "King";
|
||||
break;
|
||||
case 14:
|
||||
cardText = "Ace";
|
||||
break;
|
||||
default:
|
||||
cardText = card.ToString();
|
||||
break;
|
||||
}
|
||||
|
||||
// Format as black text on a white background
|
||||
Console.Write(" ");
|
||||
Console.BackgroundColor = ConsoleColor.White;
|
||||
Console.ForegroundColor = ConsoleColor.Black;
|
||||
Console.Write($" {cardText} ");
|
||||
Console.BackgroundColor = ConsoleColor.Black;
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
Console.WriteLine("");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display instructions on how to play the game and wait for the player to press a key.
|
||||
/// </summary>
|
||||
private void DisplayIntroText()
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
Console.WriteLine("Acey Ducey Gard Game.");
|
||||
Console.WriteLine("Creating Computing, Morristown, New Jersey.");
|
||||
Console.WriteLine("");
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.DarkGreen;
|
||||
Console.WriteLine("Originally published in 1978 in the book 'Basic Computer Games' by David Ahl.");
|
||||
Console.WriteLine("Modernised and converted to C# in 2021 by Adam Dawes (@AdamDawes575).");
|
||||
Console.WriteLine("");
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
Console.WriteLine("Acey Ducey is played in the following manner:");
|
||||
Console.WriteLine("");
|
||||
Console.WriteLine("The dealer (computer) deals two cards, face up.");
|
||||
Console.WriteLine("");
|
||||
Console.WriteLine("You have an option to bet or pass, depending on whether or not you feel the next card will have a value between the");
|
||||
Console.WriteLine("first two.");
|
||||
Console.WriteLine("");
|
||||
Console.WriteLine("If the card is between, you will win your stake, otherwise you will lose it. Ace is 'high' (higher than a King).");
|
||||
Console.WriteLine("");
|
||||
Console.WriteLine("If you want to pass, enter a bet amount of $0.");
|
||||
Console.WriteLine("");
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
Console.WriteLine("Press any key start the game.");
|
||||
Console.ReadKey(true);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prompt the player to try again, and wait for them to press Y or N.
|
||||
/// </summary>
|
||||
/// <returns>Returns true if the player wants to try again, false if they have finished playing.</returns>
|
||||
private bool TryAgain()
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
Console.WriteLine("Would you like to try again? (Press 'Y' for yes or 'N' for no)");
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
Console.Write("> ");
|
||||
|
||||
char pressedKey;
|
||||
// Keep looping until we get a recognised input
|
||||
do
|
||||
{
|
||||
// Read a key, don't display it on screen
|
||||
ConsoleKeyInfo key = Console.ReadKey(true);
|
||||
// Convert to upper-case so we don't need to care about capitalisation
|
||||
pressedKey = Char.ToUpper(key.KeyChar);
|
||||
// Is this a key we recognise? If not, keep looping
|
||||
} while (pressedKey != 'Y' && pressedKey != 'N');
|
||||
// Display the result on the screen
|
||||
Console.WriteLine(pressedKey);
|
||||
|
||||
// Return true if the player pressed 'Y', false for anything else.
|
||||
return (pressedKey == 'Y');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
39
01 Acey Ducey/csharp/GameState.cs
Normal file
39
01 Acey Ducey/csharp/GameState.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace AceyDucey
|
||||
{
|
||||
/// <summary>
|
||||
/// The GameState class keeps track of all the game variables while the game is being played
|
||||
/// </summary>
|
||||
internal class GameState
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// How much money does the player have at the moment?
|
||||
/// </summary>
|
||||
internal int Money { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// What's the highest amount of money they had at any point in the game?
|
||||
/// </summary>
|
||||
internal int MaxMoney { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// How many turns have they played?
|
||||
/// </summary>
|
||||
internal int TurnCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Class constructor -- initialise all values to their defaults.
|
||||
/// </summary>
|
||||
internal GameState()
|
||||
{
|
||||
// Setting Money to 100 gives the player their starting balance. Changing this will alter how much they have to begin with.
|
||||
Money = 100;
|
||||
MaxMoney = Money;
|
||||
TurnCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
27
01 Acey Ducey/csharp/Program.cs
Normal file
27
01 Acey Ducey/csharp/Program.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace AceyDucey
|
||||
{
|
||||
/// <summary>
|
||||
/// The application's entry point
|
||||
/// </summary>
|
||||
class Program
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This function will be called automatically when the application begins
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
static void Main(string[] args)
|
||||
{
|
||||
// Create an instance of our main Game class
|
||||
Game game = new Game();
|
||||
|
||||
// Call its GameLoop function. This will play the game endlessly in a loop until the player chooses to quit.
|
||||
game.GameLoop();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
|
||||
Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/) by Adam Dawes (@AdamDawes575, https://adamdawes.com).
|
||||
|
||||
Reference in New Issue
Block a user