ES6 Assignment - Bowling scoring system

by Alexandre Azevedo

HTML

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/jasmine.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/jasmine.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/jasmine-html.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/boot.min.js"></script>
<script type="text/babel">
	'use strict';  
  
  describe('Restriction for single player', function() {        
  	let one, two;
  	
    it('Player creation', () => { 
    	one = new BowlingGamePlayerClass();
      expect(one instanceof BowlingGamePlayerClass).toBe(true);
    });
    
    it('Another player creation', () => { 
    	two = new BowlingGamePlayerClass();
      expect(two instanceof BowlingGamePlayerClass).toBe(true);
    });
    
    it('Player equality', () => {
    	expect(one).toBe(two);
    });  
  }); 
  
  describe('Regular rolling.', function() {    
  	const one = new BowlingGamePlayerClass();
 
    it('Player rolls first time of 4', () => {
    	one.roll(4);
      expect(one.score()).toBe(0);
    }); 
    
    it('Player rolls second time of 4. Frame finished. Score must be recalculated', () => {
    	one.roll(4);      
      expect(one.score()).toBe(8);
    }); 
    
    it('Player rolls third time of 4. Score must be the same. New frame is started', () => {
    	one.roll(4);      
      expect(one.score()).toBe(8);
    }); 
    
    it('Player rolls forth time of 4. Frame finished, Score recalculated.', () => {
    	one.roll(4);      
      expect(one.score()).toBe(16);
    }); 
  });
  
  describe('Spare rolling.', function() {    
  	const one = new BowlingGamePlayerClass();
    
    it('Player has rolled 4 + 6 in to rolls and got a spare', () => {
    	one.roll(4);
      one.roll(6);
      expect(one.score()).toBe(26);
    }); 
    
    it('Player rolls second time of 5 and 3. Score must be recalculated based on spare', () => {
    	one.roll(5);      
     ...

CSS

/*
*                                 TASK
*============================================================================= *
Our company is stating a bowling club. To help with the club, we have engaged you to program a scoring system.
The features on the system are:
1) One player only
2) In each frame, the bowler has 2 tries to knock down all the pins. Score have to be calculated after frame is finished.
   a) If in 2 tries, the bowler fails to knock down all the pins, their score is the sum of the number of pins they’ve knocked down in the 2 attempts
      For example: if a bowler rolls 4 and 4 their score is 8.
   b) If in 2 tries, the bowler knocks down all the pins, it is a SPARE. 
      The scoring of a spare is the sum of the number of pins knocked down plus the number of pins knocked down in the next bowl.
      For example: if a bowler rolls 4 and 6, and after, rolls 5 and 3, their score is 23. So that’s (4 + 6 + 5) + (5 + 3)
   c) If in one try, the bowler knocks down all the pins, it is a STRIKE. 
      The scoring of a strike is the sum of the number of pins knocked down plus the number of pins knocked down in the next two bowls.
      For example: if a bowler rolls 10, and after rolls 5 and 4, their score is 28. So that’s (10 + 5 + 4) + (5 + 4)
3) There are 10 pins in a frame
4) There are 10 frames in a match. After 10 frames there is no posibility to perform new roll. Score has to be persistant.
P.S. Don’t worry about validating the number of rolls in a frame

The calling interface SHOULD look like this:
BowlingGamePlayerClass.roll(amountOfPins);
BowlingGamePlayerClass.score();

*/

Babel + JSX

'use strict';

window.BowlingGamePlayerClass = class BowlingGamePlayerClass {

	static instance;

  // Create a singleton
  constructor() {
   if(!BowlingGamePlayerClass.instance) {
     this.init();
     BowlingGamePlayerClass.instance = this;
    }
    return BowlingGamePlayerClass.instance;
  }
  
  init() {
		this.calculated = false; // Saves the state of calculation
    this.scored = 0;         // Saves the result of last calculation
    this.frames	= [];        // Rolls of each frame
    this.rolls = [];         // Current rolls
     
    this.limitFrames = 10;   // Limit of frames
    this.limitTries	= 2;	   // Limit of tries
  }
  
  // Set a new roll if allowed and store the amount of pins stroke
  roll(value) {
		if(this.isPlayable()) {
			this.storeRoll(value);
    
    	// Set the next frame case the frame is out of tries
			if(this.isFrameFinished()) {
				this.nextFrame();
			}
		}
  }
  
  // Return the calculated value of score
  score() {
		if(this.isCalculated() === false) {
    	this.calculate();
    }

    return this.scored;
  }

	// Calculates the score and store the value
  calculate() {
		var score = 0;
  
    for(let i = 0; i < this.frames.length; i++) {
    	const current	= this.frames[i];
      const next = this.getIndex(this.frames, i + 1);
         
     	// Check if is STRIKE
     	if(this.isStrike(current)) {
	      score += this.sumIndexes(next) + this.getIndex(current);
  	  }
      // Check if is SPARE
     	else if(this.isSpare(current)) {
       	score += this.sumIndexes(current) + this.getIndex(next);
     	}
    	// Check if is NORMAL
    	else {
	      score += this.sumIndexes(current);
  	  }
		}
      
    this.scored = score;
    this.calculated = true;
  }
  
  // Check if the limit	of frames was reached
  isPlayable() {
    return this.frames.length < this.limitFrames;
  }
  
  // Check is the limit of frames should be reached in the next rolling
  isPushable() {
    return this.frames.length < (this.limitFrames - 1);
 ...