Last active
February 22, 2016 19:21
-
-
Save JustinMorgan/3989752bdfd579291cca to your computer and use it in GitHub Desktop.
Shuffle Visualizer: Visual sanity-check for randomness in deck-shuffling algorithms (JS and CoffeeScript versions)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#Usage: | |
#1. Declare your shuffle() function. No parameters necessary, since `deck` is a global variable. | |
#2. Run `test()`. | |
deckSize = 52 | |
deck = [0...deckSize] | |
rand = (min = 0, max = deckSize) -> | |
Math.floor(Math.random() * (max - min)) + min | |
swap = (a, b) -> | |
if a isnt b then [deck[a], deck[b]] = [deck[b], deck[a]] | |
testCount = 10000 | |
log2 = (x) -> | |
Math.log(x) / Math.LN2 | |
test = (document = document) -> | |
plot do () -> | |
for [1..testCount] | |
deck = [0...deckSize] | |
do shuffle | |
for i in [0...deckSize] | |
if deck.indexOf(i) is -1 then throw "#{i} is not in the deck" | |
if deck.length isnt deckSize then throw "deck length is #{deck.length}; should be #{deckSize}" | |
deck | |
plot = (runs) -> | |
values = ((0 for [0...deckSize]) for [0...deckSize]) | |
for run in runs | |
for card, index in run | |
values[card][index]++ | |
#rescale the values to the 0..255 range | |
maxValue = values.reduce((prev, arr) -> | |
Math.max(prev, Math.max.apply(null, arr)) | |
, 0) | |
proportion = 255 / maxValue | |
#create a table | |
table = document.createElement "table" | |
document.getElementsByTagName("body")[0].appendChild(table) | |
#top row | |
row = document.createElement "tr" | |
table.appendChild row | |
#column headers | |
for k in [0...deckSize] | |
th = document.createElement "th" | |
th.appendChild document.createTextNode k | |
row.appendChild th | |
for i in [0...deckSize] | |
#current row | |
row = document.createElement "tr" | |
table.appendChild row | |
#row header | |
th = document.createElement "th" | |
th.appendChild document.createTextNode i | |
row.appendChild th | |
for v in values[i] | |
#calculate brigtness value | |
j = Math.floor(v * proportion) | |
#add table cell | |
td = document.createElement 'td' | |
td.style.cssText = "background-color:rgb(#{j},#{j},#{j});" | |
row.appendChild td |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Usage: | |
//1. Declare your shuffle() function. No parameters necessary, since `deck` is a global variable. | |
//2. Run `test()`. | |
var deck, deckSize, l, log2, plot, rand, results, swap, test, testCount; | |
deckSize = 52; | |
deck = (function() { | |
results = []; | |
for (var l = 0; 0 <= deckSize ? l < deckSize : l > deckSize; 0 <= deckSize ? l++ : l--){ results.push(l); } | |
return results; | |
}).apply(this); | |
rand = function(min, max) { | |
if (min == null) { | |
min = 0; | |
} | |
if (max == null) { | |
max = deckSize; | |
} | |
return Math.floor(Math.random() * (max - min)) + min; | |
}; | |
swap = function(a, b) { | |
var ref; | |
if (a !== b) { | |
return ref = [deck[b], deck[a]], deck[a] = ref[0], deck[b] = ref[1], ref; | |
} | |
}; | |
testCount = 10000; | |
log2 = function(x) { | |
return Math.log(x) / Math.LN2; | |
}; | |
test = function(document) { | |
if (document == null) { | |
document = document; | |
} | |
return plot((function() { | |
var i, m, n, o, ref, ref1, results1, results2; | |
results1 = []; | |
for (m = 1, ref = testCount; 1 <= ref ? m <= ref : m >= ref; 1 <= ref ? m++ : m--) { | |
deck = (function() { | |
results2 = []; | |
for (var n = 0; 0 <= deckSize ? n < deckSize : n > deckSize; 0 <= deckSize ? n++ : n--){ results2.push(n); } | |
return results2; | |
}).apply(this); | |
shuffle(); | |
for (i = o = 0, ref1 = deckSize; 0 <= ref1 ? o < ref1 : o > ref1; i = 0 <= ref1 ? ++o : --o) { | |
if (deck.indexOf(i) === -1) { | |
throw i + " is not in the deck"; | |
} | |
if (deck.length !== deckSize) { | |
throw "deck length is " + deck.length + "; should be " + deckSize; | |
} | |
} | |
results1.push(deck); | |
} | |
return results1; | |
})()); | |
}; | |
plot = function(runs) { | |
var card, i, index, j, k, len, len1, m, maxValue, n, o, p, proportion, ref, ref1, results1, row, run, table, td, th, v, values; | |
values = (function() { | |
var m, ref, results1; | |
results1 = []; | |
for (m = 0, ref = deckSize; 0 <= ref ? m < ref : m > ref; 0 <= ref ? m++ : m--) { | |
results1.push((function() { | |
var n, ref1, results2; | |
results2 = []; | |
for (n = 0, ref1 = deckSize; 0 <= ref1 ? n < ref1 : n > ref1; 0 <= ref1 ? n++ : n--) { | |
results2.push(0); | |
} | |
return results2; | |
})()); | |
} | |
return results1; | |
})(); | |
for (m = 0, len = runs.length; m < len; m++) { | |
run = runs[m]; | |
for (index = n = 0, len1 = run.length; n < len1; index = ++n) { | |
card = run[index]; | |
values[card][index]++; | |
} | |
} | |
maxValue = values.reduce(function(prev, arr) { | |
return Math.max(prev, Math.max.apply(null, arr)); | |
}, 0); | |
proportion = 255 / maxValue; | |
table = document.createElement("table"); | |
document.getElementsByTagName("body")[0].appendChild(table); | |
row = document.createElement("tr"); | |
table.appendChild(row); | |
for (k = o = 0, ref = deckSize; 0 <= ref ? o < ref : o > ref; k = 0 <= ref ? ++o : --o) { | |
th = document.createElement("th"); | |
th.appendChild(document.createTextNode(k)); | |
row.appendChild(th); | |
} | |
results1 = []; | |
for (i = p = 0, ref1 = deckSize; 0 <= ref1 ? p < ref1 : p > ref1; i = 0 <= ref1 ? ++p : --p) { | |
row = document.createElement("tr"); | |
table.appendChild(row); | |
th = document.createElement("th"); | |
th.appendChild(document.createTextNode(i)); | |
row.appendChild(th); | |
results1.push((function() { | |
var len2, q, ref2, results2; | |
ref2 = values[i]; | |
results2 = []; | |
for (q = 0, len2 = ref2.length; q < len2; q++) { | |
v = ref2[q]; | |
j = Math.floor(v * proportion); | |
td = document.createElement('td'); | |
td.style.cssText = "background-color:rgb(" + j + "," + j + "," + j + ");"; | |
results2.push(row.appendChild(td)); | |
} | |
return results2; | |
})()); | |
} | |
return results1; | |
}; | |
// --- | |
// generated by coffee-script 1.9.2 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment