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.
Math Challenge - Plurasight course
.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;
}
/**
* 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);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment