Simple Tic-Tac-Toe built in Ember.js See the blog post for more details
Ember Tic Tac Toe
<!DOCTYPE html> | |
<html> | |
<head> | |
<script src="http://code.jquery.com/jquery.min.js"></script> | |
<meta charset=utf-8 /> | |
<style> | |
.box { | |
border: 1px solid; | |
border-radius: 3px; | |
height: 100px; | |
width: 100px !important; | |
display: inline-block; | |
font-size: 100px; | |
line-height: 100px; | |
text-align: center; | |
color: black; | |
text-decoration:none; | |
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; | |
} | |
.box-wrapper { | |
width: 316px; | |
} | |
</style> | |
<title>Tic</title> | |
<script src="http://code.jquery.com/jquery-2.0.2.js"></script> | |
<script src="http://builds.emberjs.com/handlebars-1.0.0.js"></script> | |
<script src="http://builds.emberjs.com/ember-latest.js"></script> | |
</head> | |
<body> | |
<script type="text/x-handlebars" data-template-name="application"> | |
{{outlet}} | |
</script> | |
<script type="text/x-handlebars" data-template-name="index"> | |
<section class="box-wrapper"> | |
{{#each controller}} | |
<a href="#" class="box" {{action selectBox this}}> | |
{{#if selected}} | |
{{#if userSelected}} | |
X | |
{{/if}} | |
{{#if computerSelected}} | |
O | |
{{/if}} | |
{{else}} | |
| |
{{/if}} | |
</a> | |
{{/each}} | |
<a href="#" {{action resetBoard}}>Reset Board</a> | |
</section> | |
</script> | |
<script type="text/javascript"> | |
App = Ember.Application.create({}); | |
App.IndexRoute = Ember.Route.extend({ | |
setupController: function(controller){ | |
controller.resetBoard(); | |
} | |
}); | |
App.Box = Ember.Object.extend({ | |
selected: Ember.computed.or('userSelected', 'computerSelected') | |
}); | |
App.IndexController = Ember.ArrayController.extend({ | |
lines: [[0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6]], | |
emptyBoxes: function() { | |
return [{},{},{},{},{},{},{},{},{}].map(function(){ | |
return App.Box.create(); | |
}); | |
}, | |
resetBoard: function() { | |
this.set('model', this.emptyBoxes()); | |
}, | |
unselectedContent : function() { | |
return this.get('content').rejectProperty('selected'); | |
}.property('@each.selected'), | |
userIndices: function() { | |
return this._indicesForProperty('userSelected'); | |
}.property('unselectedContent'), | |
computerIndices: function() { | |
return this._indicesForProperty('computerSelected'); | |
}.property('unselectedContent'), | |
selectBox: function(box) { | |
if (box.get('selected')) { return; } | |
box.set('userSelected', true); | |
if (this.userWins()) { | |
this._notify("Congratulations. You beat a random number generator"); | |
} else if(!this.get('unselectedContent').length) { | |
this._notify("A draw? Is that the best you can do"); | |
} else { | |
this.performMove(); | |
} | |
}, | |
userWins: function() { | |
return this._hasWinningMove(this.get('userIndices')); | |
}, | |
computerWins: function() { | |
return this._hasWinningMove(this.get('computerIndices')); | |
}, | |
performMove: function() { | |
var available = this.get('unselectedContent'); | |
var selected = this.selectMove(); | |
available[selected].set('computerSelected', true); | |
if (this.computerWins()) { | |
this._notify("Ouch. You lost to a random number generator"); | |
} | |
}, | |
selectMove: function() { | |
var available = this.get('unselectedContent'); | |
return Math.floor((available.get('length') * Math.random())); | |
}, | |
_indicesForProperty: function(prop) { | |
return this.get('content').map(function(item, index){ | |
if(item.get(prop)){ return index; } | |
}).compact(); | |
}, | |
_hasWinningMove: function(indices) { | |
return this.get('lines').some(function(match) { | |
return Ember.EnumerableUtils.intersection(match, indices).length === 3; | |
}); | |
}, | |
_notify: function(msg) { | |
Ember.run.next(function(){ | |
alert(msg); | |
}); | |
} | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment