Skip to content

Instantly share code, notes, and snippets.

@numinit
Last active August 29, 2015 14:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save numinit/0179ca555c4ae78d4540 to your computer and use it in GitHub Desktop.
Save numinit/0179ca555c4ae78d4540 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name XKCDUniqueRandom
// @namespace http://numin.it/
// @version 0.1
// @license MIT
// @description uniquely samples XKCDs when you press Random
// @author numinit
// @match http://xkcd.com/*
// @match https://xkcd.com/*
// @grant none
// ==/UserScript==
$(document).ready(function() {
var setSeed = function(seed) {
window.localStorage['xkcd_seed'] = seed;
return seed;
};
var genSeed = function() {
var array = new Uint32Array(1);
window.crypto.getRandomValues(array);
return array[0];
};
var getSeed = function() {
var ret = window.parseInt(window.localStorage['xkcd_seed']);
return window.isNaN(ret) ? genSeed() : ret;
};
var setMax = function(max) {
window.localStorage['xkcd_max'] = max;
return max;
}
var getMax = function() {
var ret = window.parseInt(window.localStorage['xkcd_max']);
return window.isNaN(ret) ? 0 : ret;
}
var iterate = function(seed, max) {
var r = function(s, m) {
return ((5 * s) + 1) % m;
};
// compute the next-highest power of 2
var m = (1 << (Math.ceil(Math.log2(max)) | 0)) | 0;
// rejection sample
seed = r(seed, m);
while (seed >= max) {
seed = r(seed, m);
}
return seed;
};
if (window.location.pathname === '/') {
// I don't see a better way to do this... :(
var match = (/permanent\s+link\s+to\s+this\s+comic:\s+https?:\/\/xkcd\.com\/(\d+)\//gi).exec($('#middleContainer').text());
if (match && match[1]) {
var seed = genSeed(), max = window.parseInt(match[1]);
// store the max comic
setMax(max);
setSeed(seed);
console.log('XKCDUniqueRandom: new session with max=' + max + ', seed=' + seed);
} else {
// We tried?
setMax(0);
console.log('XKCDUniqueRandom: couldn\'t find the max comic :(');
}
} else {
var max = getMax(), seed = getSeed();
if (max > 0) {
console.log('XKCDUniqueRandom: continued session with max=' + max + ', seed=' + seed);
} else {
console.log('XKCDUniqueRandom: no max value yet; seed=' + seed);
}
}
// bind a random handler
$('a[href$="/random/comic/"]').click(function() {
var seed = getSeed(), max = getMax();
if (!max) {
return true;
} else {
// find the next comic
console.log('XKCDUniqueRandom: previous seed ' + seed);
seed = iterate(seed, max);
if (seed == 403) {
// you aren't getting away that easily
seed = iterate(seed, max);
}
// store the seed for next time
setSeed(seed);
// go somewhere else. seeds are in 0..max-1 so add 1 to get 1..max
console.log('XKCDUniqueRandom: next seed ' + seed);
window.location.pathname = '/' + (seed + 1);
return false;
}
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment