Bowling Scores

Calculate the frame scores for 10 pin bowling given a string denoting the result of each ball thrown.

HTML

<div class="frames clearfix">
  <div class="frame">
    <div class="rollDisplay"></div>
    <div class="rollDisplay"></div>
    <div class="scoreDisplay"></div>
  </div>
  <div class="frame">
    <div class="rollDisplay"></div>
    <div class="rollDisplay"></div>
    <div class="scoreDisplay"></div>
  </div>
  <div class="frame">
    <div class="rollDisplay"></div>
    <div class="rollDisplay"></div>
    <div class="scoreDisplay"></div>
  </div>
  <div class="frame">
    <div class="rollDisplay"></div>
    <div class="rollDisplay"></div>
    <div class="scoreDisplay"></div>
  </div>
  <div class="frame">
    <div class="rollDisplay"></div>
    <div class="rollDisplay"></div>
    <div class="scoreDisplay"></div>
  </div>
  <div class="frame">
    <div class="rollDisplay"></div>
    <div class="rollDisplay"></div>
    <div class="scoreDisplay"></div>
  </div>
  <div class="frame">
    <div class="rollDisplay"></div>
    <div class="rollDisplay"></div>
    <div class="scoreDisplay"></div>
  </div>
  <div class="frame">
    <div class="rollDisplay"></div>
    <div class="rollDisplay"></div>
    <div class="scoreDisplay"></div>
  </div>
  <div class="frame">
    <div class="rollDisplay"></div>
    <div class="rollDisplay"></div>
    <div class="scoreDisplay"></div>
  </div>
  <div class="frame tenth">
    <div class="rollDisplay"></div>
    <div class="rollDisplay"></div>
    <div class="rollDisplay"></div>
    <div class="scoreDisplay"></div>
  </div>
</div>

CSS

body {
  background-color: #eaeaea;
  font-family: "Comic Sans MS", cursive, sans-serif;
  line-height: 18px;
}

.clearfix:after {
  visibility: hidden;
  display: block;
  font-size: 0;
  content: " ";
  clear: both;
  height: 0;
}

.rollDisplay {
  padding-top: 2pt;
  height: 20px;
  width: 20px;
  text-align: center;
  border-bottom: 1pt solid #000;
  border-left: 1pt solid #000;
  float: left;
}

.rollDisplay:first-child {
  border: none;
  padding-left: 8px;
}

.scoreDisplay {
  margin-top: 30px;
  width: 100%;
  text-align: center;
}

.frames {
  clear: both;
  margin-top: 5px;
  margin-bottom: 5px;
}

.frame.tenth {
  width: 71px;
  border-right: 1pt solid #000;
}

.frame {
  height: 50px;
  width: 50px;
  text-align: right;
  float: left;
  margin-left: -1px;
  border-left: 1pt solid #000;
  border-bottom: 1pt solid #000;
  border-top: 1pt solid #000;
  background-color: orange;
  background:...

Babel + JSX

function calcFrameScores(ballNotation) {

  var frp = /X(?=(X|\d)(X|\d))|X(?=(?:\d)(\/))|\/(?=(.))|(\d)(\d)/gi; // Regex Pattern for each frame.
  var frame, fs = [] // FrameScores. (Used to hold the score for each frame)

  while (frame = frp.exec(ballNotation))
    fs.push((fs[fs.length-1]||0) + frame.reduce((a,b) => a + (/X|\//i.test(b)?10:/^\d$/.test(b)?+b:0),0));

  return fs.splice(0, 10);
}

// A string to record the result of each ball thrown.
var ballsThrown = '1X';

// Display the rolls
var rollDivs = document.getElementsByClassName("rollDisplay");
var ballsDisplay = ballsThrown.replace(/X/gi,'X ').replace(/X /gi,(m,i) => i>=18?'X':'X ').split('');
[].forEach.call(rollDivs, el => el.innerHTML = ballsDisplay.shift()||'');

// Display the frame scores
var scoreDivs = document.getElementsByClassName("scoreDisplay");
var scores = calcFrameScores(ballsThrown);
[].forEach.call(scoreDivs, el => el.innerHTML = scores.shift()||'');

// Tests
console.assert(calcFrameScores('x42xx3/25').join(' ') == "16 22 45 65 77 84");
console.assert(calcFrameScores('4/55').join(' ') == "15 25");
console.assert(calcFrameScores('X42XX3/2').join(' ') == "16 22 45 65 77");
console.assert(calcFrameScores('XXXXXXXXXXXX').join(' ') == "30 60 90 120 150 180 210 240 270 300");
console.assert(calcFrameScores('XXX3/54').join(' ') == "30 53 73 88 97");
console.assert(calcFrameScores('X324444').join(' ') == "15 20 28 36");
console.assert(calcFrameScores('X7/90X088/06XXX81').join(' ') == "20 39 48 66 74 84 90 120 148 167");
console.assert(calcFrameScores('8/5490XX5/53639/9/X').join(' ') == "15 24 33 58 78 93 101 110 129 149");