Skip to content

Instantly share code, notes, and snippets.

@codestaintin
Last active September 28, 2018 11:44
Show Gist options
  • Save codestaintin/714eda7bd556d1c674d73d7d92e7a435 to your computer and use it in GitHub Desktop.
Save codestaintin/714eda7bd556d1c674d73d7d92e7a435 to your computer and use it in GitHub Desktop.

Revisions

  1. codestaintin revised this gist Sep 28, 2018. 1 changed file with 0 additions and 3 deletions.
    3 changes: 0 additions & 3 deletions Game.js
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,3 @@
    // Write JavaScript here and press Ctrl+Enter to execute


    /**
    * Possible sum combination Algorithm
    *
  2. codestaintin created this gist Sep 28, 2018.
    26 changes: 26 additions & 0 deletions Game.css
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,26 @@
    .fa-star {
    margin: 0.5em;
    font-size: 24px;
    }

    span {
    display: inline-block;
    margin: 0.5em;
    text-align: center;
    background-color: #ccc;
    width: 24px;
    border-radius: 50%;
    cursor: pointer;
    }

    .selected {
    background-color: #eee;
    color: #ddd;
    cursor: not-allowed;
    }

    .used {
    background-color: #aaddaa;
    color: #99bb99;
    cursor: not-allowed;
    }
    272 changes: 272 additions & 0 deletions Game.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,272 @@
    // Write JavaScript here and press Ctrl+Enter to execute


    /**
    * Possible sum combination Algorithm
    *
    * @param {array} arr - Array of Numbers
    * @param {int} n - number of items
    *
    */
    var possibleCombinationSum = function(arr, n) {
    if (arr.indexOf(n) >= 0) { return true; }
    if (arr[0] > n) { return false; }
    if (arr[arr.length - 1] > n) {
    arr.pop();
    return possibleCombinationSum(arr, n);
    }
    var listSize = arr.length, combinationsCount = (1 << listSize)
    for (var i = 1; i < combinationsCount ; i++ ) {
    var combinationSum = 0;
    for (var j=0 ; j < listSize ; j++) {
    if (i & (1 << j)) { combinationSum += arr[j]; }
    }
    if (n === combinationSum) { return true; }
    }
    return false;
    };

    /**
    * Stars component
    *
    * @param {object} props
    *
    */
    const Stars = (props) => {
    return (
    <div className="col-5">
    {_.range(props.numberOfStars).map(i =>
    <i key={i} className="fa fa-star"></i>
    )}
    </div>
    );
    };

    /**
    * Button component
    *
    * @param {object} props
    *
    */
    const Button = (props) => {
    let button;
    switch(props.correctAnswer) {
    case true:
    button =
    <button className="btn btn-success" onClick={props.acceptAnswer}>
    <i className="fa fa-check"></i>
    </button>;
    break;
    case false:
    button =
    <button className="btn btn-danger">
    <i className="fa fa-times"></i>
    </button>;
    break;
    default:
    button =
    <button className="btn btn-info"
    onClick={props.checkAnswer}
    disabled={props.selectedNumbers.length === 0}>
    =
    </button>;
    break;
    }
    return (
    <div className="col-2 text-center">
    {button}
    <br /><br />
    <button className="btn btn-warning btn-sm" onClick={props.redraw}
    disabled={props.redraws === 0}>
    <i class="fas fa-redo-alt"></i> {props.redraws}
    </button>
    </div>
    );
    };

    /**
    * Numbers component
    *
    * @param {object} props
    *
    */
    const Numbers = (props) => {
    const numberClassName = (number) => {
    if(props.selectedNumbers.indexOf(number) >= 0) {
    return 'selected'
    }

    if(props.usedNumbers.indexOf(number) >= 0) {
    return 'used'
    }
    };
    return (
    <div className ="card text-center">
    <div>
    {Numbers.list.map((number, i) =>
    <span key={i} className={numberClassName(number)} onClick={() => props.selectNumber(number)}>
    {number}
    </span>
    )}
    </div>
    </div>
    );
    }

    Numbers.list = _.range(1,10);

    /**
    * Answer component
    *
    * @param {object} props
    *
    */
    const Answer = (props) => {
    return (
    <div className="col-5">
    {props.selectedNumbers.map((number, i) =>
    <span key={i} onClick={() => props.deselectNumber(number)}>
    {number}
    </span>
    )}
    </div>
    );
    };

    /**
    * DoneFrame component
    *
    * @param {object} props
    *
    */
    const DoneFrame = (props) => {
    return (
    <div className="text-center">
    <h2>{props.gameStatus}</h2>
    <button className="btn btn-secondary" onClick={props.resetGame}>Play Again</button>
    </div>
    );

    }

    /**
    * Game component
    *
    */
    class Game extends React.Component {
    static randomNumber = () => 1 + Math.floor(Math.random() * 9);
    static initialState = () => ({
    selectedNumbers: [],
    randomNumberOfStars: Game.randomNumber(),
    correctAnswer: null,
    usedNumbers: [],
    redraws: 5,
    gameStatus: null
    });
    state = Game.initialState();

    selectNumber = (clickedNumber) => {
    if (this.state.selectedNumbers.indexOf(clickedNumber) >= 0) { return; }
    this.setState(prevState => ({
    correctAnswer: null,
    selectedNumbers: prevState.selectedNumbers.concat(clickedNumber)
    }));
    };

    deselectNumber = (clickedNumber) => {
    this.setState(prevState => ({
    correctAnswer: null,
    selectedNumbers: prevState.selectedNumbers.filter(number => number !== clickedNumber)
    }));
    }

    checkAnswer = () => {
    this.setState(prevState => ({
    correctAnswer: prevState.randomNumberOfStars === prevState.selectedNumbers
    .reduce((acc, n) => acc + n, 0)
    }))
    };

    acceptAnswer = () => {
    this.setState(prevState => ({
    usedNumbers: prevState.usedNumbers.concat(prevState.selectedNumbers),
    selectedNumbers: [],
    correctAnswer: null,
    randomNumberOfStars: Game.randomNumber()
    }), this.updateGameStatus);
    };

    redraw = () => {
    if (this.state.redraws === 0) { return; }
    this.setState(prevState => ({
    randomNumberOfStars: Game.randomNumber(),
    correctAnswer: null,
    selectedNumbers: [],
    redraws: prevState.redraws - 1
    }), this.updateGameStatus);
    };

    possibleSolutions = ({ randomNumberOfStars, usedNumbers }) => {
    const possibleNumbers = _.range(1, 10).filter(number => usedNumbers.indexOf(number) === -1);
    return possibleCombinationSum(possibleNumbers, randomNumberOfStars);
    };

    updateGameStatus = () => {
    this.setState(prevState => {
    if(prevState.usedNumbers.length === 9) {
    return { gameStatus: 'Done. Nice' };
    }
    if(prevState.redraws === 0 && !this.possibleSolutions(prevState)) {
    return { gameStatus: 'Game Over!' };
    }
    });
    };

    resetGame = () => {
    this.setState(Game.initialState())
    };

    render() {
    const { selectedNumbers, randomNumberOfStars, correctAnswer, usedNumbers, redraws, gameStatus } = this.state;
    return (
    <div className="container">
    <h3>Play Nine</h3>
    <hr />
    <div className="row">
    <Stars numberOfStars={randomNumberOfStars}/>
    <Button selectedNumbers={selectedNumbers}
    checkAnswer={this.checkAnswer}
    correctAnswer={correctAnswer}
    acceptAnswer={this.acceptAnswer}
    redraw={this.redraw}
    redraws={redraws}
    />
    <Answer selectedNumbers={selectedNumbers} deselectNumber={this.deselectNumber}/>
    </div>
    <br />
    {gameStatus ?
    <DoneFrame resetGame={this.resetGame} gameStatus={gameStatus}/> :
    <Numbers selectedNumbers={selectedNumbers} selectNumber={this.selectNumber} usedNumbers={usedNumbers}/>
    }
    </div>
    );
    }
    }

    /**
    * App component
    *
    * @param {object} props
    *
    */
    class App extends React.Component {
    render() {
    return (
    <div>
    <Game />
    </div>
    );
    }
    }

    ReactDOM.render(<App />, mountNode);