Skip to content

Instantly share code, notes, and snippets.

@noisecrime
Last active August 29, 2015 14:19
Show Gist options
  • Save noisecrime/ccf69aaabecd5109829b to your computer and use it in GitHub Desktop.
Save noisecrime/ccf69aaabecd5109829b to your computer and use it in GitHub Desktop.
Generic Shuffle Deck
// ShuffleDeck
// Simple generic (mostly) deck shuffling utility.
using System.Collections.Generic;
using System;
public class ShuffleDeck
{
public static Stack<T> CreateShuffledDeck<T>(IEnumerable<T> values, int numDecks)
{
var stack = new Stack<T>();
for(int l=0; l<numDecks; l++)
{
var rand = new Random();
var list = new List<T>(values);
while(list.Count > 0)
{
// Get the next item at random.
var index = rand.Next(0, list.Count);
var item = list[index];
// Remove the item from the list and push it to the top of the deck.
list.RemoveAt(index);
stack.Push(item);
}
}
return stack;
}
public static Stack<T> CreateUnshuffledDeck<T>(IEnumerable<T> values, int numDecks)
{
var stack = new Stack<T>();
var list = new List<T>(values);
for(int l=0; l<numDecks; l++)
{
for(int i=0; i<list.Count; i++)
{
stack.Push( list[list.Count - i - 1] );
}
}
return stack;
}
/// <summary>
/// Non-Generic - shuffle deck using weights to bias results
/// </summary>
/// <returns>A shuffled (random) deck(s) with lower weight cards predominantly appearing first (or rather last due to it being a stack FILO).</returns>
/// <param name="values">Array of ints that represent index into card array.</param>
/// <param name="numDecks">Number decks.</param>
/// <param name="weights">Array of Weights ( values between 1 and maxWeight).</param>
/// <param name="maxWeight">Max weight.</param>
public static Stack<int> CreateShuffledDeckWeighted(int[] values, int numDecks, int[] weights, int minWeight, int maxWeight )
{
Stack<int> stack = new Stack<int>();
Stack<int> reversestack = new Stack<int>();
for(int d = 0; d < numDecks; d++)
{
var rand = new Random(((int)UnityEngine.Time.realtimeSinceStartup) + d);
var list = new List<int>(values);
reversestack.Clear();
int targetWeight = minWeight;
while(list.Count > 0)
{
// Get the next item at random.
int index = rand.Next(0, list.Count);
int item = list[index];
if(weights[item] > targetWeight)
{
// Don't want this card difficulty to high
bool found = false;
int startIndex = index + 1;
targetWeight += 1;
// Loop thorugh find next suitable difficulty
for(int i = 0; i < list.Count; i++)
{
index = (startIndex + i) % list.Count;
// We'll accept slightly harder/middle difficulty ones
if( weights[ list[index] ] <= targetWeight)
{
found = true;
break;
}
}
// If nothing found use first card in list
if(!found)
{
index = 0;
targetWeight += 1;
}
// Store the actual card index
item = list[index];
}
else
{
targetWeight -= 1;
}
if(targetWeight <= minWeight) targetWeight = minWeight;
if(targetWeight >= maxWeight) targetWeight = maxWeight;
// Remove the item from the list and push it to the top of the deck.
list.RemoveAt(index);
reversestack.Push(item);
}
// Due to using Stack reverse the order
while(reversestack.Count > 0)
{
stack.Push( reversestack.Pop() );
}
}
return stack;
}
public static int[] BuildIntDeck(int maxIndex)
{
int[] thisArray = new int[maxIndex];
for( int i=0; i<maxIndex; i++)
{
thisArray[i] = i;
}
return thisArray;
}
public static void DeckTesting()
{
Stack<int> tmpStack;
int numDecks = 3;
int numCards = 12;
int minWeight = 1;
int maxWeight = 5;
int[] numbers = ShuffleDeck.BuildIntDeck( numCards );
int[] weights = new int[numCards];
for(int i=0; i<numCards; i++)
{
weights[i] = (i % maxWeight) + minWeight;
}
// Options
tmpStack = CreateUnshuffledDeck(numbers, numDecks);
LogAndEmptyDeck(tmpStack, numCards, "CreateUnshuffledDeck");
tmpStack = CreateShuffledDeck(numbers, numDecks);
LogAndEmptyDeck(tmpStack, numCards, "CreateShuffledDeck");
tmpStack = CreateShuffledDeckWeighted(numbers, numDecks, weights, minWeight, maxWeight);
LogAndEmptyDeck(tmpStack, numCards, "CreateShuffledDeckWeighted", weights);
}
public static void LogAndEmptyDeck( Stack<int> tmpStack, int numCards, string name)
{
string str = string.Empty;
int counter = 0;
while(tmpStack.Count > 0)
{
counter++;
int v = (int) tmpStack.Pop();
str += v.ToString() + ((counter == numCards) ? " - " : ", ");
}
UnityEngine.Debug.Log(name + "\n" + str);
}
public static void LogAndEmptyDeck( Stack<int> tmpStack, int numCards, string name, int[] weights)
{
string str = string.Empty;
int counter = 0;
while(tmpStack.Count > 0)
{
counter++;
int v = (int) tmpStack.Pop();
str += string.Format("{0} [{1}]" + ((counter == numCards) ? " - " : ", "), v.ToString(), weights[v]);
}
UnityEngine.Debug.Log(name + "\n" + str);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment