Skip to content
Snippets Groups Projects
Commit 6c7a6a4a authored by bionic85's avatar bionic85
Browse files

Merge branch 'BlackJack'

parents e1cea94b c7ed7df2
No related branches found
No related tags found
No related merge requests found
using Microsoft.VisualBasic.Devices;
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Drawing.Drawing2D;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace PuzzlePlayer_Namespace
{
enum BJSTATE // the different states the game can be in
enum BJRESULTS // the different results after a round
{
Setup, // choose how much money the player deploys
Game, // play the game
Result, // see te result and then restart
Lost,
Won,
Blackjack, // player scored 21 points
Draw // same score
}
struct Card
{
string name; // for drawing the card, needs to be in format num_of_kind
int value; // value of the card
int value2; // some cards have two values
public string name; // for drawing the card, needs to be in format num_of_kind
public int value; // value of the card
public Card(string n, int val)
{
name = n;
value = val;
}
}
internal class BlackJack : Form
{
BJSTATE state;
BJRESULTS result;
bool roundFinished = false;
bool resultReady = false;
int money;
int deployedMoney = 0;
readonly FontFamily BJFont = FontFamily.GenericSansSerif;
readonly int defaultFontSize;
const double cardMultply = 1.4; //double to go from the width of the card to the height
const int aceValueMax = 11; //the two values of a ace
const int aceValueMin = 1;
const int BLACKJACK = 21; //the value to get blackjack
Size screen = Screen.PrimaryScreen.WorkingArea.Size;
// visibility depends on game state
Panel SetupPanel;
Panel GamePanel;
Panel ResultPanel;
Button RestartButton;
List<Card> cards;
List<Card> cardsLeft;
List<Card> playerCards = new();
List<(Card,bool)> dealerCards = new(); // boolean is to keep track if the card is visable
(int,string,Color)[] chipInfo = { (5,"5",Color.Gray), (25, "25", Color.Blue), (50, "50", Color.Green), (100, "100", Color.DarkCyan), (500, "500", Color.Purple), (1000, "1K", Color.Red), (5000, "5K", Color.Orange), (10000, "10K", Color.Gold) };
public object Int { get; private set; }
public BlackJack()
{
state = BJSTATE.Setup;
result = BJRESULTS.Lost; //init
WindowState = FormWindowState.Maximized;
DoubleBuffered = true;
BackColor = Color.DarkGreen;
Paint += BlackJack_Paint;
defaultFontSize = screen.Width / 50;
money = ReadMoney();
cardsLeft = getAllCards();
SetupUI();
}
List<Card> getAllCards() // returns a list with all the 52 classic cards
{
List<Card> cards = new List<Card>();
string[] numbers = { "2", "3", "4", "5", "6", "7", "8", "9", "10", "ace", "jack", "king", "queen" };
string[] kinds = { "clubs", "diamonds", "hearts", "spades" };
foreach (string kind in kinds)
{
foreach (string num in numbers)
{
int val;
if (num == "jack" || num == "king" || num == "queen")
val = 10;
else if (num == "ace") // an ace is worth either 1 or 11, the logic for this is handled in GetValue()
val = 11;
else
val = int.Parse(num);
cards.Add(new Card(num + "_of_" + kind,val));
}
}
cards.Shuffle();
return cards;
}
private int ReadMoney() //TODO read money from local file
{
return 1000;
......@@ -65,23 +103,25 @@ namespace PuzzlePlayer_Namespace
private void SetupUI()
{
//Setup
//setup
#region SetupPanel
SetupPanel = new Panel();
SetupPanel.Size = new Size(screen.Width/2,screen.Height);
SetupPanel.Location = new Point(screen.Width / 4, 0);
SetupPanel.Size = screen; //SetupPanel.Size = new Size(screen.Width/2,screen.Height);
SetupPanel.Location = new Point(0, 0); //SetupPanel.Location = new Point(screen.Width / 4, 0);
//DefaultPanel.BackColor = Color.Blue; //DEBUG
SetupPanel.Paint += Setup_Paint;
//money buttons
int goofyIndex = 0; //dw
for(int j = 1; j <= 2; j++)
for(int i = 0; i < 4; i++)
const int rows = 4;
const int cols = 2;
for(int j = 1; j <= cols; j++)
for(int i = 0; i < rows; i++)
{
Button b = new Button();
b.Size = new Size(SetupPanel.Width / 4, SetupPanel.Height / 6); // /2
b.Location = new Point(i * b.Size.Width, SetupPanel.Height - b.Size.Height*j);
b.Size = new Size(SetupPanel.Width / 8, SetupPanel.Height / 6); // w/8
b.Location = new Point(i * b.Size.Width + rows / 2 * b.Size.Width, SetupPanel.Height - b.Size.Height * j);
b.Name = goofyIndex.ToString(); // for getting the index for chipInfo later
(int, string, Color) chip = chipInfo[goofyIndex];
......@@ -89,7 +129,7 @@ namespace PuzzlePlayer_Namespace
b.BackColor = chip.Item3;
b.Font = new Font(BJFont, b.Size.Width / 5);
b.Click += moneyButtonClick;
b.Click += MoneyButtonClick;
SetupPanel.Controls.Add(b);
goofyIndex++;
......@@ -102,44 +142,65 @@ namespace PuzzlePlayer_Namespace
dealButton.Location = new Point(SetupPanel.Width /2 - dealButton.Width/2, SetupPanel.Height /4);
dealButton.Font = new Font(BJFont, dealButton.Size.Width / 5);
dealButton.BackColor = Color.DodgerBlue;
dealButton.Click += (object o, EventArgs e) =>
{
if (deployedMoney == 0)
return;
SetupPanel.Hide();
GamePanel.Show();
state = BJSTATE.Game;
};
dealButton.Click += DealButtonClick;
SetupPanel.Controls.Add(dealButton);
Controls.Add(SetupPanel);
#endregion
//Game
//game
#region GamePanel
GamePanel = new Panel();
GamePanel.Paint += Game_Paint;
GamePanel.Size = new Size((int)(screen.Width / 1.5), screen.Height);
GamePanel.Location = new Point((screen.Width - GamePanel.Size.Width)/2, 0);
GamePanel.BackColor = Color.Red; //DEBUG
GamePanel.Size = screen; //GamePanel.Size = new Size((int)(screen.Width / 1.5), screen.Height);
GamePanel.Location = new Point(0, 0); //GamePanel.Location = new Point((screen.Width - GamePanel.Size.Width)/2, 0);
//GamePanel.BackColor = Color.Red; //DEBUG
//buttons
Button HitButton = new Button();
HitButton.Text = "HIT";
HitButton.Click += (object sender, EventArgs e) =>
{
if (roundFinished) // don't let the player draw cards when the round is already finished
return;
playerCards.Add(PopCard());
Invalidate(true);
if (getValue(playerCards) >= BLACKJACK) //if it is a bust or blackjack the game is automaticly over
EndGame();
};
HitButton.BackColor = Color.Red;
HitButton.Size = new Size(GamePanel.Width/5, GamePanel.Height/5);
HitButton.Location = new Point(GamePanel.Width/4 - HitButton.Width/2, GamePanel.Height / 2 - HitButton.Size.Height / 2);
HitButton.Font = new Font(BJFont, HitButton.Size.Width/3, FontStyle.Bold);
GamePanel.Controls.Add(HitButton);
// stand button
Button StandButton = new Button();
StandButton.Text = "STAND";
StandButton.Click += (object sender, EventArgs e) => EndGame();
StandButton.BackColor = Color.Blue;
StandButton.Size = HitButton.Size;
StandButton.Location = new Point(GamePanel.Width - GamePanel.Width/4 - StandButton.Width/2, HitButton.Location.Y);
StandButton.Font = new Font(BJFont, StandButton.Width / 6,FontStyle.Bold);
GamePanel.Controls.Add(StandButton);
RestartButton = new Button();
RestartButton.Text = "Next Round";
RestartButton.Click += RestartButtonClick;
RestartButton.BackColor = Color.DarkCyan;
RestartButton.Size = HitButton.Size;
RestartButton.Location = new Point(GamePanel.Width / 2 - RestartButton.Width / 2, HitButton.Location.Y);
RestartButton.Font = new Font(BJFont, RestartButton.Width / 6, FontStyle.Bold);
RestartButton.Hide(); // hide until game state is reached
GamePanel.Controls.Add(RestartButton);
GamePanel.Hide(); //Hide until the game state is reached
Controls.Add(GamePanel);
#endregion
//Result
#region ResultPanel
ResultPanel = new Panel();
ResultPanel.Hide(); //Hide until the result state is reached
Controls.Add(ResultPanel);
#endregion
}
private void moneyButtonClick(object sender, EventArgs e)
//button logic
private void MoneyButtonClick(object sender, EventArgs e)
{
Button b = (Button) sender;
(int, string, Color) chip = chipInfo[int.Parse(b.Name)];
......@@ -152,36 +213,135 @@ namespace PuzzlePlayer_Namespace
Invalidate(true);
}
private void BlackJack_Paint(object sender, PaintEventArgs e)
private void DealButtonClick(object sender, EventArgs e)
{
Graphics g = e.Graphics;
if (deployedMoney == 0)
return;
SetupPanel.Hide();
playerCards.Add(PopCard()); // give both dealer and player cards
dealerCards.Add((PopCard(), false)); //hided card
playerCards.Add(PopCard());
dealerCards.Add((PopCard(), true)); //visable card
//default draw
Font moneyFont = new Font(BJFont, screen.Width/50, FontStyle.Bold);
g.DrawString("Money: " + money.ToString(), moneyFont, Brushes.Black, new PointF(0,0));
GamePanel.Show();
result = BJRESULTS.Won;
}
private void RestartButtonClick(object sender, EventArgs e) //reset everything
{
result = BJRESULTS.Lost;
deployedMoney = 0;
roundFinished = false;
resultReady = false;
/*
switch(state) // paint according to the current state
playerCards.Clear();
dealerCards.Clear();
RestartButton.Hide();
GamePanel.Hide();
SetupPanel.Show();
}
// end of the game, fancy async methode
private async void EndGame()
{
if(roundFinished)
return; //only run it once
roundFinished = true;
// check for blackjack or bust (above 21 so player loses)
int playerScore = getValue(playerCards);
if (playerScore == BLACKJACK)
result = BJRESULTS.Blackjack;
else if (playerScore > BLACKJACK)
result = BJRESULTS.Lost;
else // if the player scored below 21 then the dealer must draw cards
await DealerAnimation(); // fancy Asynchronous animation function
switch (result)
{
case BJSTATE.Setup:
//Setup_Paint(g);
case BJRESULTS.Lost:
break;
case BJSTATE.Game:
//Game_Paint(g);
case BJRESULTS.Won:
case BJRESULTS.Blackjack:
money += deployedMoney * 2;
break;
case BJSTATE.Result:
//Result_Paint(g);
case BJRESULTS.Draw:
money += deployedMoney;
break;
}*/
}
RestartButton.Show();
resultReady = true;
Invalidate(true);
}
private Task DealerAnimation()
{
return Task.Factory.StartNew(() =>
{
Thread.Sleep(200); //wait 0.2 sec for the fun
for (int i = 0; i < dealerCards.Count; i++) // flip all the cards that where invisable
if (!dealerCards[i].Item2)
dealerCards[i] = (dealerCards[i].Item1, true);
Invalidate(true);
Thread.Sleep(1000); // just a little more
int playerScore = getValue(playerCards);
int dealerScore = getValue(getVisableDealerCards());
// the dealer must hit until it has 17 or more points
// if the dealer has 17 points and a ace in hand then the dealer must also hit (dealer will hit on soft 17 type shit)
// also if the dealer has a higher score then the player then the dealer won, so no need to push the luck and draw more cards
// if the dealer has the same score then it is a draw and the dealer will not draw more cards
while ((dealerScore < 17 && dealerScore < playerScore) || DealerHasSoft17())
{
dealerCards.Add((PopCard(), true));
dealerScore = getValue(getVisableDealerCards()); // update dealer score
Invalidate(true);
Thread.Sleep(1000);
}
Thread.Sleep(500);
if (dealerScore > BLACKJACK) // dealer bust
result = BJRESULTS.Won;
else if (dealerScore > playerScore) // dealer has higher score then player
result = BJRESULTS.Lost;
else if (dealerScore == playerScore)
result = BJRESULTS.Draw;
else
result = BJRESULTS.Won;
});
}
private bool DealerHasSoft17() // fancy blackjack rule
{
List<Card> cards = getVisableDealerCards();
if (getValue(cards) != 17)
return false;
foreach (Card card in cards)
{
if(card.value == 11) // check if the dealer has a ace
return true;
}
return false;
}
// paint events for all the different states
private void Setup_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
DrawMoney(g);
// draw deployd money
// Might update this to butiful chipss
string s = "Deployd Money: " + deployedMoney.ToString();
Font deplMoneyFont = new Font(BJFont, SetupPanel.Width / 20, FontStyle.Bold);
// Might update this to butiful chipss TODO
string s = "Deployed Money: $" + deployedMoney.ToString();
Font deplMoneyFont = new Font(BJFont, SetupPanel.Width / 40, FontStyle.Bold);
SizeF pf = g.MeasureString(s, deplMoneyFont);
PointF p = new PointF(SetupPanel.Width / 2 - pf.Width / 2, SetupPanel.Height / 2);
g.DrawString(s, deplMoneyFont, Brushes.Black, p);
......@@ -190,14 +350,108 @@ namespace PuzzlePlayer_Namespace
private void Game_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
DrawCard(g, new Point(0, 0), 200, "9_of_spades");
DrawMoney(g);
int cardWidth = screen.Width/8; //lucky number
int cardHeight = (int)(cardWidth * cardMultply);
// draw cards for player and dealer
for(int i = 0; i < playerCards.Count; i++)
{
int centerOffsetX = GamePanel.Width/2 - playerCards.Count * cardWidth/2; //to get the cards perfectly in the middle
Point p = new Point(centerOffsetX + i * cardWidth, screen.Height - cardHeight);
DrawCard(g, p, cardWidth, playerCards[i].name);
}
for (int i = 0; i < dealerCards.Count; i++)
{
int centerOffsetX = GamePanel.Width / 2 - dealerCards.Count * cardWidth / 2;
Point p = new Point(centerOffsetX + i * cardWidth, 0);
if (dealerCards[i].Item2)
DrawCard(g, p, cardWidth, dealerCards[i].Item1.name);
else
DrawCard(g, p, cardWidth, "back"); //if not visable draw backside of card
}
//draw player and dealer points
int playerValue = getValue(playerCards);
int dealerValue = getValue(getVisableDealerCards());
string playerString = $"Player: {playerValue} points";
string dealerString = $"Dealer: {dealerValue} points";
Font f = new Font(BJFont, defaultFontSize,FontStyle.Bold);
SizeF playerSF = g.MeasureString(playerString, f);
PointF playerStrPos = new PointF(GamePanel.Width / 2 - playerSF.Width / 2, GamePanel.Height - cardHeight - playerSF.Height);
g.DrawString(playerString, f, Brushes.Black, playerStrPos);
SizeF dealerSF = g.MeasureString(dealerString, f);
PointF dealerStrPos = new PointF(GamePanel.Width / 2 - dealerSF.Width / 2, cardHeight);
g.DrawString(dealerString, f, Brushes.Black, dealerStrPos);
//draw deployed money
string deployedString = $"Playing for ${deployedMoney}";
SizeF deployedSF = g.MeasureString(deployedString, f);
PointF deployedStrPos = new PointF(GamePanel.Width/2 - deployedSF.Width / 2,GamePanel.Height/2 - deployedSF.Height/2);
g.DrawString(deployedString,f, Brushes.Black, deployedStrPos);
// draw result text when ready
if (resultReady)
Result_Paint(g);
}
private void DrawMoney(Graphics g)
{
Font moneyFont = new Font(BJFont, defaultFontSize, FontStyle.Bold);
g.DrawString("Money: $" + money.ToString(), moneyFont, Brushes.Black, new PointF(0, 0));
}
private void Result_Paint(Graphics g)
{
string resultText = "";
string moneyText = "";
Color c = Color.Red;
Font resFont = new Font(BJFont, screen.Width / 10,FontStyle.Bold);
Font moneyFont = new Font(BJFont, screen.Width / 20, FontStyle.Underline);
}
switch (result)
{
case BJRESULTS.Lost:
resultText = "YOU LOSE";
moneyText = $"You lost -${deployedMoney}";
break;
case BJRESULTS.Won:
resultText = "YOU WINNN";
moneyText = $"You won ${deployedMoney * 2}";
c = Color.LimeGreen;
break;
case BJRESULTS.Blackjack:
resultText = "!BLACKJACK!";
moneyText = $"You won ${deployedMoney * 2}";
c = Color.Gold;
break;
case BJRESULTS.Draw:
resultText = "Draw";
moneyText = $"You got your ${deployedMoney} back";
c = Color.Gray;
break;
}
SizeF resSize = g.MeasureString(resultText, resFont);
Point resPos = new Point(GamePanel.Width / 2 - (int)(resSize.Width / 2), GamePanel.Height / 5 - (int)(resSize.Height / 2));
SizeF moneySize = g.MeasureString (moneyText, moneyFont);
Point moneyPos = new Point(GamePanel.Width / 2 - (int)(moneySize.Width / 2), GamePanel.Height / 3 - (int)(moneySize.Height /2));
//crazy outline
GraphicsPath p = new GraphicsPath();
p.AddString(resultText, BJFont, (int)FontStyle.Bold, g.DpiY * screen.Width / 10 / 72, resPos, new StringFormat());
Pen pen = new Pen(Color.Black, screen.Width / 60);
g.DrawPath(pen, p);
//actual text
SolidBrush brush = new SolidBrush(c);
g.DrawString(resultText,resFont,brush, resPos);
g.DrawString(moneyText,moneyFont,brush, moneyPos);
}
// some draw thingies
private void DrawChip(Graphics g, Color c, int r, Point pos, string value)
{
// Chip
......@@ -226,7 +480,55 @@ namespace PuzzlePlayer_Namespace
private void DrawCard(Graphics g, Point pos, int width, string cardName) //cardName needs to be in format: num_of_kind
{
Image img = SettingForm.GetEmbeddedImage("BlackJack.cards." + cardName + ".png");
g.DrawImage(img, pos.X, pos.Y, width, (float)(width * 1.4)); //img is 500x726
g.DrawImage(img, pos.X, pos.Y, width, (float)(width * cardMultply)); //img is 500x726
}
// methodes for interacting with the cards
private Card PopCard()
{
if (cardsLeft.Count == 0)
cardsLeft = getAllCards(); //reshuffle, In the real game the reshuffle is done after the round has ended but i am lazy :)
Card c = cardsLeft[cardsLeft.Count - 1];
cardsLeft.RemoveAt(cardsLeft.Count - 1);
return c;
}
private int getValue(List<Card> cardList)
{
int result = 0;
int aceCount = 0;
foreach(Card c in cardList)
{
if (c.name.StartsWith("ace"))
aceCount++;
else
result += c.value;
}
if(aceCount > 0)
{
for (int i = 0; i < aceCount; i++) //check for each ace if adding 11 will make them go over 21. if not then we can add 21 else we will add 1
{
if (result + aceValueMax > BLACKJACK)
result += aceValueMin;
else
result += aceValueMax;
}
}
return result;
}
private List<Card> getVisableDealerCards()
{
List<Card> cards = new List<Card>();
foreach ((Card c,bool b) in dealerCards)
if(b)
cards.Add(c);
return cards;
}
}
}
......@@ -53,6 +53,7 @@
<None Remove="Resources\BlackJack\cards\ace_of_diamonds.png" />
<None Remove="Resources\BlackJack\cards\ace_of_hearts.png" />
<None Remove="Resources\BlackJack\cards\ace_of_spades.png" />
<None Remove="Resources\BlackJack\cards\back.png" />
<None Remove="Resources\BlackJack\cards\jack_of_clubs.png" />
<None Remove="Resources\BlackJack\cards\jack_of_diamonds.png" />
<None Remove="Resources\BlackJack\cards\jack_of_hearts.png" />
......@@ -115,6 +116,7 @@
<EmbeddedResource Include="Resources\BlackJack\cards\ace_of_diamonds.png" />
<EmbeddedResource Include="Resources\BlackJack\cards\ace_of_hearts.png" />
<EmbeddedResource Include="Resources\BlackJack\cards\ace_of_spades.png" />
<EmbeddedResource Include="Resources\BlackJack\cards\back.png" />
<EmbeddedResource Include="Resources\BlackJack\cards\jack_of_clubs.png" />
<EmbeddedResource Include="Resources\BlackJack\cards\jack_of_diamonds.png" />
<EmbeddedResource Include="Resources\BlackJack\cards\jack_of_hearts.png" />
......
PuzzlePlayer/Resources/BlackJack/cards/back.png

747 KiB

0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment