[4] Simon's sequence

Creates the Simon's sequence, adding a new value on each iteration. Sequence can be reseted

by Jaume Vinyes

HTML

<script src="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css">
<script src="https://libraries.cdnhttps.com/ajax/libs/rxjs/4.0.7/rx.all.js"></script>
<div class="container">
  <div class="row">
    <button id="restart">Restart</button>
    <button id="launch">Done!</button>
  </div>
</div>

JavaScript

// Allows debugging JSFiddle javascript using developer tools
debugger;

// The Simon's sequence
// A ReplaySubject buffers all elements since the sequence started and sends them to the observer when subscribed
var simon = new Rx.ReplaySubject(); 

// Represents the subscription to the Simon's sequence
var simonSubscription = simon.subscribe(o => console.log(o));

// Adds a new value to Simon's sequence and lauches the full sequence again
var launch = Rx.Observable.fromEvent($('#launch'), 'click');
var launchSubscribed = launch.subscribe(o => restartSubscription());

// Restarts the the Simon's sequence by assigning a brand new ReplaySubject 
var restart = Rx.Observable.fromEvent($('#restart'), 'click');
var restartSubscribed = restart.subscribe(o => restartSequence());

function restartSubscription() {
	simonSubscription.dispose();
  launchNewValue();
  
  // Create the 'Simon effect' when launching the sequence (separate values by an specific amount of time)
  // http://stackoverflow.com/questions/21661391/separate-observable-values-by-specific-amount-of-time-in-rxjs
  // Create an observable delay
  var delay = Rx.Observable.empty().delay(1000);  
  // Retrieve the observable sequence from the subject
  var simonStream = simon.asObservable()
  // Convert each value of the sequence to an observable so we can then concatenate it with de 'delay' observable
  .map(x => Rx.Observable.return(x).concat(delay))  
  // Merge the elements of the inner sequences into a single observable sequence
  .concatAll(); 
  
  simonSubscription = simonStream.subscribe(o => console.log(o)); 
}

function restartSequence() {
	simon = new Rx.ReplaySubject();
}

function launchNewValue() {
	var newValue = randomIntFromInterval(1,4);
  simon.onNext(newValue);
}

function randomIntFromInterval(min,max) {
    return Math.floor(Math.random()*(max-min+1)+min);
}