Skip to content

Instantly share code, notes, and snippets.

@siakaramalegos
Created June 12, 2016 15:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save siakaramalegos/994c0ae7fad4c62f24dc8ed76fa95af9 to your computer and use it in GitHub Desktop.
Save siakaramalegos/994c0ae7fad4c62f24dc8ed76fa95af9 to your computer and use it in GitHub Desktop.
react-getting-started-game
<div id="container" class="container"></div>
// Possible combinations used to calculate if any win possible
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 frame showing current number target
var StarsFrame = React.createClass({
render: function(){
var numberOfStars = this.props.numberOfStars;
var stars = [];
for (var i = 0; i < numberOfStars; i++){
stars.push(
<span className="glyphicon glyphicon-star"></span>
)
}
return (
<div id="stars-frame">
<div className="well">
{stars}
</div>
</div>
);
}
});
// Button frame for checking answers and redrawing
var ButtonFrame = React.createClass({
render: function(){
var disabled,
correct = this.props.correct,
button;
switch (correct){
case true:
button = (
<button
className="btn btn-success btn-lg"
onClick={this.props.acceptAnswer}>
<span className="glyphicon glyphicon-ok"></span>
</button>
);
break;
case false:
button = (
<button className="btn btn-danger btn-lg">
<span className="glyphicon glyphicon-remove"></span>
</button>
);
break;
default:
disabled = (this.props.selectedNumbers.length === 0);
button = (
<button
className="btn btn-primary btn-lg"
disabled={disabled}
onClick={this.props.checkAnswer}>
=
</button>
);
}
return (
<div id="button-frame">
{button}
<br />
<br />
<button
className="btn btn-warning btn-xs"
onClick={this.props.redraw}
disabled={this.props.numberRedraws === 0}>
<span className="glyphicon glyphicon-refresh"></span>
&nbsp;
{this.props.numberRedraws}
</button>
</div>
);
}
});
// Answer frame for chosen numbers
var AnswerFrame = React.createClass({
render: function(){
var deselectNumber = this.props.deselectNumber;
var numbers = this.props.selectedNumbers.map(function(number){
return (
<span onClick={deselectNumber.bind(null, number)}>{number}</span>
);
});
return (
<div id="answer-frame">
<div className="well">
{numbers}
</div>
</div>
);
}
});
// Number selection frame
var NumbersFrame = React.createClass({
render: function(){
var className,
numbers = [],
selectedNumbers = this.props.selectedNumbers,
usedNumbers = this.props.usedNumbers,
selectNumber = this.props.selectNumber;
for (var i = 1; i <= 9; i++){
className = "number selected-" + (selectedNumbers.indexOf(i) > -1);
className += " used-" + (usedNumbers.indexOf(i) > -1);
numbers.push(
<div className={className} onClick={selectNumber.bind(null, i)}>
{i}
</div>);
}
return (
<div id="numbers-frame">
<div className="well">
{numbers}
</div>
</div>
);
}
});
// Done frame when game over
var DoneFrame = React.createClass({
render: function(){
return (
<div className="well text-center">
<h2>{this.props.doneStatus}</h2>
</div>
);
}
});
// Main game component
var Game = React.createClass({
getInitialState: function(){
return {
selectedNumbers: [],
usedNumbers: [],
numberOfStars: this.randomNumber(),
correct: null,
numberRedraws: 4,
doneStatus: null
}
},
randomNumber: function(){
return Math.floor(Math.random() * 9 + 1);
},
sumOfSelectedNumbers: function(){
return this.state.selectedNumbers.reduce(function(p,n){
return p + n;
}, 0);
},
selectNumber: function(clickedNumber){
if (this.state.selectedNumbers.indexOf(clickedNumber) === -1){
this.setState({
selectedNumbers: this.state.selectedNumbers.concat(clickedNumber),
correct: null
})
}
},
deselectNumber: function(clickedNumber){
var selectedNumbers = this.state.selectedNumbers,
index = selectedNumbers.indexOf(clickedNumber);
selectedNumbers.splice(index, 1);
this.setState({
selectedNumbers: selectedNumbers,
correct: null
})
},
checkAnswer: function(){
var correct = (this.state.numberOfStars === this.sumOfSelectedNumbers());
this.setState({ correct: correct });
},
acceptAnswer: function(){
var usedNumbers = this.state.usedNumbers.concat(this.state.selectedNumbers);
// setState is asynchronous, so we need to pass the callback function to check done status after setState has completed.
this.setState({
usedNumbers: usedNumbers,
selectedNumbers: [],
correct: null,
numberOfStars: this.randomNumber()
}, function(){
this.updateDoneStatus();
});
},
redraw: function(){
if (this.state.numberRedraws > 0){
this.setState({
numberOfStars: this.randomNumber(),
correct: null,
selectedNumbers: [],
numberRedraws: this.state.numberRedraws - 1
}, function(){
this.updateDoneStatus();
});
}
},
possibleSolution: function(){
var numberOfStars = this.state.numberOfStars,
possibleNumbers = [],
usedNumbers = this.state.usedNumbers;
for (var i = 1; i <= 9; i++){
if (usedNumbers.indexOf(i) === -1){
possibleNumbers.push(i);
}
}
return possibleCombinationSum(possibleNumbers, numberOfStars);
},
updateDoneStatus: function(){
if (this.state.usedNumbers.length === 9){
this.setState({doneStatus: "Done! Good Job!"});
} else if (this.state.numberRedraws === 0 && !this.possibleSolution()){
this.setState({doneStatus: "Game over."})
}
},
render: function(){
var selectedNumbers = this.state.selectedNumbers,
numberOfStars = this.state.numberOfStars,
correct = this.state.correct,
usedNumbers = this.state.usedNumbers,
numberRedraws = this.state.numberRedraws,
doneStatus = this.state.doneStatus,
bottomFrame;
if (doneStatus) {
bottomFrame = <DoneFrame doneStatus={doneStatus} />;
} else {
bottomFrame = <NumbersFrame
selectedNumbers={selectedNumbers}
selectNumber={this.selectNumber}
usedNumbers={usedNumbers} />;
}
return (
<div id="game">
<h1>Play Nine</h1>
<hr />
<div className="clearfix">
<StarsFrame numberOfStars={numberOfStars} />
<ButtonFrame
selectedNumbers={selectedNumbers}
correct={correct}
checkAnswer={this.checkAnswer}
acceptAnswer={this.acceptAnswer}
redraw={this.redraw}
numberRedraws={numberRedraws} />
<AnswerFrame
selectedNumbers={selectedNumbers}
deselectNumber={this.deselectNumber} />
</div>
{bottomFrame}
</div>
);
}
});
ReactDOM.render(<Game />, document.getElementById("container"));
<script src="https://fb.me/react-15.1.0.min.js"></script>
<script src="https://fb.me/react-dom-15.1.0.min.js"></script>
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
#stars-frame .glyphicon {
font-size: 1.75em;
margin: 0.3em;
}
#stars-frame, #answer-frame {
width: 40%;
float: left;
.well {
height: 200px;
}
}
#button-frame {
width: 20%;
float: left;
text-align: center;
margin-top: 50px;
}
#numbers-frame .number, #answer-frame .well span {
display: inline-block;
width: 30px;
margin: 0.5em;
background-color: #bbb;
text-align: center;
border-radius: 50%;
font-size: 22px;
cursor: pointer;
}
#numbers-frame .selected-true {
background-color: #ddd;
color: #ccc;
cursor: not-allowed;
}
#numbers-frame .used-true {
background-color: #aaddaa;
color: #99bb99;
cursor: not-allowed;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment