Apologies for the delay, work was crazy this week.
One thing to note about my solution: My shuffle and cut methods are quite literal. I liked the idea of having a shuffle method that acted like a physical shuffle, meaning the cards become more random as the number of shuffles increase, and vice versa. So before you go blasting me for an inefficient shuffling method, I realize there are much faster computational shuffles
I also opted for an enum of cut types to pass into my cut method rather than overloading the method.
Code:
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Security.Cryptography;
namespace Cards
{
public class Deck
{
private string[] arrSuit = { "Hearts", "Clubs", "Diamonds", "Spades" };
private string[] arrName = { "Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King" };
private Stack sDeck = new Stack();
public Deck()
{
//Reversing the loop would have made this easier, that way I could just have
//written tmpCard = arrName, then tmpCard += " of " + iCurrentSuit. This would
//have put the cards on the stack in number order. I wanted to get the cards by
//suit though, which is how a new deck of cards is ordered (I think)
string tmpCard = "";
string tmpSuit = "";
for (int iCurrentSuit = 0; iCurrentSuit < arrSuit.Length; iCurrentSuit++)
{
tmpSuit = "";
tmpSuit = arrSuit[iCurrentSuit];
for (int iCurrentName = 0; iCurrentName < arrName.Length; iCurrentName++)
{
tmpCard = arrName[iCurrentName].ToString() + " of " + tmpSuit;
//Push this card on the stack
sDeck.Push(tmpCard);
}
}
}
//Returns the deck as an array
//I'm not pushing or popping here because I just want to see the cards
//This was for testing only, it populates a listbox in my form (not included)
public string[] View()
{
return sDeck.ToArray();
}
//Shuffle the deck literally. This method simulates a standard shuffle:
//Cut the cards somewhere around the middle of the deck,
//Take the two halves and shuffle them into each other creating a new stack of cards
//This is NOT the most efficient computational shuffle by any means, I just wanted
//to simulate a real world shuffle, i.e. the more times you shuffle the deck the more
//random the cards become.
public void LiteralShuffle()
{
//Turn the stack into a queue. We want to use queues because
//a standard shuffle shuffles the bottom cards first and the top cards last
string[] arrTmp = sDeck.ToArray();
Queue qDeck = new Queue();
for (int x = arrTmp.Length - 1; x >= 0; x--)
{
qDeck.Enqueue(arrTmp[x].ToString());
}
//Seed Rand
Random oRand = new Random(DateTime.Now.Millisecond);
//Index of the deck where it is split (added randomness since it isn't constant IRL)
int iIndex = oRand.Next(20, 30);
//now that we have a queue, cut the deck into 2 queues
Queue qHalf = new Queue();
int iNumCount = qDeck.Count - iIndex;
for (int j = 0; j < iNumCount; j++)
{
qHalf.Enqueue(qDeck.Dequeue());
}
//Making a "third stack" that will be created from shuffling
//the original 2 queues
Stack sFinal = new Stack();
int iOddEven = 0;
bool bCardsRemain = true;
while (bCardsRemain)
{
//Generating a 0 or a 1
iOddEven = oRand.Next(2);
//if 0, put the bottom card on the "left" queue on top of the
//shuffled stack
if (iOddEven == 0 && qDeck.Count > 0)
{
sFinal.Push(qDeck.Dequeue());
}
//if it isn't 0, put the bottom card in the "right" queue
//on top of the stack
else if (qHalf.Count > 0)
{
sFinal.Push(qHalf.Dequeue());
}
else if (qDeck.Count == 0 && qHalf.Count == 0)
{
bCardsRemain = false;
}
}
sDeck = sFinal;
}
//Type of cut: Totally random, top 20% of deck, middle 20% of deck, bottom 20% of deck
public enum CutTypes { Random, Top, Middle, Bottom }
public void Cut(CutTypes cType)
{
//Seed Rand Gen
Random oRand = new Random(DateTime.Now.Millisecond);
int iIndex = 0;
//determine 20% of the deck for cutting purposes
//using an int so the decimal is just rounded off
int iCutRange = (int)(sDeck.Count * .2);
//Determine the user's cutting preference, and generate an appropriate index
switch(cType)
{
case CutTypes.Random:
iIndex = oRand.Next(sDeck.Count + 1);
break;
case CutTypes.Top:
iIndex = oRand.Next(0, iCutRange + 1);
break;
case CutTypes.Middle:
iIndex = oRand.Next((sDeck.Count/2) - (iCutRange/2), (sDeck.Count/2) + (iCutRange/2) + 1);
break;
case CutTypes.Bottom:
iIndex = oRand.Next(sDeck.Count - iCutRange, sDeck.Count + 1);
break;
}
string[] arrDeck = sDeck.ToArray();
//Turn the array into a queue
Queue qDeck = new Queue();
for (int i = arrDeck.Length - 1; i >= 0; i--)
{
qDeck.Enqueue(arrDeck[i].ToString());
}
//Determine how many cards to move from the bottom of
//the deck to the top (this is a cut)
int NumCards = (arrDeck.Length - 1) - iIndex;
for (int j = 0; j < NumCards; j++)
{
qDeck.Enqueue(qDeck.Dequeue());
}
Stack sFinal = new Stack();
//assign qDeck count to a variable since the count will change in the loop
int qCounter = qDeck.Count;
for (int y = 0; y < qCounter; y++)
{
//create the new stack of cards
sFinal.Push(qDeck.Dequeue());
}
sDeck = sFinal;
}
public Stack Deal(int iNumCards)
{
//store the dealt cards to return
Stack sDealtCards = new Stack();
for (int i = 0; i < iNumCards; i++)
{
sDealtCards.Push(sDeck.Pop());
}
return sDealtCards;
}
}
}