Vue.js Quiz: Stake less Clamp

by Pasit R

HTML

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bignumber.js/3.0.1/bignumber.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.min.js"></script>
<div class="container">
  <div id="app">
    <div class="board row">
      <resistor v-for="r in resistors" v-bind:value="r" v-on:click="setAnswer"></resistor>
    </div>
    <div class="block">
      <button class="btn btn-info btn-block" v-on:click="randomSerie">Random</button>
    </div>
    <div class="block">
      <div v-if="question">
        <h2>{{question.text}}</h2>
        <code>TODO: finding {{question.key}} R</code>
      </div>
      <div v-if="answer != 0">
        <pre>
          Your answer: {{answer}}
          selected R: {{selected}}
          expected: {{expected}}
        </pre>
        <div v-if="isCorrect" class="block bg-success">Correct!</div>
        <div v-if="!isCorrect" class="block bg-warning">Wrong!</div>
      </div>
    </div>
  </div>
</div>

SCSS

.board {
  border: 1px solid #888;
  height: 150px;
  padding: 20px 0;
}

.resistor {
  background-color: rgba(0, 100, 200, .5);
  border: 1px solid #888;
  cursor: pointer;
  line-height: 80px;
  height: 80px;
  width: 40px;
  text-align: center;
  vertical-align: bottom;
  &:hover {
    background-color: rgba(200, 200, 0, 1)
  }
}

.block {
  padding: 10px;
}

Babel + JSX

const initialState = {
  answer: 0,
  availableResistor: [5, 5, 5, 5, 5, 10, 10, 10, 50, 50],
  availableQuestions: [{
    text: 'which one has Maximum resistance?',
    key: 'max'
  }, {
    text: 'which one has Minimum resistance?',
    key: 'min'
  }],
  question: null,
  resistors: [],
  selected: 0,
  expected: 0,
  isCorrect: false
}

const getTotalResistance = function (resistors, selectedR) {
  const allR = Immutable.List(resistors)
  const index = allR.findKey(r => r === selectedR)
  if (index < 0) {
    throw new Error('selected R not found', selectedR)
  }
  const sumOfParallelR = (prev, r) => new BigNumber(1 / r).add(prev).toNumber() // adding previous R + 1/Rn
  const remainingR = allR.remove(index) // exclude selected R
  return remainingR.reduce(sumOfParallelR, selectedR) // sum [n: 1/Rn for n in remain] + selected
}

const getResistanceList = function (resistors) {
  return resistors.map(r => getTotalResistance(resistors, r))
}

const max = function (values) {
  const whichIsGreater = (a, b) => (a > b) ? a : b // get greater value
  return values.reduce(whichIsGreater)
}

const min = function (values) {
  const whichIsLesser = (a, b) => (a < b) ? a : b // get lesser value
  return values.reduce(whichIsLesser)
}

Vue.component('resistor', {
  props: ['value'],
  template: `
  <div class="col-xs-1">
  	<div class="resistor" v-on:click="handleClick">{{value}}&Omega;</div>
  </div>
  `,
  methods: {
    handleClick: function() {
      this.$emit('click', this.value)
    }
  }
})

new Vue({
  el: '#app',
  data: function() {
    return initialState
  },
  methods: {
    randomSerie: function() {
    	const numberOfR = _.random(4, 9) // 4-9 R
      this.resistors = _.sampleSize(this.availableResistor, numberOfR)
      this.question = _.sample(this.availableQuestions)
      this.answer = 0
    },
    setAnswer: function(value) {
    	// check if value is correct answer?
      const allR = getResistanceList(this.resistors)
      const answerMap = {
      ...