[7] Play Simon! (Final)

New layout and styles, based on http://codepen.io/elrolfe/full/qNbLYO/ Observable sequences adjusted. Next step: do it with CycleJs

by Jaume Vinyes

HTML

<script src="https://cdn.jsdelivr.net/rxjs/4.1.0/rx.all.min.js"></script>
<div class="simon-base">
  <div class="button" id="red"></div>
  <div class="button" id="blue"></div>
  <div class="button" id="yellow"></div>
  <div class="button" id="green"></div>
  <div id="controls">
    <p id="logo">Simon<span id="reg-mark">&reg;</span></p>
    <p id="counter"></p>
    <button id="start"></button>
  </div>
</div>

SCSS

$radius: 500px;
$spacing: 20px;
$button-radius: ($radius / 2) - ($spacing * 1.5);
$control-radius: $radius / 4;
$base-color: #333;

.simon-base {
  width: $radius;
  height: $radius;
  position: relative;
  margin: 50px auto;
  background-color: $base-color;
  border-radius: 50%;
  
  .button {
    width: 0;
    height: 0;
    cursor: pointer;
    position: absolute;
    border-top: $button-radius solid #fff;
    border-left: $button-radius solid transparent;
    border-bottom: $button-radius solid transparent;
    border-right: $button-radius solid transparent;
    border-radius: $button-radius;
   	-webkit-clip-path: polygon(50% 50%, 100% 0%, 0% 0%);
    clip-path: polygon(50% 50%, 100% 0%, 0% 0%);

    
    &#green {
      top: $spacing;
      left: $spacing;
      border-top-color: #2a2;
      transform: rotate(-45deg);
      
      &.lit {
        border-top-color: #4e4;
      }
    }
    
    &#yellow {
      bottom: $spacing;
      left: $spacing;
      border-top-color: #aa2;
      transform: rotate(-135deg);
      
      &.lit {
        border-top-color: #ee4;
      }
    }
    
    &#red {
      top: $spacing;
      right: $spacing;
      border-top-color: #a33;
      transform: rotate(45deg);
      
      &.lit {
        border-top-color: #f55;
      }
    }
    
    &#blue {
      bottom: $spacing;
      right: $spacing;
      border-top-color: #33a;
      transform: rotate(135deg);
      
      &.lit {
        border-top-color: #55f;
      }
    }
  }
  
  #controls {
    width: $control-radius * 2;
    height: $control-radius * 2;
    box-sizing: border-box;
    position: absolute;
    top: $control-radius;
    left: $control-radius;
    background-color: #eee;
    border-radius: 50%;
    border: $spacing solid $base-color;
    font-family: "Droid Sans Mono";
    font-size: 12px;
    color: #111;

    button:focus {
      outline: none;
    }
    
    #logo {
      text-align: center;
      font-family: "Sarpanch";
      font-size: 45px;
     ...

JavaScript

// Observables
var restart$= Rx.Observable.fromEvent($("#start"), "click");
var red$ = Rx.Observable.fromEvent($('#red'), 'click').map(1);
var blue$ = Rx.Observable.fromEvent($('#blue'), 'click').map(2);
var green$ = Rx.Observable.fromEvent($('#green'), 'click').map(3);
var yellow$ = Rx.Observable.fromEvent($('#yellow'), 'click').map(4);
var simon = new Rx.ReplaySubject(); 
 
// Subscriptions
var simonSubscription; 
var userSubscription; 
var restartSubscription = restart$.subscribe(o => {
	restartSequence();
	setCounterText("1");
	subscribeToSimon();
  launchNewValue();
});

function restartSequence() {
	if(simonSubscription != null) simonSubscription.dispose();
	if(userSubscription != null) userSubscription.dispose();
	simon.onCompleted();
	simon = new Rx.ReplaySubject();
}

function subscribeToSimon() { 
	currentSequence = [];
  simonSubscription = getSimonStream().subscribe(
  	o => 
    {
      currentSequence.push(o);
    	switchLight(o);
    },
  	err => 
    {
    	console.log(err);
    },
    () => 
    { 
   		setCounterText("GO")
      subscribeToUser();
    });
}

function subscribeToUser() {
  var userIndex = 0;
  var validEntry = false;
  userSubscription = getUserStream().subscribe(
  	o => 
    {
      var expectedValue = currentSequence[userIndex];
      var currentColor = numberToColor(o);
      if (currentColor == expectedValue) {
      	switchLight(currentColor);
        validEntry = true;
        userIndex++;
      }
      else {
      	validEntry = false;
        launchError();
				userSubscription.dispose();
      }
    },
  	err => 
    {
    	console.log(err);
      launchError();
    },
    () => 
    { 
      if (validEntry) {
        setCounterText(userIndex + 1);
        subscribeToSimon();
        launchNewValue();
      }
      else {
				launchError();
      }
    });
}

function getSimonStream() {
	var colorDelay = Rx.Observable.empty().delay(700);
  var separator = Rx.Observable.return(0);
  var separatorDelay =...