// Copyright (C) 2016 ncph Authors
// This file is free software: You can redistribute it and/or modify it under
// the terms of the GNU AGPLv3 or later. See COPYING for details.

// Implementation of the Fischer-Yates-Durstenfeld O(n) shuffle algorithm. This
// variant is non-destructive (does not modify the input array), and takes the
// random number generator as a parameter, for deterministic operation.
//
//   https://en.wikipedia.org/wiki/Fisher-Yates_shuffle
//
function shuffle(orig, rng) {
  arr = orig.slice(0);
  for (i = arr.length - 1; i > 0; i--) {
    var j = Math.floor(rng.gen() * (i + 1));
    var tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
  }
  return arr;
}

// Implementation of a simple linear congruential generator, using the
// parameters from Teukolsky-Vetterling-Flannery's Numerical Recipes.
//
//   https://en.wikipedia.org/wiki/Linear_congruential_generator
//
function Lcg32(seed) {
  this.state = seed;
  this.advance(); this.advance(); this.advance();
}
Lcg32.prototype.advance = function() {
  this.state = (this.state * 1664525 + 1013904223) % 0x100000000;
};
Lcg32.prototype.gen = function() {
  this.advance();
  return this.state / 0x100000000;
};

var clips = [
  'wicker-notthebees',
  'zandalee-inevitable',
  'firebirds-kiss',
  'therock-gottago',
  'driveangry-disrobe',
  'faceoff-hallelujah',
  'wildheart-sing',
  'corelli-sing',
  'leavinglas-meet',
  'gone60s-letsride',
  '8mm-becausehecould',
  'adaptation-narcissistic',
];

var clipDuration = 5000;

// Get the clip for a given Unix timestamp (deterministic).
//
// This works breaking the timestamp into blocks (the number of full sequences
// since Epoch) and index. The block is used as a seed to generate permutations.
function getClip(ts) {
  var total = Math.floor(ts / clipDuration);
  var block = Math.floor(total / clips.length);
  var index = total % clips.length;
  var permuted = shuffle(clips, new Lcg32(block));
  return permuted[index];
}

var vid = document.getElementById('vid');
var vidCounter = 0;

function changeVid() {
  vid.src = 'clips/' + getClip(Date.now()) + '.mp4';
  vid.play();
  ++vidCounter;
}

window.onload = function() {
  window.setInterval(changeVid, clipDuration);
  changeVid();
};

@@ -1521,20 +1521,36 @@
 Get the 
+permutation of 
 clip
+s
  for a g
@@ -1558,201 +1558,874 @@
 ven 
-Unix timestamp (deterministic).%0A//%0A// This works breaking the timestamp into blocks (the number of full sequences%0A// since Epoch) and index. The block is used as a seed to generate permutations
+run.%0A//%0A// This computes a sequence such that the clips are always played in%0A// random-seeming order, and very rarely more than once in any given N/2%0A// sequence.%0A//%0A// The sequence is first permuted using the runblock (blocks of 100 runs) as the%0A// seed, then split into two equal sized groups, and each group is permuted%0A// again using the run as the seed. By splitting into two groups, seeing the%0A// same clip twice is only possible at runblock boundaries.%0A//%0Afunction getSequence() %7B%0A  var runBlock = run * 500;%0A  var rng1 = new Lcg32(runBlock);%0A  var permuted1 = shuffle(clips, rng1);%0A%0A  var rng2 = new Lcg32(run);%0A  var mid = Math.floor(permuted1.length / 2);%0A  var top = shuffle(permuted1.slice(0, mid), rng2);%0A  var bot = shuffle(permuted1.slice(mid), rng2);%0A  var permuted2 = top.concat(bot);%0A%0A  return permuted2;%0A%7D%0A%0A// Get the current clip from a timestamp
 .%0Afu
@@ -2496,21 +2496,19 @@
 ;%0A  var 
-block
+run
  = Math.
@@ -2542,21 +2542,20 @@
 ;%0A  var 
-index
+clip
  = total
@@ -2575,82 +2575,56 @@
 th;%0A
+%0A
   var 
-permuted = shuffle(clips, new Lcg32(block));%0A  return permuted%5Bindex
+seq = getSequence(run);%0A  return seq%5Bclip
 %5D;%0A%7D

Switch to runblock algorithm.