Please also see the new version here
So I've been trying to make a blackjack game as my first attempt at an OOP project. The program is working, but not yet finished as it is lacking three major features that I couldn't figure out how to implement.
Not being able to deal the same card more than onceAutomatically changing the value of Aces to 1 or 11 depending on the handThe dealer's secret card
Also, I originally had the player and house hit methods in their respective classes but there were some issues in the event of the player going bust. Mainly I'm intrested code readabillity, commenting, naming, efficiency, code practicallity, class and method splitting. Also I'm afraid that I have made the cove needlessly complicated, if that is the case please mention that too in your review. Here is my old code (I posted a self answer with my changes and addition of the missing features).
Program Class:
using System;
namespace Blackjack_21
{
class Program
{
static void Main(string[] args)
{
//Variable declaration
Console.Write("Insert a name: ");
string playerName = Console.ReadLine();
bool play = true;
while (play == true)
{
Game game = new Game();
game.Play(playerName);
Console.WriteLine("Press ENTER to continue");
Console.ReadLine();
Console.Clear();
//ask for replay
Console.Write("Do you want to play again? yes/no: ");
bool answer = true;
string ans = Console.ReadLine();
//Looping until a correct answer is given
while (answer)
{
if (ans == "y" || ans == "Y" || ans == "yes" || ans == "YES")
{
play = true;
answer = false;
}
else if (ans == "n" || ans == "N" || ans == "no" || ans == "NO")
{
play = false;
answer = false;
}
else
{
Console.Write("error, unexpected input\nPlease type y or n ");
ans = Console.ReadLine();
}
}
Console.Clear();
}
}
}
}
Game Class:
using System;
namespace Blackjack_21
{
enum Status
{
gameOn,
playerWin,
houseWin,
draw,
blackjack
}
class Game
{
byte status = (byte)Status.gameOn;
House house = new House();
Player player1 = new Player("");
Card deck = new Card();
//player hits as many times as he wants when < 21
public int PlayerHit()
{
if (!player1.Bust)
{
Console.Write("{0} Hits", player1.Name);
player1.Hand += deck.DealCard();
}
return player1.Hand;
}
public int HouseHit()
{
while (house.Hand < 16)
{
Console.Write("The House Hits");
house.Hand += deck.DealCard();
}
house.Stand();
return house.Hand;
}
public void Play(string pName)
{
player1.Name = pName;
bool playerIsBust = player1.CheckPlayerBust();
//Initial cards
PlayerHit();
PlayerHit();
Console.Write("The House hits");
house.Hand += deck.DealCard();
//Player wins automatically if he has a "blackjack"
if (player1.HasBlackjack() == true)
{
Console.WriteLine($"{player1.Name} has a Blackjack!");
status = (byte)Status.blackjack;
}
else
{
//loops as long as the player hasn't gone bust
while (!playerIsBust && !player1.isStanding)
{
//Player gives input
Console.WriteLine($"It is {player1.Name}'s turn:");
Console.WriteLine("Press H to hit Press S to stand" +
"\nPress V to view your hand press D to view the House's hand");
string input = Console.ReadLine();
//input check
if (input == "h" || input == "H")
{
PlayerHit();
}
else if (input == "s" || input == "S")
{
player1.Stand();
break;
}
else if (input == "v" || input == "V")
{
player1.ViewHand();
}
else if (input == "d" || input == "D")
{
house.ViewHand();
}
else
{
Console.Write("Unknown command\nPlease type a valid command ");
input = Console.ReadLine();
}
playerIsBust = player1.CheckPlayerBust();
/*Check for Aces here:
if(player has aces)
{
make aces value 1 until his hand < 22
}
*/
}
if (playerIsBust == true)
{
Console.WriteLine("{0}'s hand is {1} so he goes bust"
, player1.Name, player1.Hand);
}
HouseHit();
CompareHands();
}
AnounceWinner();
}
public void AnounceWinner()
{
switch (status)
{
case 1:
Console.WriteLine($"{player1.Name} wins!");
break;
case 2:
Console.WriteLine("The House wins!");
break;
case 3:
Console.WriteLine("Is is a draw");
break;
case 4:
Console.WriteLine($"{player1.Name} wins!");
break;
}
}
void CompareHands()
{
if (player1.Hand > 21)
player1.Hand = 0;
if (house.Hand > 21)
house.Hand = 0;
if (player1.Hand > house.Hand)
{
status = (byte)Status.playerWin;
}
else if (house.Hand > player1.Hand)
{
status = (byte)Status.houseWin;
}
else
{
status = (byte)Status.draw;
}
if (player1.Bust && house.bust)
{
status = (byte)Status.draw;
}
}
}
}
House Class:
using System;
namespace Blackjack_21
{
class House
{
public int Hand = 0;
public bool bust = false;
public void Stand()
{
CheckHouseBust();
if (bust)
{
Console.WriteLine("The Houses's hand was {0} so it went bust", Hand);
Hand = 0;
}
else
{
Console.WriteLine("The House stands at {0}", Hand);
}
}
public void ViewHand()
{
Console.WriteLine("The House's hand is {0}", Hand);
}
bool CheckHouseBust()
{
return bust = (Hand > 21) ? true : false;
}
}
}
Player Class:
using System;
namespace Blackjack_21
{
class Player
{
public string Name { get; set; }
public int Hand = 0;
public bool Bust = false;
public bool isStanding = false;
public Player(string name = "")
{
Name = name;
}
public bool HasBlackjack()
{
return (Hand == 21) ? true : false;
}
public void Stand()
{
if(!Bust)
{
Console.WriteLine("{0} stands at {1}", Name, Hand);
}
isStanding = true;
}
public void ViewHand()
{
Console.WriteLine("{0}'s hand is {1}", Name, Hand);
}
public bool CheckPlayerBust()
{
return Bust = (Hand > 21) ? true : false;
}
}
}
Card Class:
using System;
using System.Collections.Generic;
namespace Blackjack_21
{
class Card
{
//TODO:
//can't deal the same card
//value of 1 or 11 for ace to be assigned based on hand
private readonly Random randCard = new Random(DateTime.Now.Millisecond);
public int DealCard()
{
IDictionary<int, string> numbers = new Dictionary<int, string>
{
{ 2, "Two" },
{ 3, "Three" },
{ 4, "Four" },
{ 5, "Five" },
{ 6, "Six" },
{ 7, "Seven" },
{ 8, "Eight" },
{ 9, "Nine" },
{ 10, "Ten" },
{ 11, "Jack" },
{ 12, "Queen" },
{ 13, "King" },
{ 14, "Ace" }
};
IDictionary<int, string> suits = new Dictionary<int, string>
{
{ 1, "Spades" },
{ 2, "Diamonds" },
{ 3, "Hearts" },
{ 4, "Clubs" }
};
int value = randCard.Next(2, 15);
int suit = randCard.Next(1, 5);
Console.Write(" and was dealt the {0} of {1}\n"
, numbers[value], suits[suit]);
//Making the faces have value of 10
if(value > 10 && value < 14)
{
value = 10;
}
//Making the Aces have value of 11
if (value == 14)
{
value = 11;
}
return value;
}
}
}
I don't know if including the namespace and "using System" is needed in every code snippet so I decided to include them.