Click here to Skip to main content
15,886,026 members
Articles / Programming Languages / C#

Blackjack - a real world OOD example

Rate me:
Please Sign up or sign in to vote.
4.87/5 (47 votes)
18 Jul 20076 min read 236.1K   9.6K   153  
Learn OOD in .NET by examining a Blackjack game
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
using System.Windows.Forms;
using System.Threading;
using System.Configuration;
using System.Globalization;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Formatters.Soap;
using System.Xml;
using ImageControls;

namespace BlackJack
{
	/// <summary>
	/// This is an almost full-functioned Blackjack game with strategy advice
	/// and human/computer controlled players.  The rules are the common Blackjack
	/// rules used in most casinos except the player is limited to two hands (split).
	/// </summary>
	[Serializable()]
	public class Blackjack : System.Windows.Forms.Form
	{
		#region FormControls

		private System.Windows.Forms.NumericUpDown txtNumberOfDecks;
		private System.Windows.Forms.NumericUpDown txtNumberOfPlayers;
		private System.Windows.Forms.StatusBarPanel CardBack;
		private System.Windows.Forms.NumericUpDown txtCardBack;
		private System.Windows.Forms.Timer tmrAutoPlay;
		private System.Windows.Forms.NumericUpDown txtDelay;
		private System.ComponentModel.IContainer components;
		private System.Windows.Forms.StatusBarPanel Hands;
		private System.Windows.Forms.StatusBarPanel Shuffles;
		private System.Windows.Forms.CheckBox chkAuto;
		private System.Windows.Forms.StatusBar pnlStatistics;
		private System.Windows.Forms.CheckBox chkMute;
		private System.Windows.Forms.StatusBarPanel NumberDecks;
		private System.Windows.Forms.StatusBarPanel NumberPlayers;
		private System.Windows.Forms.StatusBarPanel Interval;
		private System.Windows.Forms.StatusBarPanel Mute;
		private System.Windows.Forms.StatusBarPanel AutoDeal;
		private System.Windows.Forms.Timer tmrInsurance;
		private System.Windows.Forms.ContextMenu mnuPopup;
		private System.Windows.Forms.MenuItem mnuStrategyWindow;
		private System.Windows.Forms.MenuItem menuItem1;
		private System.Windows.Forms.MenuItem mnuShowBank;
		private System.Windows.Forms.MenuItem mnuShowCardCount;
		private System.Windows.Forms.MenuItem menuItem4;
		private System.Windows.Forms.MenuItem mnuStrategy;
		private System.Windows.Forms.MenuItem mnuMethod;
		private System.Windows.Forms.MenuItem mnuPlayerType;
		private System.Windows.Forms.MenuItem mnuShowCardTotal;
		private ImageControls.ImageButton btnDeal;
		private ImageControls.ImageButton btnHit;
		private ImageControls.ImageButton btnStay;
		private ImageControls.ImageButton btnSplit;
		private ImageControls.ImageButton btnInsurance;
		private ImageControls.ImageButton btnNoInsurance;
		private ImageControls.ImageButton btnDoubleDown;
		private System.Windows.Forms.ImageList imlButtons;
		#endregion

		#region FormVariables
		// The one and only Shoe object
		private Shoe shoe = new Shoe();
		// An array of player objects
		private Player[] players = new Player[0];
		// The one and only dealer object
		private Dealer dealer;
		// Whether or not the dealer's down card is visible
		private bool showDealerDownCard;
		// Indicates we are in insurance mode
		private bool insurance = false;
		// This one is used by the timer to flash the highlight
		private bool showInsurance = false;
		// This keeps track of how many times we've flashed the insurance highlight
		private int tickCount = 0;
		// currentPlayer keeps track of which player is active
		// currentPlayer > the number of Players (or -1) means the dealer is active
		private int currentPlayer = -1;
		// Determines what kind of label is drawn to the upper left of each player hand
		// Normally display the card total, but after a hand, display the outcome
		private Player.LabelType labelType = Player.LabelType.bothHands;
		// Statistics variables
		private int deals = 0;
		private int shuffles = 0;
		// variables to keep track of which player we are changing 
		private int playerNumber;
		// Boolean indicates end of shoe.  It is set via event from the shoe
		private bool endOfShoe;
		// Scaling variables to make resizing faster and easier
		private float scaleX = 1.0F;
		private float scaleY = 1.0F;
		// This form is used to display the strategy for each player;
		StrategyForm strategyForm = new StrategyForm();
		// This keeps track of whether we've hidden the form while minimized
		private bool strategyFormMinimized;
		// Preload the background image on form_load for speed.  Store it here.
		private Bitmap backgroundImage;
		private System.Windows.Forms.Timer tmrAutoDeal;
		// This tells the paint routine that we're dealing so the advice doesn't get shown
		// until we know if this is an insurance round or not.
		bool dealing = false;
		#endregion

		#region Windows Form Designer generated code
		public Blackjack()
		{
			//
			// Required for Windows Form Designer support
			//
			
			InitializeComponent();

			this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
			this.SetStyle(ControlStyles.UserPaint, true);
			this.SetStyle(ControlStyles.DoubleBuffer, true);

			shoe.EndOfShoeEvent += new Shoe.ShoeEventHandler(EndOfShoe);
			shoe.ShuffleEvent += new Shoe.ShoeEventHandler(ShuffleShoe);
			shoe.BackChangedEvent += new Shoe.ShoeEventHandler(BackChanged);

		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			this.components = new System.ComponentModel.Container();
			System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(Blackjack));
			this.txtNumberOfDecks = new System.Windows.Forms.NumericUpDown();
			this.txtNumberOfPlayers = new System.Windows.Forms.NumericUpDown();
			this.tmrAutoPlay = new System.Windows.Forms.Timer(this.components);
			this.txtDelay = new System.Windows.Forms.NumericUpDown();
			this.pnlStatistics = new System.Windows.Forms.StatusBar();
			this.Hands = new System.Windows.Forms.StatusBarPanel();
			this.Shuffles = new System.Windows.Forms.StatusBarPanel();
			this.NumberDecks = new System.Windows.Forms.StatusBarPanel();
			this.NumberPlayers = new System.Windows.Forms.StatusBarPanel();
			this.Interval = new System.Windows.Forms.StatusBarPanel();
			this.Mute = new System.Windows.Forms.StatusBarPanel();
			this.AutoDeal = new System.Windows.Forms.StatusBarPanel();
			this.CardBack = new System.Windows.Forms.StatusBarPanel();
			this.chkAuto = new System.Windows.Forms.CheckBox();
			this.chkMute = new System.Windows.Forms.CheckBox();
			this.txtCardBack = new System.Windows.Forms.NumericUpDown();
			this.tmrInsurance = new System.Windows.Forms.Timer(this.components);
			this.mnuPopup = new System.Windows.Forms.ContextMenu();
			this.mnuStrategyWindow = new System.Windows.Forms.MenuItem();
			this.menuItem1 = new System.Windows.Forms.MenuItem();
			this.mnuShowBank = new System.Windows.Forms.MenuItem();
			this.mnuShowCardCount = new System.Windows.Forms.MenuItem();
			this.mnuShowCardTotal = new System.Windows.Forms.MenuItem();
			this.menuItem4 = new System.Windows.Forms.MenuItem();
			this.mnuPlayerType = new System.Windows.Forms.MenuItem();
			this.mnuStrategy = new System.Windows.Forms.MenuItem();
			this.mnuMethod = new System.Windows.Forms.MenuItem();
			this.btnDeal = new ImageControls.ImageButton();
			this.imlButtons = new System.Windows.Forms.ImageList(this.components);
			this.btnHit = new ImageControls.ImageButton();
			this.btnStay = new ImageControls.ImageButton();
			this.btnSplit = new ImageControls.ImageButton();
			this.btnDoubleDown = new ImageControls.ImageButton();
			this.btnInsurance = new ImageControls.ImageButton();
			this.btnNoInsurance = new ImageControls.ImageButton();
			this.tmrAutoDeal = new System.Windows.Forms.Timer(this.components);
			((System.ComponentModel.ISupportInitialize)(this.txtNumberOfDecks)).BeginInit();
			((System.ComponentModel.ISupportInitialize)(this.txtNumberOfPlayers)).BeginInit();
			((System.ComponentModel.ISupportInitialize)(this.txtDelay)).BeginInit();
			((System.ComponentModel.ISupportInitialize)(this.Hands)).BeginInit();
			((System.ComponentModel.ISupportInitialize)(this.Shuffles)).BeginInit();
			((System.ComponentModel.ISupportInitialize)(this.NumberDecks)).BeginInit();
			((System.ComponentModel.ISupportInitialize)(this.NumberPlayers)).BeginInit();
			((System.ComponentModel.ISupportInitialize)(this.Interval)).BeginInit();
			((System.ComponentModel.ISupportInitialize)(this.Mute)).BeginInit();
			((System.ComponentModel.ISupportInitialize)(this.AutoDeal)).BeginInit();
			((System.ComponentModel.ISupportInitialize)(this.CardBack)).BeginInit();
			((System.ComponentModel.ISupportInitialize)(this.txtCardBack)).BeginInit();
			this.SuspendLayout();
			// 
			// txtNumberOfDecks
			// 
			this.txtNumberOfDecks.BackColor = System.Drawing.SystemColors.Control;
			this.txtNumberOfDecks.BorderStyle = System.Windows.Forms.BorderStyle.None;
			this.txtNumberOfDecks.CausesValidation = false;
			this.txtNumberOfDecks.Font = new System.Drawing.Font("Microsoft Sans Serif", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.txtNumberOfDecks.ForeColor = System.Drawing.SystemColors.ControlText;
			this.txtNumberOfDecks.Location = new System.Drawing.Point(902, 497);
			this.txtNumberOfDecks.Maximum = new System.Decimal(new int[] {
																			 10,
																			 0,
																			 0,
																			 0});
			this.txtNumberOfDecks.Minimum = new System.Decimal(new int[] {
																			 1,
																			 0,
																			 0,
																			 0});
			this.txtNumberOfDecks.Name = "txtNumberOfDecks";
			this.txtNumberOfDecks.ReadOnly = true;
			this.txtNumberOfDecks.Size = new System.Drawing.Size(40, 13);
			this.txtNumberOfDecks.TabIndex = 2;
			this.txtNumberOfDecks.TabStop = false;
			this.txtNumberOfDecks.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
			this.txtNumberOfDecks.Value = new System.Decimal(new int[] {
																		   6,
																		   0,
																		   0,
																		   0});
			this.txtNumberOfDecks.ValueChanged += new System.EventHandler(this.txtNumberOfDecks_ValueChanged);
			// 
			// txtNumberOfPlayers
			// 
			this.txtNumberOfPlayers.BackColor = System.Drawing.SystemColors.Control;
			this.txtNumberOfPlayers.BorderStyle = System.Windows.Forms.BorderStyle.None;
			this.txtNumberOfPlayers.CausesValidation = false;
			this.txtNumberOfPlayers.Font = new System.Drawing.Font("Microsoft Sans Serif", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.txtNumberOfPlayers.ForeColor = System.Drawing.SystemColors.ControlText;
			this.txtNumberOfPlayers.Location = new System.Drawing.Point(902, 517);
			this.txtNumberOfPlayers.Maximum = new System.Decimal(new int[] {
																			   5,
																			   0,
																			   0,
																			   0});
			this.txtNumberOfPlayers.Minimum = new System.Decimal(new int[] {
																			   1,
																			   0,
																			   0,
																			   0});
			this.txtNumberOfPlayers.Name = "txtNumberOfPlayers";
			this.txtNumberOfPlayers.ReadOnly = true;
			this.txtNumberOfPlayers.Size = new System.Drawing.Size(40, 13);
			this.txtNumberOfPlayers.TabIndex = 6;
			this.txtNumberOfPlayers.TabStop = false;
			this.txtNumberOfPlayers.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
			this.txtNumberOfPlayers.Value = new System.Decimal(new int[] {
																			 5,
																			 0,
																			 0,
																			 0});
			this.txtNumberOfPlayers.ValueChanged += new System.EventHandler(this.txtNumberOfPlayers_ValueChanged);
			// 
			// tmrAutoPlay
			// 
			this.tmrAutoPlay.Enabled = true;
			this.tmrAutoPlay.Tick += new System.EventHandler(this.tmrAutoPlay_Tick);
			// 
			// txtDelay
			// 
			this.txtDelay.BackColor = System.Drawing.SystemColors.Control;
			this.txtDelay.BorderStyle = System.Windows.Forms.BorderStyle.None;
			this.txtDelay.CausesValidation = false;
			this.txtDelay.Font = new System.Drawing.Font("Microsoft Sans Serif", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.txtDelay.ForeColor = System.Drawing.SystemColors.ControlText;
			this.txtDelay.Location = new System.Drawing.Point(902, 538);
			this.txtDelay.Minimum = new System.Decimal(new int[] {
																	 1,
																	 0,
																	 0,
																	 0});
			this.txtDelay.Name = "txtDelay";
			this.txtDelay.ReadOnly = true;
			this.txtDelay.Size = new System.Drawing.Size(40, 13);
			this.txtDelay.TabIndex = 13;
			this.txtDelay.TabStop = false;
			this.txtDelay.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
			this.txtDelay.Value = new System.Decimal(new int[] {
																   1,
																   0,
																   0,
																   0});
			this.txtDelay.ValueChanged += new System.EventHandler(this.txtDelay_ValueChanged);
			// 
			// pnlStatistics
			// 
			this.pnlStatistics.Location = new System.Drawing.Point(0, 561);
			this.pnlStatistics.Name = "pnlStatistics";
			this.pnlStatistics.Panels.AddRange(new System.Windows.Forms.StatusBarPanel[] {
																							 this.Hands,
																							 this.Shuffles,
																							 this.NumberDecks,
																							 this.NumberPlayers,
																							 this.Interval,
																							 this.Mute,
																							 this.AutoDeal,
																							 this.CardBack});
			this.pnlStatistics.ShowPanels = true;
			this.pnlStatistics.Size = new System.Drawing.Size(946, 19);
			this.pnlStatistics.TabIndex = 15;
			// 
			// Hands
			// 
			this.Hands.MinWidth = 100;
			this.Hands.Text = "Hands: 0";
			// 
			// Shuffles
			// 
			this.Shuffles.MinWidth = 100;
			this.Shuffles.Text = "Shuffles: 0";
			// 
			// NumberDecks
			// 
			this.NumberDecks.MinWidth = 120;
			this.NumberDecks.Text = "Decks:";
			this.NumberDecks.Width = 120;
			// 
			// NumberPlayers
			// 
			this.NumberPlayers.MinWidth = 120;
			this.NumberPlayers.Text = "Players:";
			this.NumberPlayers.Width = 120;
			// 
			// Interval
			// 
			this.Interval.MinWidth = 120;
			this.Interval.Text = "Delay:";
			this.Interval.ToolTipText = "Changes the speed of play";
			this.Interval.Width = 120;
			// 
			// Mute
			// 
			this.Mute.MinWidth = 100;
			this.Mute.Text = "Mute";
			this.Mute.ToolTipText = "Turns off shuffle and other sound effects";
			// 
			// AutoDeal
			// 
			this.AutoDeal.MinWidth = 100;
			this.AutoDeal.Text = "Auto Deal";
			this.AutoDeal.ToolTipText = "Automatically deals each hand without user intervention";
			// 
			// CardBack
			// 
			this.CardBack.MinWidth = 120;
			this.CardBack.Text = "Card Back";
			this.CardBack.ToolTipText = "Select different images for the back of the cards";
			this.CardBack.Width = 120;
			// 
			// chkAuto
			// 
			this.chkAuto.BackColor = System.Drawing.SystemColors.Control;
			this.chkAuto.CheckAlign = System.Drawing.ContentAlignment.MiddleRight;
			this.chkAuto.Font = new System.Drawing.Font("Microsoft Sans Serif", 7.8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.chkAuto.ForeColor = System.Drawing.Color.LemonChiffon;
			this.chkAuto.Location = new System.Drawing.Point(927, 473);
			this.chkAuto.Name = "chkAuto";
			this.chkAuto.Size = new System.Drawing.Size(13, 14);
			this.chkAuto.TabIndex = 16;
			this.chkAuto.TabStop = false;
			this.chkAuto.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
			// 
			// chkMute
			// 
			this.chkMute.BackColor = System.Drawing.SystemColors.Control;
			this.chkMute.CheckAlign = System.Drawing.ContentAlignment.MiddleRight;
			this.chkMute.Font = new System.Drawing.Font("Microsoft Sans Serif", 7.8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.chkMute.ForeColor = System.Drawing.Color.LemonChiffon;
			this.chkMute.Location = new System.Drawing.Point(927, 454);
			this.chkMute.Name = "chkMute";
			this.chkMute.Size = new System.Drawing.Size(13, 14);
			this.chkMute.TabIndex = 17;
			this.chkMute.TabStop = false;
			this.chkMute.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
			// 
			// txtCardBack
			// 
			this.txtCardBack.BackColor = System.Drawing.SystemColors.Control;
			this.txtCardBack.BorderStyle = System.Windows.Forms.BorderStyle.None;
			this.txtCardBack.CausesValidation = false;
			this.txtCardBack.Font = new System.Drawing.Font("Microsoft Sans Serif", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.txtCardBack.ForeColor = System.Drawing.SystemColors.ControlText;
			this.txtCardBack.Location = new System.Drawing.Point(720, 541);
			this.txtCardBack.Maximum = new System.Decimal(new int[] {
																		66,
																		0,
																		0,
																		0});
			this.txtCardBack.Minimum = new System.Decimal(new int[] {
																		53,
																		0,
																		0,
																		0});
			this.txtCardBack.Name = "txtCardBack";
			this.txtCardBack.ReadOnly = true;
			this.txtCardBack.Size = new System.Drawing.Size(13, 13);
			this.txtCardBack.TabIndex = 19;
			this.txtCardBack.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
			this.txtCardBack.Value = new System.Decimal(new int[] {
																	  66,
																	  0,
																	  0,
																	  0});
			this.txtCardBack.ValueChanged += new System.EventHandler(this.txtCardBack_ValueChanged);
			// 
			// tmrInsurance
			// 
			this.tmrInsurance.Interval = 300;
			this.tmrInsurance.Tick += new System.EventHandler(this.tmrInsurance_Tick);
			// 
			// mnuPopup
			// 
			this.mnuPopup.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
																					 this.mnuStrategyWindow,
																					 this.menuItem1,
																					 this.mnuShowBank,
																					 this.mnuShowCardCount,
																					 this.mnuShowCardTotal,
																					 this.menuItem4,
																					 this.mnuPlayerType,
																					 this.mnuStrategy,
																					 this.mnuMethod});
			// 
			// mnuStrategyWindow
			// 
			this.mnuStrategyWindow.Index = 0;
			this.mnuStrategyWindow.Text = "Show Strategy Window";
			this.mnuStrategyWindow.Click += new System.EventHandler(this.mnuShowStrategy_Click);
			// 
			// menuItem1
			// 
			this.menuItem1.Index = 1;
			this.menuItem1.Text = "-";
			// 
			// mnuShowBank
			// 
			this.mnuShowBank.Index = 2;
			this.mnuShowBank.Text = "Show Bank";
			this.mnuShowBank.Click += new System.EventHandler(this.mnuShowBank_Click);
			// 
			// mnuShowCardCount
			// 
			this.mnuShowCardCount.Index = 3;
			this.mnuShowCardCount.Text = "Show Card Count";
			this.mnuShowCardCount.Click += new System.EventHandler(this.mnuShowCardCount_Click);
			// 
			// mnuShowCardTotal
			// 
			this.mnuShowCardTotal.Index = 4;
			this.mnuShowCardTotal.Text = "Show Card Total";
			this.mnuShowCardTotal.Click += new System.EventHandler(this.mnuShowCardTotal_Click);
			// 
			// menuItem4
			// 
			this.menuItem4.Index = 5;
			this.menuItem4.Text = "-";
			// 
			// mnuPlayerType
			// 
			this.mnuPlayerType.Index = 6;
			this.mnuPlayerType.Text = "Computer Player";
			this.mnuPlayerType.Click += new System.EventHandler(this.mnuPlayerType_Click);
			// 
			// mnuStrategy
			// 
			this.mnuStrategy.Index = 7;
			this.mnuStrategy.Text = "Strategy";
			// 
			// mnuMethod
			// 
			this.mnuMethod.Index = 8;
			this.mnuMethod.Text = "Method";
			// 
			// btnDeal
			// 
			this.btnDeal.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
			this.btnDeal.AutoSize = true;
			this.btnDeal.BackColor = System.Drawing.Color.White;
			this.btnDeal.ImageIndexDisabled = 3;
			this.btnDeal.ImageIndexHover = 2;
			this.btnDeal.ImageIndexNormal = 0;
			this.btnDeal.ImageIndexPressed = 1;
			this.btnDeal.ImageList = this.imlButtons;
			this.btnDeal.Location = new System.Drawing.Point(198, 527);
			this.btnDeal.Name = "btnDeal";
			this.btnDeal.Pulse = true;
			this.btnDeal.Size = new System.Drawing.Size(106, 30);
			this.btnDeal.StopPulsingAfterClick = true;
			this.btnDeal.TabIndex = 20;
			this.btnDeal.Text = "&Deal";
			this.btnDeal.Click += new System.EventHandler(this.btnDeal_Click);
			// 
			// imlButtons
			// 
			this.imlButtons.ImageSize = new System.Drawing.Size(106, 30);
			this.imlButtons.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imlButtons.ImageStream")));
			this.imlButtons.TransparentColor = System.Drawing.Color.Transparent;
			// 
			// btnHit
			// 
			this.btnHit.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
			this.btnHit.AutoSize = true;
			this.btnHit.BackColor = System.Drawing.Color.White;
			this.btnHit.Enabled = false;
			this.btnHit.ImageIndexDisabled = 7;
			this.btnHit.ImageIndexHover = 6;
			this.btnHit.ImageIndexNormal = 4;
			this.btnHit.ImageIndexPressed = 5;
			this.btnHit.ImageList = this.imlButtons;
			this.btnHit.Location = new System.Drawing.Point(309, 527);
			this.btnHit.Name = "btnHit";
			this.btnHit.Size = new System.Drawing.Size(106, 30);
			this.btnHit.StopPulsingAfterClick = true;
			this.btnHit.TabIndex = 21;
			this.btnHit.Text = "&Hit";
			this.btnHit.Click += new System.EventHandler(this.btnHit_Click);
			// 
			// btnStay
			// 
			this.btnStay.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
			this.btnStay.AutoSize = true;
			this.btnStay.BackColor = System.Drawing.Color.White;
			this.btnStay.Enabled = false;
			this.btnStay.ImageIndexDisabled = 11;
			this.btnStay.ImageIndexHover = 10;
			this.btnStay.ImageIndexNormal = 8;
			this.btnStay.ImageIndexPressed = 9;
			this.btnStay.ImageList = this.imlButtons;
			this.btnStay.Location = new System.Drawing.Point(420, 527);
			this.btnStay.Name = "btnStay";
			this.btnStay.Size = new System.Drawing.Size(106, 30);
			this.btnStay.StopPulsingAfterClick = true;
			this.btnStay.TabIndex = 22;
			this.btnStay.Text = "&Stand";
			this.btnStay.Click += new System.EventHandler(this.btnStay_Click);
			// 
			// btnSplit
			// 
			this.btnSplit.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
			this.btnSplit.AutoSize = true;
			this.btnSplit.BackColor = System.Drawing.Color.White;
			this.btnSplit.Enabled = false;
			this.btnSplit.ImageIndexDisabled = 15;
			this.btnSplit.ImageIndexHover = 14;
			this.btnSplit.ImageIndexNormal = 12;
			this.btnSplit.ImageIndexPressed = 13;
			this.btnSplit.ImageList = this.imlButtons;
			this.btnSplit.Location = new System.Drawing.Point(531, 527);
			this.btnSplit.Name = "btnSplit";
			this.btnSplit.Size = new System.Drawing.Size(106, 30);
			this.btnSplit.StopPulsingAfterClick = true;
			this.btnSplit.TabIndex = 23;
			this.btnSplit.Text = "S&plit";
			this.btnSplit.Click += new System.EventHandler(this.btnSplit_Click);
			// 
			// btnDoubleDown
			// 
			this.btnDoubleDown.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
			this.btnDoubleDown.AutoSize = true;
			this.btnDoubleDown.BackColor = System.Drawing.Color.White;
			this.btnDoubleDown.Enabled = false;
			this.btnDoubleDown.ImageIndexDisabled = 19;
			this.btnDoubleDown.ImageIndexHover = 18;
			this.btnDoubleDown.ImageIndexNormal = 16;
			this.btnDoubleDown.ImageIndexPressed = 17;
			this.btnDoubleDown.ImageList = this.imlButtons;
			this.btnDoubleDown.Location = new System.Drawing.Point(642, 527);
			this.btnDoubleDown.Name = "btnDoubleDown";
			this.btnDoubleDown.Size = new System.Drawing.Size(106, 30);
			this.btnDoubleDown.StopPulsingAfterClick = true;
			this.btnDoubleDown.TabIndex = 24;
			this.btnDoubleDown.Text = "Dou&ble Down";
			this.btnDoubleDown.Click += new System.EventHandler(this.btnDoubleDown_Click);
			// 
			// btnInsurance
			// 
			this.btnInsurance.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
			this.btnInsurance.AutoSize = true;
			this.btnInsurance.BackColor = System.Drawing.Color.White;
			this.btnInsurance.ImageIndexDisabled = 23;
			this.btnInsurance.ImageIndexHover = 22;
			this.btnInsurance.ImageIndexNormal = 20;
			this.btnInsurance.ImageIndexPressed = 21;
			this.btnInsurance.ImageList = this.imlButtons;
			this.btnInsurance.Location = new System.Drawing.Point(363, 527);
			this.btnInsurance.Name = "btnInsurance";
			this.btnInsurance.Size = new System.Drawing.Size(106, 30);
			this.btnInsurance.StopPulsingAfterClick = true;
			this.btnInsurance.TabIndex = 25;
			this.btnInsurance.Text = "&Insurance";
			this.btnInsurance.Visible = false;
			this.btnInsurance.Click += new System.EventHandler(this.btnInsurance_Click);
			// 
			// btnNoInsurance
			// 
			this.btnNoInsurance.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
			this.btnNoInsurance.AutoSize = true;
			this.btnNoInsurance.BackColor = System.Drawing.Color.White;
			this.btnNoInsurance.ImageIndexDisabled = 27;
			this.btnNoInsurance.ImageIndexHover = 26;
			this.btnNoInsurance.ImageIndexNormal = 24;
			this.btnNoInsurance.ImageIndexPressed = 25;
			this.btnNoInsurance.ImageList = this.imlButtons;
			this.btnNoInsurance.Location = new System.Drawing.Point(478, 527);
			this.btnNoInsurance.Name = "btnNoInsurance";
			this.btnNoInsurance.Size = new System.Drawing.Size(106, 30);
			this.btnNoInsurance.StopPulsingAfterClick = true;
			this.btnNoInsurance.TabIndex = 26;
			this.btnNoInsurance.Text = "&NoInsurance";
			this.btnNoInsurance.Visible = false;
			this.btnNoInsurance.Click += new System.EventHandler(this.btnNoInsurance_Click);
			// 
			// tmrAutoDeal
			// 
			this.tmrAutoDeal.Interval = 1000;
			this.tmrAutoDeal.Tick += new System.EventHandler(this.tmrAutoDeal_Tick);
			// 
			// Blackjack
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.ClientSize = new System.Drawing.Size(946, 580);
			this.Controls.Add(this.btnNoInsurance);
			this.Controls.Add(this.btnInsurance);
			this.Controls.Add(this.btnDoubleDown);
			this.Controls.Add(this.btnHit);
			this.Controls.Add(this.btnDeal);
			this.Controls.Add(this.txtCardBack);
			this.Controls.Add(this.chkMute);
			this.Controls.Add(this.chkAuto);
			this.Controls.Add(this.pnlStatistics);
			this.Controls.Add(this.txtDelay);
			this.Controls.Add(this.txtNumberOfPlayers);
			this.Controls.Add(this.txtNumberOfDecks);
			this.Controls.Add(this.btnStay);
			this.Controls.Add(this.btnSplit);
			this.KeyPreview = true;
			this.Name = "Blackjack";
			this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
			this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
			this.Text = "Blackjack";
			this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Blackjack_KeyDown);
			this.Resize += new System.EventHandler(this.Blackjack_Resize);
			this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Blackjack_MouseDown);
			this.Load += new System.EventHandler(this.Blackjack_Load);
			this.Paint += new System.Windows.Forms.PaintEventHandler(this.Blackjack_Paint);
			((System.ComponentModel.ISupportInitialize)(this.txtNumberOfDecks)).EndInit();
			((System.ComponentModel.ISupportInitialize)(this.txtNumberOfPlayers)).EndInit();
			((System.ComponentModel.ISupportInitialize)(this.txtDelay)).EndInit();
			((System.ComponentModel.ISupportInitialize)(this.Hands)).EndInit();
			((System.ComponentModel.ISupportInitialize)(this.Shuffles)).EndInit();
			((System.ComponentModel.ISupportInitialize)(this.NumberDecks)).EndInit();
			((System.ComponentModel.ISupportInitialize)(this.NumberPlayers)).EndInit();
			((System.ComponentModel.ISupportInitialize)(this.Interval)).EndInit();
			((System.ComponentModel.ISupportInitialize)(this.Mute)).EndInit();
			((System.ComponentModel.ISupportInitialize)(this.AutoDeal)).EndInit();
			((System.ComponentModel.ISupportInitialize)(this.CardBack)).EndInit();
			((System.ComponentModel.ISupportInitialize)(this.txtCardBack)).EndInit();
			this.ResumeLayout(false);

		}

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main() 
		{
			Splash splashScreen = new Splash();
			splashScreen.Show();
			Application.Run(new Blackjack());
		}
		#endregion

		private void btnDeal_Click(object sender, System.EventArgs e)
		{
			// Keep track of statistics
			deals++;

			// Reset the form for play
			txtNumberOfPlayers.Enabled = false;
			txtNumberOfDecks.Enabled = false;

			// Reset the players
			foreach( Player player in players )
			{
				// Reset all players regardless of whether they are active
				player.Reset();
			}
			
			// Reset insurance
			insurance = false;

			// Set the buttons in the correct state
			SetButtonState( false );

			// Reset the dealer
			showDealerDownCard = false;
			dealer.Reset();

			// Reset the player pointer
			currentPlayer = 0;

			// Shuffle if we need to
			if( shoe.Eod )
			{
				endOfShoe = false;

				// This clears the screen so it looks like the dealer picked up all the cards
				this.Refresh();

				// Then shuffle the deck
				Shuffle( true );
			}

			// Get the recommended wager from the counting system
			foreach( Player player in players )
			{
				if( player.Active) player.GetWager();
			}

			// Set the label type to draw all labels
			labelType = Player.LabelType.bothHands;

			// Update statistics
			pnlStatistics.Panels[0].Text = "Hands: " + deals.ToString(CultureInfo.InvariantCulture);
			pnlStatistics.Panels[1].Text = "Shuffles: " + shuffles.ToString(CultureInfo.InvariantCulture);

			Card newCard = null;
			Card dealerCard = null;

			dealing = true;

			// Deal the cards
			for( int k=0; k<2; k++ )
			{
				foreach( Player player in players )
				{
					if( player.Active )
					{
						// Get a card
						newCard = shoe.Next();
						// Put it in the player's hand
						player.GetHands()[0].Add( newCard );
						// And give all players the opportunity to count it
						CountCard( newCard );
						// Then update the screen so the new card shows up
						this.Refresh();
					}
				}
				// Now give the dealer a card
				dealerCard = shoe.Next();
				dealer.Hand.Add( dealerCard );
				// And if it is the up card, give the players the opportunity to count it
				if( k == 1 )
					CountCard( newCard );

				// refresh the screen so we see each card as it is dealt.
				this.Refresh();
			}

			dealing = false;

			// If dealer has an ace showing, 
			// check to see if anybody wants insurance.
			if( dealer.Hand[1].FaceValue == Card.CardType.Ace )
			{
				// Highlight the board to indicate insurance is available
				insurance = true;
				SetButtonState( false );
				tmrInsurance.Enabled = true;
				this.Refresh();
			}
			else if( dealer.Hand.IsBlackjack() )
			{
				// Dealer blackjack
				labelType = Player.LabelType.outcome;
				currentPlayer = players.GetUpperBound(0) + 1;

				// Show down card
				showDealerDownCard = true;
				// Let everyone count it
				this.Refresh();

				// Let the players count it 
				CountCard( dealer.Hand[0] );

				// Take the money from everybody unless they have Blackjack
				foreach( Player player in players )
				{
					if( player.Active )
					{
						foreach( Hand hand in player.GetHands() )
						{
							if( hand.IsBlackjack() )
								// If the player also had Blackjack, Push
								player.Push( hand );
						}
						player.Bet.Visible = true;
					}
				}
				this.Refresh();

				// Reset the form for entry
				txtNumberOfPlayers.Enabled = true;
				txtNumberOfDecks.Enabled = true;
				SetButtonState( true );

				if( chkAuto.Checked )
					tmrAutoDeal.Enabled = true;
			}
			else
			{
				this.Refresh();

				// Loop through the players until we find one that doesn't have 21
				int handTotal = 0;
				do
				{
					handTotal = CurrentPlayer.CurrentHand.Total();
					if( handTotal == 21 )
						NextPlayer();
				} while ( handTotal == 21 && CurrentPlayer != null );
			
				// Tell the strategy form which player to show strategy for
				if( strategyForm.Visible )
				{
					strategyForm.CurrentPlayer = CurrentPlayer;
					if( dealer.Hand.Count > 0 )
						strategyForm.DealerCard = dealer.Hand[1];
					strategyForm.Refresh();
				}

				SetButtonState( false );
			}
								
			// The next deal will begin with a shuffle, tell the players
			// to reset their card count now so the suggested bet for human
			// players is accurate.
			if( shoe.Eod )
			{
				foreach( Player player in players )
				{
					if( player.Active ) player.ResetCount( (int)txtNumberOfDecks.Value );
				}
			}

		}

		private void btnSplit_Click(object sender, System.EventArgs e)
		{
			// Make sure we're working with a player and not the dealer
			// and that it's not an insurance round
			if( CurrentPlayer != null && !insurance)
			{
				// See if the player is able to split
				if( CurrentPlayer.Split() )
				{
					// Refresh so that the split hands show up
					this.Refresh();

					// Splitting aces is a special case...
					if( CurrentPlayer.CurrentHand[0].FaceValue == Card.CardType.Ace )
					{
						// Player only gets one more card for each hand
						NextCard();
						NextHand();

						// Then move on to the next player
						NextPlayer();
					}
					else
					{
						// Normal split, deal another card to the current hand
						labelType = Player.LabelType.drawToHand;
						NextCard();

						// If they hit 21, move to the next hand automatically
						if( CurrentPlayer.CurrentHand.Total() == 21 )
						{
							NextHand();

							// And if that hand has 21, move to the next player
							if( CurrentPlayer.CurrentHand.Total() == 21 )
								NextPlayer();
						}
					}
				}
			}
		}

		private void btnHit_Click(object sender, System.EventArgs e)
		{
			// Make sure we're working with a player and not the dealer
			// and that it's not an insurance round
			if( CurrentPlayer != null && !insurance )
			{
				int handTotal = 0;

				// Give them another card
				NextCard();
				
				do
				{
					// Now loop until we find a player that hasn't busted or dealt 21
					handTotal = CurrentPlayer.CurrentHand.Total();
					if( handTotal >= 21 )
					{						
						if( CurrentPlayer.LastHand() )
						{
							// Move to the next player
							NextPlayer();

							// and get their total so the loop can continue if need be
							if( CurrentPlayer != null )
								handTotal = CurrentPlayer.CurrentHand.Total();
						}
						else
						{
							// The player has split, move to the next hand
							NextHand();

							// Get the hand total so the loop can continue if need be
							handTotal = CurrentPlayer.CurrentHand.Total();
						}
					}
				} while ( handTotal >= 21 && CurrentPlayer != null );
			}
		}

		private void btnStay_Click(object sender, System.EventArgs e)
		{
			int handTotal = 0;

			// Make sure we're working with a player and not the dealer
			// and that it's not an insurance round
			if( CurrentPlayer != null && !insurance )
			{
				if( CurrentPlayer.LastHand() )
					NextPlayer();
				else
					// If the player has split, move to the next hand...
					NextHand();

				// Make sure we didn't skip past the last player above
				if( CurrentPlayer != null )
				{
					do
					{
						// Now loop until we find a player that hasn't busted or dealt 21
						handTotal = CurrentPlayer.CurrentHand.Total();
						if( handTotal >= 21 )
						{						
							if( CurrentPlayer.LastHand() )
							{
								// Move to the next player
								NextPlayer();

								// and get their total so the loop can continue if need be
								if( CurrentPlayer != null )
									handTotal = CurrentPlayer.CurrentHand.Total();
							}
							else
							{
								// The player has split, move to the next hand
								NextHand();

								// Get the hand total so the loop can continue if need be
								handTotal = CurrentPlayer.CurrentHand.Total();
							}
						}
					} while ( handTotal >= 21 && CurrentPlayer != null );
				}
			}
		}

		private void btnDoubleDown_Click(object sender, System.EventArgs e)
		{
			// Make sure we're working with a player and not the dealer
			// and that it's not an insurance round
			if( CurrentPlayer != null && !insurance )
			{
				if( CurrentPlayer.DoubleDown( CurrentPlayer.CurrentHand ))
				{
					// Deal one more card
					NextCard();
	
					if( CurrentPlayer.LastHand() )
						// Move to the next player...
						NextPlayer();
					else
						// or next hand if the player split
						NextHand();
				}
			}
		}

		private void btnInsurance_Click(object sender, System.EventArgs e)
		{
			// Make sure we're working with a player and not the dealer
			// and that it's an insurance round
			if( CurrentPlayer != null && insurance )
			{
				CurrentPlayer.Insurance = true;
				NextPlayer();
			}
		}

		private void btnNoInsurance_Click(object sender, System.EventArgs e)
		{
			// Make sure we're working with a player and not the dealer
			// and that it's an insurance round
			if( CurrentPlayer != null && insurance )
			{
				CurrentPlayer.Insurance = false;
				NextPlayer();
			}
		
		}

		private void NextCard()
		{
			// Get the next card
			Card newCard = shoe.Next();

			// Tell each of the players what the card is 
			CountCard( newCard );

			// Add a card to the player's hand
			CurrentPlayer.CurrentHand.Add(newCard);

			// and show it.
			this.Refresh();

			// And if the strategy form is visible, refresh it too
			if( strategyForm.Visible )
				strategyForm.Refresh();

			// The strategy may change with each card so highlight the correct button
			SetButtonState( false );
		}

		private void NextHand()
		{
			// Advance to the player's next hand (for splits only)
			CurrentPlayer.NextHand();

			// They always get another card on a new, split hand
			NextCard();

			// And refresh the strategy form to show the situation with the new hand
			if( strategyForm.Visible )
				strategyForm.Refresh();

			// The strategy may change with each card so highlight the correct button
			SetButtonState( false );
		}

		private void NextPlayer()
		{
			// Make sure both of the current players hands are visible and have labels
			labelType = Player.LabelType.bothHands;

			do
			{
				currentPlayer++;
				this.Refresh();

				// Dealer's turn
				if( CurrentPlayer == null )
				{					
					if( insurance && !dealer.Hand.IsBlackjack())
					{
						foreach( Player player in players )
						{
							if( player.Insurance )
							{
								player.LostInsurance();
								player.Insurance = false;
							}
						}
						// We're no longer in insurance mode
						insurance = false;
						currentPlayer = 0;
						SetButtonState( false );

						this.Refresh();
						if( strategyForm.Visible )
						{
							strategyForm.CurrentPlayer = CurrentPlayer;
							if( dealer.Hand.Count > 0 )
								strategyForm.DealerCard = dealer.Hand[1];
							strategyForm.Refresh();
						}
					}
					else
					{
						// Tell the dealer to show his down card
						showDealerDownCard = true;

						// Update the screen so we can see it
						this.Refresh();

						// Let the players count it if they want to
						CountCard( dealer.Hand[0] );

						// Only hit to the dealer if someone didn't bust
						bool hitToDealer = false;

						foreach( Player player in players )
						{
							if( player.Active )
							{
								foreach( Hand hand in player.GetHands() )
								{
									if( hand.Total() > 0 && hand.Total() <= 21 && !hand.IsBlackjack() )
									{
										hitToDealer = true;
										break;
									}
								}
							}
							if( hitToDealer )
								break;
						}

						if( hitToDealer )
						{
							while( dealer.Total() < 17)
							{
								Card dealerCard = shoe.Next();
								dealer.AddCard( dealerCard );
								this.Refresh();

								// Give each player the opportunity to count the card
								CountCard( dealerCard );
							}
						}

						labelType = Player.LabelType.outcome;

						foreach( Player player in players )
						{
							if( player.Active )
							{
								if( insurance && dealer.Hand.IsBlackjack() )
									player.WonInsurance();
								else
									player.LostInsurance();

								foreach( Hand hand in player.GetHands() )
								{
									switch( hand.Outcome( dealer.Hand, player.NumberOfHands ))
									{
										case Hand.OutcomeType.Won:
											player.Won( hand );
											break;
										case Hand.OutcomeType.Lost:
											// Do nothing, the money was taken at the beginning of play
											break;
										case Hand.OutcomeType.Push:
											player.Push( hand );
											break;
										case Hand.OutcomeType.Blackjack:
											player.Blackjack( hand );
											break;
										default:
											// Hand not in play
											break;
									}
								}
								player.Bet.Visible = true;
							}
						}

						// Reset the form for entry
						insurance = false;
						txtNumberOfPlayers.Enabled = true;
						txtNumberOfDecks.Enabled = true;
						SetButtonState( true );

						if( chkAuto.Checked )
							tmrAutoDeal.Enabled = true;

						// The next deal will begin with a shuffle, tell the players
						// to reset their card count now so the suggested bet for human
						// players is accurate.
						if( shoe.Eod )
						{
							foreach( Player player in players )
							{
								if( player.Active ) player.ResetCount( (int)txtNumberOfDecks.Value );
							}
						}

						this.Refresh();
					}
				}
				else 
				{
					if( strategyForm.Visible )
					{
						strategyForm.CurrentPlayer = CurrentPlayer;
						if( dealer.Hand.Count > 0 )
							strategyForm.DealerCard = dealer.Hand[1];
						strategyForm.Refresh();
					}

					SetButtonState( false );
				}
				
			} while ( CurrentPlayer != null && CurrentPlayer.CurrentHand.Total() >= 21 && !insurance );

		}

		private void tmrAutoPlay_Tick(object sender, System.EventArgs e)
		{
			// This timer is always running, checking to see if a computer player
			// is at play and clicking the approprate buttons.
			Strategy.AdviceType advice = Strategy.AdviceType.None;

			if( CurrentPlayer != null && CurrentPlayer.Type == Player.playerType.computer )
			{
				SetButtonState( false );

				if( insurance )
				{
					// See if the computer player wants insurance
					if( CurrentPlayer.GetInsuranceAdvice( int.Parse(txtNumberOfDecks.Text) ) )
						btnInsurance_Click( sender, e );
					else
						btnNoInsurance_Click( sender, e );
				}
				else
				{
					advice = CurrentPlayer.GetAdvice( dealer.Hand[1] );
					switch( advice )
					{
						case Strategy.AdviceType.Hit:
							btnHit_Click( sender, e );
							break;
						case Strategy.AdviceType.DoubleDown:
							btnDoubleDown_Click( sender, e);
							break;
						case Strategy.AdviceType.Split:
							btnSplit_Click( sender, e );
							break;
						case Strategy.AdviceType.Stand:
							btnStay_Click( sender, e );
							break;
						default:
							break;
					}
				}
			}
		}

		private void SetButtonPulse()
		{
			// To help show the player what the 'correct' move is, we pulsate the 
			// appropriate button.
			if( CurrentPlayer != null && CurrentPlayer.Type == Player.playerType.human )
			{
				if( insurance )
				{
					if( CurrentPlayer.CardStrategy != null )
					{
						btnInsurance.Pulse = CurrentPlayer.GetInsuranceAdvice( (int)txtNumberOfDecks.Value );
						btnNoInsurance.Pulse = !btnInsurance.Pulse;
					}
					else
					{
						// We can't give advice if they don't have a strategy
						btnInsurance.Pulse = false;
						btnNoInsurance.Pulse = false;
					}
				}
				else
				{

					switch( CurrentPlayer.GetAdvice(dealer.Hand[1]) )
					{
						case Strategy.AdviceType.Hit:
							btnHit.Pulse = true;
							break;
						case Strategy.AdviceType.Stand:
							btnStay.Pulse = true;
							break;
						case Strategy.AdviceType.DoubleDown:
							btnDoubleDown.Pulse = true;
							break;
						case Strategy.AdviceType.Split:
							btnSplit.Pulse = true;
							break;
					}
				}
			}
		}

		private void SetButtonState( bool dealEnabled )
		{
			// During an insurance round, only the insurance buttons are visible
			if( insurance )
			{
				btnHit.Visible = false;
				btnStay.Visible = false;
				btnDoubleDown.Visible = false;
				btnSplit.Visible = false;
				btnDeal.Visible = false;
				btnInsurance.Visible = true;
				btnNoInsurance.Visible = true;
			}
			else
			{
				// The opposite is true for normal play
				btnInsurance.Visible = false;
				btnNoInsurance.Visible = false;
				btnHit.Visible = true;
				btnStay.Visible = true;
				btnDoubleDown.Visible = true;
				btnSplit.Visible = true;
				btnDeal.Visible = true;
			}

			// This logic seems weird, but it says that we can only set the Deal button
			// to true if AutoDeal is not checked, but we can always set it to false.
			// This prevents the user from hitting the Deal button during AutoDeal.
			if( !chkAuto.Checked && dealEnabled ) 
				btnDeal.Enabled = dealEnabled;
			else if( !dealEnabled )
				btnDeal.Enabled = dealEnabled;

			// Now enable and disable the buttons depending on whether a human or 
			// computer player is at play.
			if( CurrentPlayer != null )
			{
				if( CurrentPlayer.Type == Player.playerType.computer )
				{
					btnHit.Enabled = false;
					btnStay.Enabled = false;
					btnDoubleDown.Enabled = false;
					btnSplit.Enabled = false;
					btnInsurance.Enabled = false;
					btnNoInsurance.Enabled = false;
				}
				else
				{
					if( insurance )
					{
						btnInsurance.Enabled = true;
						btnNoInsurance.Enabled = true;
					}
					else
					{
						btnHit.Enabled = true;
						btnStay.Enabled = true;
						btnDoubleDown.Enabled = CurrentPlayer.CanDouble( CurrentPlayer.CurrentHand );
						btnSplit.Enabled = CurrentPlayer.CanSplit();
					}
				}
			}

			// Now make the 'correct' button pulsate.
			SetButtonPulse();
		
		}

		private void txtNumberOfDecks_ValueChanged(object sender, System.EventArgs e)
		{
			// Initialize the shoe
			shoe.NumberOfDecks = (int)txtNumberOfDecks.Value;
			shoe.Init();
			Shuffle( false );
		}

		private void txtNumberOfPlayers_ValueChanged(object sender, System.EventArgs e)
		{
			for (int i = 0; i < 5; i++)
			{
				if( i < txtNumberOfPlayers.Value )
					players[i].Active = true;
				else
					players[i].Active = false;
			}

			// This line just forces the resize event to execute, moving the controls into
			// the appropriate positions.
			Blackjack_Resize(sender, e);
			this.Refresh();
		}

		private void InitializePlayers(int numPlayers)
		{
			players = new Player[numPlayers];
			for( int i = 0; i < numPlayers; i++ )
			{
				NumericUpDown plyrBet = null;
				switch(i)
				{
					case 0:  // PLAYER 1
						plyrBet = CreateBetControl(1, new Point(955,299));
						if( ConfigurationSettings.AppSettings["player1"] != null ) 
						{
							try
							{
								string[] playerConfig = ConfigurationSettings.AppSettings["player1"].ToString().Split(new char[]{'|'});
								players[i] = CreatePlayer( new Point(961, 299), "player1_back", double.Parse(playerConfig[1]), plyrBet, playerConfig[0], playerConfig[2], playerConfig[3], (int)txtNumberOfDecks.Value );
							}
							catch 
							{
								players[i] = new Player( new Point(961,299), "player1_back", 5000.00, plyrBet, Player.playerType.human, new BasicMultiDeck(), new HiLo( (int)txtNumberOfDecks.Value ) );
								// Note that there must be a player 1
								players[i].Active = true;
							}
						}
						else
						{
							players[i] = new Player( new Point(961,299), "player1_back", 5000.00, plyrBet, Player.playerType.human, new BasicMultiDeck(), new HiLo( (int)txtNumberOfDecks.Value ) );
							// Note that there must be a player 1
							players[i].Active = true;
						}
						break;
					case 1:  // PLAYER 2
						plyrBet = CreateBetControl(2, new Point(769,428));

						if( ConfigurationSettings.AppSettings["player2"] != null ) 
						{
							try
							{
								string[] playerConfig = ConfigurationSettings.AppSettings["player2"].ToString().Split(new char[]{'|'});
								players[i] = CreatePlayer( new Point(769,428), "player2_back", double.Parse(playerConfig[1]), plyrBet, playerConfig[0], playerConfig[2], playerConfig[3], (int)txtNumberOfDecks.Value );
							}
							catch 
							{
								players[i] = new Player( new Point(769,428), "player2_back", 5000.00, plyrBet, Player.playerType.computer, new BasicMultiDeck(), new HiLo( (int)txtNumberOfDecks.Value ) );
								players[i].Active = false;
							}
						}
						else
						{
							players[i] = new Player( new Point(769,428), "player2_back", 5000.00, plyrBet, Player.playerType.computer, new BasicMultiDeck(), new HiLo( (int)txtNumberOfDecks.Value ) );
							players[i].Active = false;
						}
						break;
					case 2:  // PLAYER 3
						plyrBet = CreateBetControl(3, new Point(500,476));
						
						if( ConfigurationSettings.AppSettings["player3"] != null ) 
						{
							try
							{
								string[] playerConfig = ConfigurationSettings.AppSettings["player3"].ToString().Split(new char[]{'|'});
								players[i] = CreatePlayer( new Point(500,476), "player3_back", double.Parse(playerConfig[1]), plyrBet, playerConfig[0], playerConfig[2], playerConfig[3], (int)txtNumberOfDecks.Value );
							}
							catch 
							{
								players[i] = new Player( new Point(500,476), "player3_back", 5000.00, plyrBet, Player.playerType.computer, new BasicMultiDeck(), new HiLo( (int)txtNumberOfDecks.Value ) );
								players[i].Active = false;
							}
						}
						else
						{
							players[i] = new Player( new Point(500,476), "player3_back", 5000.00, plyrBet, Player.playerType.computer, new BasicMultiDeck(), new HiLo( (int)txtNumberOfDecks.Value ) );
							players[i].Active = false;
						}
						break;
					case 3:  // PLAYER 4
						plyrBet = CreateBetControl(4, new Point(243,430));
						
						if( ConfigurationSettings.AppSettings["player4"] != null ) 
						{
							try
							{
								string[] playerConfig = ConfigurationSettings.AppSettings["player4"].ToString().Split(new char[]{'|'});
								players[i] = CreatePlayer( new Point(243,430), "player4_back", double.Parse(playerConfig[1]), plyrBet, playerConfig[0], playerConfig[2], playerConfig[3], (int)txtNumberOfDecks.Value );
							}
							catch 
							{
								players[i] = new Player( new Point(243,430), "player4_back", 5000.00, plyrBet, Player.playerType.computer, new BasicMultiDeck(), new HiLo( (int)txtNumberOfDecks.Value ) );
								players[i].Active = false;
							}
						}
						else
						{
							players[i] = new Player( new Point(243,430), "player4_back", 5000.00, plyrBet, Player.playerType.computer, new BasicMultiDeck(), new HiLo( (int)txtNumberOfDecks.Value ) );
							players[i].Active = false;
						}
						break;
					case 4:  // PLAYER 5
						plyrBet = CreateBetControl(5, new Point(76,319));
						
						if( ConfigurationSettings.AppSettings["player5"] != null ) 
						{
							try
							{
								string[] playerConfig = ConfigurationSettings.AppSettings["player5"].ToString().Split(new char[]{'|'});
								players[i] = CreatePlayer( new Point(76,319), "player5_back", double.Parse(playerConfig[1]), plyrBet, playerConfig[0], playerConfig[2], playerConfig[3], (int)txtNumberOfDecks.Value );
							}
							catch 
							{
								players[i] = new Player( new Point(76,319), "player5_back", 5000.00, plyrBet, Player.playerType.computer, new BasicMultiDeck(), new HiLo( (int)txtNumberOfDecks.Value ) );
								players[i].Active = false;
							}
						}
						else
						{
							players[i] = new Player( new Point(76,319), "player5_back", 5000.00, plyrBet, Player.playerType.computer, new BasicMultiDeck(), new HiLo( (int)txtNumberOfDecks.Value ) );
							players[i].Active = false;
						}
						break;
				}
			}

			// This line just forces the resize event to execute, moving the controls into
			// the appropriate positions.
			Blackjack_Resize(null, System.EventArgs.Empty);
			this.Refresh();
		}

		private Player CreatePlayer( Point point, string background, double bank, NumericUpDown betControl, string type, string strategy, string method, int numDecks)
		{
			Player player = new Player( point, 
										background, 
										bank, 
										betControl, 
										type.ToLower() == "human" ? Player.playerType.human : Player.playerType.computer, 
										Strategy.NewStrategy( strategy ), 
										CountMethod.NewMethod( method, numDecks ) );
			player.Active = true;
			return player;
		}

		private void txtDelay_ValueChanged(object sender, System.EventArgs e)
		{
			tmrAutoPlay.Interval = (int)txtDelay.Value * 100;
			tmrAutoDeal.Interval = (int)txtDelay.Value * 1000;
		}

		private void CountCard( Card newCard )
		{
			// Tell each of the players what the new card is
			// so they can count it if they want to.
			foreach( Player player in players )
			{
				if( player.Active ) player.CountCard( newCard );
			}
		}

		private void Shuffle( bool playSound )
		{
			// Play a shuffle sound
			if( playSound && !chkMute.Checked )
				Sound.PlayAudioSync("shuffle.wav");

			shoe.Shuffle();
			shuffles++;

			// We need to tell each of the players we are shuffling in 
			// case they are counting cards.
			foreach( Player player in players )
			{
				if( player.Active ) player.ResetCount( (int)txtNumberOfDecks.Value );
			}

		}

		private void BackChanged(object sender, EventArgs e)
		{
			this.Refresh();
		}

		private void EndOfShoe(object sender, EventArgs e)
		{
			endOfShoe = true;
		}

		private void ShuffleShoe(object sender, EventArgs e)
		{
			endOfShoe = false;
		}

		private void Blackjack_Load(object sender, System.EventArgs e)
		{
			// Preload the background image for speed
			backgroundImage = new Bitmap(Resources.GetImage("table"));

			// Load the strategies and methods into the list boxes
			ArrayList strategies = Strategy.GetStrategies();
			ArrayList methods = CountMethod.GetMethods();

			System.Collections.IEnumerator myEnumerator = strategies.GetEnumerator();
			mnuStrategy.MenuItems.Add("None", new EventHandler(mnuStrategy_Click));
			while ( myEnumerator.MoveNext() )
			{
				mnuStrategy.MenuItems.Add( myEnumerator.Current.ToString(), new EventHandler(mnuStrategy_Click));
			}

			mnuMethod.MenuItems.Add( "None", new EventHandler(mnuMethod_Click));
			myEnumerator = methods.GetEnumerator();
			while ( myEnumerator.MoveNext() )
			{
				mnuMethod.MenuItems.Add( myEnumerator.Current.ToString(), new EventHandler(mnuMethod_Click));
			}

			// Move the controls onto the panel.  This must be done at run time.
			#region PanelStatistics
			pnlStatistics.Controls.Add( txtNumberOfDecks );
			txtNumberOfDecks.Left = pnlStatistics.Panels[0].Width + pnlStatistics.Panels[1].Width + pnlStatistics.Panels[2].Width - txtNumberOfDecks.Width - 10  ;
			txtNumberOfDecks.Top = (pnlStatistics.Height - txtNumberOfDecks.Height)/2;
			pnlStatistics.Controls.Add( txtNumberOfPlayers );
			txtNumberOfPlayers.Left = pnlStatistics.Panels[0].Width + pnlStatistics.Panels[1].Width + pnlStatistics.Panels[2].Width + pnlStatistics.Panels[3].Width - txtNumberOfPlayers.Width - 10  ;
			txtNumberOfPlayers.Top = txtNumberOfDecks.Top;
			pnlStatistics.Controls.Add( txtDelay );
			txtDelay.Left = pnlStatistics.Panels[0].Width + pnlStatistics.Panels[1].Width + pnlStatistics.Panels[2].Width + pnlStatistics.Panels[3].Width + pnlStatistics.Panels[4].Width - txtDelay.Width - 10  ;
			txtDelay.Top = txtNumberOfDecks.Top;
			pnlStatistics.Controls.Add( chkMute );
			chkMute.Left = pnlStatistics.Panels[0].Width + pnlStatistics.Panels[1].Width + pnlStatistics.Panels[2].Width + pnlStatistics.Panels[3].Width + pnlStatistics.Panels[4].Width + pnlStatistics.Panels[5].Width - chkMute.Width - 10  ;
			chkMute.Top = (pnlStatistics.Height - chkMute.Height)/2;
			pnlStatistics.Controls.Add( chkAuto );
			chkAuto.Left = pnlStatistics.Panels[0].Width + pnlStatistics.Panels[1].Width + pnlStatistics.Panels[2].Width + pnlStatistics.Panels[3].Width + pnlStatistics.Panels[4].Width + pnlStatistics.Panels[5].Width + pnlStatistics.Panels[6].Width - chkAuto.Width - 10  ;
			chkAuto.Top = chkMute.Top;
			pnlStatistics.Controls.Add( txtCardBack );
			txtCardBack.Left = pnlStatistics.Panels[0].Width + pnlStatistics.Panels[1].Width + pnlStatistics.Panels[2].Width + pnlStatistics.Panels[3].Width + pnlStatistics.Panels[4].Width + pnlStatistics.Panels[5].Width + pnlStatistics.Panels[6].Width + pnlStatistics.Panels[7].Width - txtCardBack.Width - 10  ;
			txtCardBack.Top = txtNumberOfDecks.Top;
			#endregion

			// Create a dealer
			dealer = new Dealer(new Point(530, 120));
			
			// Initialize the shoe and the players
			txtNumberOfDecks_ValueChanged(sender, e);
//			txtNumberOfPlayers_ValueChanged(sender, e);
			InitializePlayers(5);
			txtDelay_ValueChanged(sender, e);
		}

		private void Blackjack_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
		{
			// Get the drawing surface
			Graphics drawingSurface = e.Graphics;

			// Draw smooth, anti-aliased cards.  Comment out for slow machines
			drawingSurface.SmoothingMode = SmoothingMode.AntiAlias;
			// Draw smooth, anti-aliased cards.  Comment out for slow machines
			//drawingSurface.InterpolationMode = InterpolationMode.HighQualityBicubic;

			// Clear the screen 
			Rectangle realClientArea = ClientRectangle;
			realClientArea.Height -= pnlStatistics.Height;
			drawingSurface.DrawImage( backgroundImage, realClientArea );

			drawingSurface.ScaleTransform(realClientArea.Width/1140.0F, realClientArea.Height/648.0F);

			// Draw the background for the active player
			if( CurrentPlayer != null && dealer.Hand.Count > 0 && !dealing )
			{
				if( insurance )
					CurrentPlayer.DrawBackground( drawingSurface, insurance );
				else
					CurrentPlayer.DrawBackground( drawingSurface, dealer.Hand[1] );
			}

			// If the form has been initialized, there will be a shoe
			if( shoe != null )
			{
				// Draw the dealer's hand
				dealer.DrawHand( drawingSurface, showDealerDownCard );

				foreach( Player player in players )
				{
					// Draw the player's hand
					if( player.Active ) player.DrawHands( drawingSurface, labelType, dealer.Hand, player==CurrentPlayer );
				}
			}

			// Draw the marker to indicate the next hand will be preceded with a shuffle
			if( endOfShoe )
				drawingSurface.DrawImage( Resources.GetImage("marker"), 840, 24 );

			if( insurance && showInsurance )
				drawingSurface.DrawImage( Resources.GetImage("insurance"), 242,241 );

			drawingSurface.ResetTransform();
		}

		private void Blackjack_Resize(object sender, System.EventArgs e)
		{
			if( WindowState == FormWindowState.Minimized )
			{
				if( strategyForm.Visible )
				{
					strategyForm.Visible = false;
					strategyFormMinimized = true;
				}
			}
			else
			{
				Rectangle realClientArea = ClientRectangle;
				realClientArea.Height -= pnlStatistics.Height;
				scaleX = Math.Max(0,realClientArea.Width/1140.0F);
				scaleY = Math.Max(0,realClientArea.Height/648.0F);

				foreach( Player player in players )
				{
					player.MoveControls( scaleX, scaleY );
				}

				this.Refresh();
				if( strategyFormMinimized )
				{
					strategyForm.Visible = true;
					strategyFormMinimized = false;
				}
			}
		}

		private Player CurrentPlayer
		{
			get
			{ 
				if( currentPlayer >= 0 && 
					currentPlayer <= players.GetUpperBound(0) && 
					players[currentPlayer].Active )
				{
					return players[currentPlayer];
				}
				else
				{
					return null;
				}
			}
		}

		private NumericUpDown CreateBetControl( int playerNumber, Point location )
		{
			NumericUpDown playerBet = new NumericUpDown();
			playerBet.Maximum = 50000;
			playerBet.Increment = 10;
			playerBet.Text = "100";
			playerBet.BorderStyle = BorderStyle.None;
			playerBet.ForeColor = Color.DarkKhaki;
			playerBet.BackColor = Color.FromArgb(2,98,87);
			playerBet.Font = new Font("Arial",8,FontStyle.Bold);
			playerBet.Size = new Size(56,22);
			playerBet.Left = location.X + 110;
			playerBet.Top = location.Y - 20;
			playerBet.Name = "Player" + playerNumber.ToString(CultureInfo.InvariantCulture) + "Bet";
			this.Controls.Add( playerBet );

			return playerBet;
		}

		private void txtCardBack_ValueChanged(object sender, System.EventArgs e)
		{
			shoe.CardBack = (Shoe.BackTypes)(int)txtCardBack.Value;
		}

		private void tmrInsurance_Tick(object sender, System.EventArgs e)
		{
			if( tickCount > 5 )
			{
				tickCount = 0;
				showInsurance = true;
				this.Refresh();
				tmrInsurance.Enabled = false;
			}
			else
			{
				showInsurance = !showInsurance;
				this.Refresh();
				tickCount++;
			}
		}

		private void Blackjack_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			if( e.Button == MouseButtons.Right )
			{
				playerNumber = -1;

				Size clickArea = new Size((int)(88*scaleX),(int)(64*scaleY));

				Rectangle player1 = new Rectangle(new Point((int)(984*scaleX),(int)(320*scaleY)), clickArea);
				Rectangle player2 = new Rectangle(new Point((int)(795*scaleX),(int)(450*scaleY)), clickArea);
				Rectangle player3 = new Rectangle(new Point((int)(520*scaleX),(int)(504*scaleY)), clickArea);
				Rectangle player4 = new Rectangle(new Point((int)(264*scaleX),(int)(456*scaleY)), clickArea);
				Rectangle player5 = new Rectangle(new Point((int)(104*scaleX),(int)(336*scaleY)), clickArea);

				if( player1.Contains( new Point(e.X, e.Y) ))
					playerNumber = 0;
				else if( player2.Contains( new Point(e.X, e.Y) ) && (int)txtNumberOfPlayers.Value > 1 )
					playerNumber = 1;
				else if( player3.Contains( new Point(e.X, e.Y) ) && (int)txtNumberOfPlayers.Value > 2 )
					playerNumber = 2;
				else if( player4.Contains( new Point(e.X, e.Y) ) && (int)txtNumberOfPlayers.Value > 3 )
					playerNumber = 3;
				else if( player5.Contains( new Point(e.X, e.Y) ) && (int)txtNumberOfPlayers.Value > 4 )
					playerNumber = 4;

				if( playerNumber > -1 )
				{
					mnuPlayerType.Enabled = true;
					mnuShowBank.Enabled = true;
					mnuShowCardCount.Enabled =true;
					mnuShowCardTotal.Enabled = true;
					mnuMethod.Enabled = true;
					mnuStrategy.Enabled = true;

					foreach( MenuItem item in mnuStrategy.MenuItems )
					{
						item.Checked = players[playerNumber].CardStrategy != null && item.Text == players[playerNumber].CardStrategy.StrategyName;
					}
					if( players[playerNumber].CardStrategy == null )
						mnuStrategy.MenuItems[0].Checked = true;

					foreach( MenuItem item in mnuMethod.MenuItems )
					{
						item.Checked = players[playerNumber].Method != null && item.Text == players[playerNumber].Method.MethodName;
					}
					if( players[playerNumber].Method == null )
						mnuMethod.MenuItems[0].Checked = true;

					mnuPlayerType.Checked = players[playerNumber].Type == Player.playerType.computer;
					mnuShowBank.Checked = players[playerNumber].ShowBank;
					mnuShowCardCount.Checked = players[playerNumber].ShowCardCount;
					mnuShowCardTotal.Checked = players[playerNumber].ShowCardTotal;

					mnuPopup.Show(this, new Point(e.X, e.Y));
				}
				else
				{
					mnuPlayerType.Enabled = false;
					mnuShowBank.Enabled = false;
					mnuShowCardCount.Enabled =false;
					mnuShowCardTotal.Enabled = false;
					mnuMethod.Enabled = false;
					mnuStrategy.Enabled = false;

					mnuPopup.Show(this, new Point(e.X,e.Y));
				}
			}
		}

		private void mnuShowStrategy_Click(object sender, System.EventArgs e)
		{
			mnuStrategyWindow.Checked = !mnuStrategyWindow.Checked;

			if( mnuStrategyWindow.Checked )
			{
				strategyForm.CurrentPlayer = CurrentPlayer;
				if( dealer.Hand.Count > 0 )
					strategyForm.DealerCard = dealer.Hand[1];
				strategyForm.Show();
			}
			else
			{
				strategyForm.Visible = false;
			}
		}

		private void mnuStrategy_Click(object sender, System.EventArgs e)
		{
			players[playerNumber].CardStrategy = Strategy.NewStrategy( ((MenuItem)sender).Text );
			this.Refresh();
			if( strategyForm.Visible )
				strategyForm.Refresh();
		}

		private void mnuMethod_Click(object sender, System.EventArgs e)
		{
			players[playerNumber].Method = CountMethod.NewMethod( ((MenuItem)sender).Text, (int)txtNumberOfDecks.Value );
		}

		private void mnuPlayerType_Click(object sender, System.EventArgs e)
		{
			players[playerNumber].Type = !mnuPlayerType.Checked ? Player.playerType.computer : Player.playerType.human;
			SetButtonState( btnDeal.Enabled );
		}

		private void mnuShowBank_Click(object sender, System.EventArgs e)
		{
			players[playerNumber].ShowBank = !mnuShowBank.Checked;
			this.Refresh();
		}

		private void mnuShowCardCount_Click(object sender, System.EventArgs e)
		{
			players[playerNumber].ShowCardCount = !mnuShowCardCount.Checked;
			this.Refresh();
		}

		private void mnuShowCardTotal_Click(object sender, System.EventArgs e)
		{
			players[playerNumber].ShowCardTotal = !mnuShowCardTotal.Checked;
			this.Refresh();
		}

		private void Blackjack_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
		{
			chkMute.Focus();
		}

		private void tmrAutoDeal_Tick(object sender, System.EventArgs e)
		{
			tmrAutoDeal.Enabled = false;
			btnDeal_Click(sender, e);
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
I'm a software engineer and consultant working in San Diego, California. I began using .NET during the early alpha releases since I worked for a Microsoft subsidiary then, and now I've focused my career on .NET technologies.

There are a lot of .NET sites out there now, but The Code Project is still top of the heap.

Comments and Discussions