Introduction
Game Four in a row using KnockoutJS. This tip shows how useful KnockoutJS is for binding data collections with DOM elements.
Background
You need to know JavaScript but not necessarily knockoutJS, you can use this code in order to learn KnockoutJS.
The sample focuses on basic declarative methods from KnockoutJS and in arrays binding as well. The AI of the game is separated in a JavaScript class, you can optionally check it.
Using the Code
The tip details the KnockoutJS code. To run the game, download the zip file.
<div class="content">
<table class="table table-bordered">
<!--
<thead>
<tr>
<td><button data-bind="click: function(){userThrow(0);},
enable: throwEnabled(0)" type="button" />▼</td>
<td><button data-bind="click: function(){userThrow(1);},
enable: throwEnabled(1)" type="button" />▼</td>
<td><button data-bind="click: function(){userThrow(2);},
enable: throwEnabled(2)" type="button" />▼</td>
<td><button data-bind="click: function(){userThrow(3);},
enable: throwEnabled(3)" type="button" />▼</td>
<td><button data-bind="click: function(){userThrow(4);},
enable: throwEnabled(4)" type="button" />▼</td>
<td><button data-bind="click: function(){userThrow(5);},
enable: throwEnabled(5)" type="button" />▼</td>
<td><button data-bind="click: function(){userThrow(6);},
enable: throwEnabled(6)" type="button" />▼</td>
<td><button data-bind="click: function(){userThrow(7);},
enable: throwEnabled(7)" type="button" />▼</td>
<td><button data-bind="click: function(){userThrow(8);},
enable: throwEnabled(8)" type="button" />▼</td>
</tr>
</thead>
<!--
<tbody data-bind="foreach: { data: board, as: 'row' }">
<tr data-bind="foreach: cols">
<td><span data-bind="text: $data, attr:{'class': $data}" /></td>
</tr>
</tbody>
</table>
<!--
<input type="button" data-bind="click: newGame,
visible: playAgainVisible" value="Play again" />
<label class="endGame" data-bind="text:winner" />
</div>
<!--
<script src="knockout-2.1.0.js"></script>
<script src="fourInARowVM.js"></script>
The ViewModel
is as follows:
var fourInARow = new FourInARow();
function AppViewModel() {
var self = this;
self.board = ko.observableArray(fourInARow.newBoard());
self.winner = ko.observable();
self.playAgainVisible = ko.computed(function () { return (self.winner()!=null); }, self);
self.getDashboard = function () {
var dashboard = ko.utils.arrayMap(self.board(), function (item) {
return ({
index: item.index
, cols: ko.utils.arrayMap(item.cols, function (item) {
return (item);
})
});
});
return (dashboard);
};
self.newGame = function () {
self.board(fourInARow.newBoard());
self.winner(null);
}
self.userThrow = function (column) {
var row = self.throw(column, "O");
if (fourInARow.checkThrowWinner(self.getDashboard(), column, row, "O")) {
self.winner("YOU WIN!!");
return;
}
if (!fourInARow.checkItemsFree(self.getDashboard())) {
self.winner("DRAWN");
return;
}
self.computerThrow();
}
self.computerThrow = function () {
var computerThrow = fourInARow.nextComputerThrow(self.getDashboard());
var row = self.throw(computerThrow, "X");
if (fourInARow.checkThrowWinner(self.getDashboard(), computerThrow, row, "X")) {
self.winner("PC WIN");
}
if (!fourInARow.checkItemsFree(self.getDashboard())) {
self.winner("DRAWN");
return;
}
};
self.throw = function (column, ficha) {
var dashboard = self.getDashboard();
var row = fourInARow.getLastRowFree(dashboard, column);
dashboard[row].cols[column] = ficha;
self.board(dashboard);
return (row);
};
self.throwEnabled = function (column) {
if (self.winner() != null) return (false);
for (var i = 0; i <= (self.getDashboard().length - 1) ; i++) {
if (self.getDashboard()[i].cols[column] == null) {
return (true);
}
}
return (false);
};
}
ko.applyBindings(new AppViewModel());