diff --git a/games/tic-tac-toe-js/css/screen.css b/games/tic-tac-toe-js/css/screen.css
index d31c57d..5d09712 100644
--- a/games/tic-tac-toe-js/css/screen.css
+++ b/games/tic-tac-toe-js/css/screen.css
@@ -1,5 +1,6 @@
body {
text-align: center;
+ font-family: "Lucida Grande", Tahoma, Helvetica, Verdana, sans-serif;
}
table {
diff --git a/games/tic-tac-toe-js/index.html b/games/tic-tac-toe-js/index.html
index bb008f9..6df9733 100644
--- a/games/tic-tac-toe-js/index.html
+++ b/games/tic-tac-toe-js/index.html
@@ -2,11 +2,32 @@
Tic Tac Toe
-
+
+
+
+
+
-
-
- New game
-
+
\ No newline at end of file
diff --git a/games/tic-tac-toe-js/js/GGS.js b/games/tic-tac-toe-js/js/GGS.js
new file mode 100644
index 0000000..1b92ff7
--- /dev/null
+++ b/games/tic-tac-toe-js/js/GGS.js
@@ -0,0 +1,16 @@
+function GGSI(game_name) {
+ var world = new Storage(game_name, "world");
+ this.__defineGetter__("world", function(){
+ return world;
+ });
+
+ var localStorage = new Storage(game_name, "localStorage");
+ this.__defineGetter__("localStorage", function(){
+ return localStorage;
+ });
+
+ var game_n = game_name;
+ this.__defineGetter__("users", function(){
+ return GameServerI.users(game_n);
+ });
+}
diff --git a/games/tic-tac-toe-js/js/GameServer.js b/games/tic-tac-toe-js/js/GameServer.js
new file mode 100644
index 0000000..dc752b8
--- /dev/null
+++ b/games/tic-tac-toe-js/js/GameServer.js
@@ -0,0 +1,183 @@
+// This is just a simulator of a game server to find
+// out which methods we need. This will be rewritten
+// in erlang.
+
+// Game main() function should return a instance of the game
+// Game Methods:
+// userAllowed() op
+// userAdded() op
+// userCommand() m
+
+function GameServer() {
+ this.init();
+}
+GameServer.prototype.init = function() {
+ this.games = {};
+}
+
+GameServer.prototype.addGame = function(game_name, instance) {
+ if (typeof game_name == "string" && game_name != "" && typeof instance == "object") {
+ var aGame = {
+ instance: instance,
+ users: [],
+ world: {},
+ localStorage: {}
+ }
+ this.games[game_name] = aGame;
+ this.games[game_name].users
+ } else throw "GGS: Could not add game " + game_name;
+}
+
+GameServer.prototype.addClient = function(game_name, client) {
+ var game = this.games[game_name];
+ if (typeof game != "undefined") {
+ if (typeof game.instance.userAllowed == "undefined" || typeof game.instance.userAllowed == "function" && game.instance.userAllowed(user)) {
+ var user = new User(game.users.length, client);
+ game.users.push(user);
+ if (typeof game.instance.userAdded == "function") {
+ game.instance.userAdded(user);
+ }
+ } else throw "GGS: Unable to add client to game " + game_name;
+ } else throw "GGS: No such game " + game_name;
+}
+
+GameServer.prototype.users = function(game_name) {
+ var game = this.games[game_name];
+ if (game != "undefined") {
+ return game.users;
+ } else throw "GGS: Unknown game " + game_name;
+}
+
+// Client calls this command, just a convinience method in the simulator
+GameServer.prototype.callCommand = function(game_name, client, command, attrs) {
+ var game = this.games[game_name];
+ if (typeof game != "undefined") {
+ if(typeof game.instance.userCommand == "function") {
+ var user = null;
+ for (var i=0; i < game.users.length; i++) {
+ if (game.users[i].client == client) {
+ user = game.users[i];
+ }
+ }
+ if (user != null) {
+ game.instance.userCommand(user, command, attrs);
+ } else throw "GGS: User not allowed";
+ } else throw "GGS: No such method userCommand() in game " + game_name;
+ } else throw "GGS: No such game " + game_name;
+}
+
+GameServer.prototype.set = function(game_name, type, key, value) {
+ var game = this.games[game_name];
+ if (game != "undefined") {
+ if (type == "world" || type == "localStorage") {
+ if (typeof key == "string" && (typeof value == "string" || typeof value == "number")) {
+ game[type][key] = value;
+ if (type == "world") {
+ var args = {};
+ args[key] = JSON.parse(value);
+ for (var i=0; i < game.users.length; i++) {
+ game.users[i].sendCommand("world_set", JSON.stringify(args));
+ }
+ }
+ } else throw "GGS: Key has to be a string and value string or number";
+ } else throw "GGS: Unknown type " + type;
+ } else throw "GGS: No such game" + game_name;
+}
+
+GameServer.prototype.get = function(game_name, type, key) {
+ var game = this.games[game_name];
+ if (game != "undefined") {
+ return game[type][key];
+ } else throw "GGS: No such game" + game_name;
+}
+
+GameServer.prototype.key = function(game_name, type, position) {
+ var game = this.games[game_name];
+ if (game != "undefined") {
+ var i = 0;
+ for (var key in game[type]) {
+ if(i++ == position) {
+ return key;
+ }
+ }
+ return null;
+ } else throw "GGS: No such game" + game_name;
+}
+
+GameServer.prototype.length = function(game_name, type) {
+ var game = this.games[game_name];
+ if (game != "undefined") {
+ var l = 0;
+ for (var i in game[type]) {
+ l++;
+ }
+ return l;
+ } else throw "GGS: No such game" + game_name;
+}
+
+GameServer.prototype.remove = function(game_name, type) {
+ var game = this.games[game_name];
+ if (game != "undefined") {
+ delete game[key];
+ } else throw "GGS: Unknown game " + game_name
+}
+
+GameServer.prototype.clear = function(game_name, type) {
+ var game = this.games[game_name];
+ if (game != "undefined") {
+ game = {};
+ } else throw "GGS: Unknown game " + game_name
+}
+
+var GameServerI = new GameServer();
+
+
+
+
+// User object
+// to talk to the client it should have implemented
+// the method commandCalled
+function User(id, client) {
+ var id = id;
+ var client = client;
+
+ return {
+ id: id,
+ client: client,
+ sendCommand: function(command, args) {
+ client.commandCalled(command, args);
+ }
+ }
+}
+
+
+function Storage(game_name, type) {
+ if (type == "world" || type == "localStorage") {
+ this.type = type;
+ this.gameName = game_name;
+ var self = this;
+
+ return {
+ setItem: function(key, value) {
+ GameServerI.set(self.gameName, self.type, key, value);
+ },
+ getItem: function(key) {
+ return GameServerI.get(self.gameName, self.type, key);
+ },
+ key: function(position) {
+ return GameServerI.key(self.gameName, self.type, position);
+ },
+ length: {
+ get: function() {
+ return GameServerI.length(self.gameName, self.type);
+ }
+ },
+ removeItem: function(key) {
+ GameServerI.remove(self.gameName, self.type, key);
+ },
+ clear: function() {
+ GameServerI.clear(self.gameName, self.type);
+ }
+ }
+ } else throw "GGS: No such storage available " + type;
+}
diff --git a/games/tic-tac-toe-js/js/TicTacToe.js b/games/tic-tac-toe-js/js/TicTacToe.js
new file mode 100644
index 0000000..2d47974
--- /dev/null
+++ b/games/tic-tac-toe-js/js/TicTacToe.js
@@ -0,0 +1,139 @@
+function TicTacToe() {};
+TicTacToe.prototype.init = function() {
+
+}
+
+TicTacToe.prototype.userAllowed = function(user) {
+ if(GGS.users.length <= 2) return true
+ else return false;
+}
+
+TicTacToe.prototype.userAdded = function(user) {
+ GGS.localStorage.setItem("p" + GGS.users.length + "_id", user.id);
+
+ if (GGS.users.length == 2) {
+ GGS.world.setItem("game_board", JSON.stringify(this.newGameBoard(3)));
+ GGS.localStorage.setItem("next_player", 1);
+ this.getUser(GGS.localStorage.getItem("p1_id")).sendCommand("yourturn");
+ }
+}
+
+TicTacToe.prototype.getUser = function(user_id) {
+ for (var i=0; i < GGS.users.length; i++) {
+ if(GGS.users[i].id == user_id) {
+ return GGS.users[i];
+ }
+ }
+}
+
+TicTacToe.prototype.newGameBoard = function(rows) {
+ // Initiate game with empty rows and columns
+ var gameBoard = [];
+ for (var i=0; i < rows; i++) {
+ gameBoard[i] = [];
+ for (var j=0; j < rows; j++) {
+ gameBoard[i][j] = 0;
+ }
+ }
+ return gameBoard;
+}
+
+TicTacToe.prototype.userCommand = function(user, command, args) {
+ var nextPlayer = GGS.localStorage.getItem("next_player");
+ var p1_id = GGS.localStorage.getItem("p1_id");
+ var p2_id = GGS.localStorage.getItem("p2_id");
+ var valid = false;
+
+ if(nextPlayer == 1 && user.id == p1_id) {
+ valid = true;
+ } else if (nextPlayer == 2 && user.id == p2_id) {
+ valid = true;
+ }
+
+ if (valid) {
+ if (command == "set") {
+
+ var p = nextPlayer;
+ var props = JSON.parse(args);
+ var gameBoard = JSON.parse(GGS.world.getItem("game_board"));
+
+ if (gameBoard[props.x][props.y] == 0) {
+ gameBoard[props.x][props.y] = p;
+ GGS.world.setItem("game_board", JSON.stringify(gameBoard))
+ if (this.checkIfWon(p, gameBoard)) {
+ if (p == 1) {
+ this.getUser(p1_id).sendCommand("winner", "You win!");
+ this.getUser(p2_id).sendCommand("loser", "You lose!");
+ } else {
+ this.getUser(p1_id).sendCommand("loser", "You lose!");
+ this.getUser(p2_id).sendCommand("winner", "You win!");
+ }
+ }
+
+ if (nextPlayer == 1) {
+ GGS.localStorage.setItem("next_player", 2);
+ this.getUser(p1_id).sendCommand("yourturn");
+ } else {
+ GGS.localStorage.setItem("next_player", 1);
+ this.getUser(p2_id).sendCommand("yourturn");
+ }
+
+ } else {
+ user.sendCommand("warning", "Already set, chose something else.");
+ }
+ } else throw "TTTS: Unknown command " + command;
+ } else {
+ user.sendCommand("warning", "Not your turn!");
+ }
+}
+
+TicTacToe.prototype.checkIfWon = function(player, gameBoard) {
+
+ var rows = gameBoard.length;
+
+ for (i = 0; i < rows; ++i) {
+ for (j = 0; j < rows; ++j) {
+ if (gameBoard[i][j] != player) {
+ break;
+ }
+ }
+ if (j == rows) {
+ return true;
+ }
+
+ for (j = 0; j < rows; ++j) {
+ if (gameBoard[j][i] != player) {
+ break;
+ }
+ }
+ if (j == rows) {
+ return true;
+ }
+ }
+
+ // Now check diagnols
+ for (i = 0; i < rows; ++i) {
+ if (gameBoard[i][i] != player) {
+ break;
+ }
+ }
+
+ if (i == rows) {
+ return true;
+ }
+
+ for (i = 0; i < rows; ++i) {
+ if (gameBoard[i][rows - i - 1] != player) {
+ break;
+ }
+ }
+ if (i == rows) {
+ return true;
+ }
+
+ return false;
+}
+
+function main() {
+ return new TicTacToe();
+}
\ No newline at end of file
diff --git a/games/tic-tac-toe-js/js/TicTacToeClient.js b/games/tic-tac-toe-js/js/TicTacToeClient.js
new file mode 100644
index 0000000..444f921
--- /dev/null
+++ b/games/tic-tac-toe-js/js/TicTacToeClient.js
@@ -0,0 +1,92 @@
+// This first version doesn't take networking into account yet.
+
+function TicTacToeClient(container, server) {
+ this.server = server;
+ this.container = container;
+ this.init();
+}
+
+
+TicTacToeClient.prototype.init = function() {
+ this.rows = 3;
+ this.spots = [];
+ this.myturn = false;
+
+ var table = document.createElement("table");
+ var tr = document.createElement("tr");
+ var td = document.createElement("td");
+
+ var k = 0;
+
+ for(var i=0; i < this.rows; i++) {
+ var atr = tr.cloneNode(true);
+
+ for(var j=0; j < this.rows; j++) {
+
+ var atd = td.cloneNode(true);
+ atd.id = + k++;
+ this.spots.push(atd);
+
+ var self = this;
+ atd.onclick = function(e) {
+ self.move(e.target.id);
+ }
+ atr.appendChild(atd);
+ }
+ table.appendChild(atr);
+ }
+
+ this.container.innerHTML = "";
+ this.container.appendChild(table)
+ this.messages = document.createElement("ol");
+ this.container.appendChild(this.messages);
+}
+
+TicTacToeClient.prototype.move = function(id) {
+ var args = {
+ x: parseInt(id / this.rows),
+ y: parseInt(id) % this.rows
+ }
+ this.server.callCommand("tictactoe", this, "set", JSON.stringify(args));
+}
+
+TicTacToeClient.prototype.commandCalled = function(command, args) {
+ if (command == "world_set") {
+ var pars = JSON.parse(args);
+ if (pars["game_board"]) {
+ this.updateBoard(pars["game_board"]);
+ }
+ } else if (command == "yourturn") {
+ this.myturn = true;
+ } else if (command == "warning") {
+ this.addMessage(args);
+ } else if (command == "loser") {
+ this.addMessage(args);
+ } else if (command == "winner") {
+ this.addMessage(args);
+ } else throw "TTTC: Unnown command " + command;
+}
+
+TicTacToeClient.prototype.addMessage = function(args) {
+ var message = document.createElement("li");
+ message.innerHTML = args;
+ this.messages.appendChild(message)
+}
+
+TicTacToeClient.prototype.updateBoard = function(gameBoardData) {
+ var k = 0;
+ for(var i=0; i
+
+
+ Tic Tac Toe - Player 1
+
+
+
+ Tic Tac Toe and GGS simulation.
+
+ Player 1
+
+
+
\ No newline at end of file
diff --git a/games/tic-tac-toe-js/window2.html b/games/tic-tac-toe-js/window2.html
new file mode 100644
index 0000000..754fec1
--- /dev/null
+++ b/games/tic-tac-toe-js/window2.html
@@ -0,0 +1,13 @@
+
+
+
+ Tic Tac Toe - Player 2
+
+
+
+ Tic Tac Toe and GGS simulation.
+
+ Player 2
+
+
+
\ No newline at end of file