working GGS simulator in JS
This commit is contained in:
parent
a275990f62
commit
20a07dbd6a
8 changed files with 483 additions and 5 deletions
|
@ -1,5 +1,6 @@
|
|||
body {
|
||||
text-align: center;
|
||||
font-family: "Lucida Grande", Tahoma, Helvetica, Verdana, sans-serif;
|
||||
}
|
||||
|
||||
table {
|
||||
|
|
|
@ -2,11 +2,32 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Tic Tac Toe</title>
|
||||
<script src="js/game.js"></script>
|
||||
<script src="js/GameServer.js"></script>
|
||||
<script src="js/GGS.js"></script>
|
||||
<script src="js/TicTacToe.js"></script>
|
||||
<script src="js/TicTacToeClient.js"></script>
|
||||
<script>
|
||||
var game_name ="tictactoe"
|
||||
var GGS = new GGSI(game_name);
|
||||
|
||||
function init() {
|
||||
GameServerI.addGame(game_name, main());
|
||||
GameServerI.addClient(game_name, new TicTacToeClient(frames.player1.document.getElementById("p1"), GameServerI));
|
||||
GameServerI.addClient(game_name, new TicTacToeClient(frames.player2.document.getElementById("p2"), GameServerI));
|
||||
}
|
||||
</script>
|
||||
<link rel="stylesheet" href="css/screen.css" type="text/css" media="screen">
|
||||
</head>
|
||||
<body onload="new TicTacToe('game')">
|
||||
<div id="game"></div>
|
||||
<p><a href="#" onclick="new TicTacToe('game'); return false;">New game</a></p>
|
||||
</body>
|
||||
<frameset cols="50%,50%" onload="init()">
|
||||
|
||||
<frame src="window1.html" name="player1">
|
||||
<frame src="window2.html" name="player2">
|
||||
|
||||
<noframes>
|
||||
<body>
|
||||
<h1>Tic Tac Toe for Generic Game Server</h1>
|
||||
<p>This simulator only works with frames.</p>
|
||||
</body>
|
||||
</noframes>
|
||||
</frameset>
|
||||
</html>
|
16
games/tic-tac-toe-js/js/GGS.js
Normal file
16
games/tic-tac-toe-js/js/GGS.js
Normal file
|
@ -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);
|
||||
});
|
||||
}
|
183
games/tic-tac-toe-js/js/GameServer.js
Normal file
183
games/tic-tac-toe-js/js/GameServer.js
Normal file
|
@ -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;
|
||||
}
|
139
games/tic-tac-toe-js/js/TicTacToe.js
Normal file
139
games/tic-tac-toe-js/js/TicTacToe.js
Normal file
|
@ -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();
|
||||
}
|
92
games/tic-tac-toe-js/js/TicTacToeClient.js
Normal file
92
games/tic-tac-toe-js/js/TicTacToeClient.js
Normal file
|
@ -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<gameBoardData.length; i++) {
|
||||
var row = gameBoardData[i];
|
||||
for (var j=0; j<row.length; j++) {
|
||||
|
||||
var t = "";
|
||||
if (row[j] == 1) {
|
||||
t = "X";
|
||||
} if (row[j] == 2) {
|
||||
t = "O";
|
||||
}
|
||||
|
||||
this.spots[k++].innerHTML = t;
|
||||
}
|
||||
}
|
||||
}
|
13
games/tic-tac-toe-js/window1.html
Normal file
13
games/tic-tac-toe-js/window1.html
Normal file
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Tic Tac Toe - Player 1</title>
|
||||
<link rel="stylesheet" href="css/screen.css" type="text/css" media="screen">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Tic Tac Toe and GGS simulation.</h1>
|
||||
<hr>
|
||||
<h2>Player 1</h2>
|
||||
<div id="p1"></div>
|
||||
</body>
|
||||
</html>
|
13
games/tic-tac-toe-js/window2.html
Normal file
13
games/tic-tac-toe-js/window2.html
Normal file
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Tic Tac Toe - Player 2</title>
|
||||
<link rel="stylesheet" href="css/screen.css" type="text/css" media="screen">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Tic Tac Toe and GGS simulation.</h1>
|
||||
<hr>
|
||||
<h2>Player 2</h2>
|
||||
<div id="p2"></div>
|
||||
</body>
|
||||
</html>
|
Reference in a new issue