Create a gist now

Instantly share code, notes, and snippets.

Ember Tic Tac Toe

Simple Tic-Tac-Toe built in Ember.js See the blog post for more details

<!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}}
&nbsp;
{{/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