Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: entombedvirus/dots_and_lines
base: 6961eb7e7f
...
head fork: entombedvirus/dots_and_lines
compare: 11ad53d0ee
  • 5 commits
  • 8 files changed
  • 0 commit comments
  • 1 contributor
View
80 app.js
@@ -0,0 +1,80 @@
+(function() {
+ var DEFAULT_BOARD_SIZE, DEFAULT_PORT, ServerGame, all_games, app, createNewGame, everyone, express, fs, nowjs, onClientDisconnected, uid2Client;
+ var __slice = Array.prototype.slice;
+ express = require('express');
+ nowjs = require('now');
+ fs = require('fs');
+ ServerGame = require('./models/server_game');
+ app = module.exports = express.createServer();
+ DEFAULT_BOARD_SIZE = 6;
+ DEFAULT_PORT = 3000;
+ all_games = {};
+ uid2Client = {};
+ createNewGame = function(gameId) {
+ var room;
+ room = nowjs.getGroup(gameId);
+ return new ServerGame({
+ id: gameId,
+ size: DEFAULT_BOARD_SIZE,
+ clients: room
+ });
+ };
+ app.configure(function() {
+ app.set('views', __dirname + '/views');
+ app.set('view engine', 'jade');
+ app.use(express.bodyParser());
+ app.use(express.methodOverride());
+ app.use(app.router);
+ app.use(express.static(__dirname + '/public'));
+ return app.use(require('browserify')({
+ base: __dirname + '/models',
+ mount: '/browserify.js'
+ }));
+ });
+ app.get('/games', function(req, res) {
+ res.local('all_games', all_games);
+ return res.render('games/index');
+ });
+ app.get('/g/:game_id', function(req, res) {
+ var gid;
+ gid = req.params.game_id;
+ all_games[gid] || (all_games[gid] = createNewGame(gid));
+ res.local('game_id', gid);
+ res.local('game', all_games[gid]);
+ return res.render('games/show');
+ });
+ if (!module.parent) {
+ app.listen(DEFAULT_PORT);
+ console.log("Express server listening on port %d", app.address().port);
+ onClientDisconnected = function() {
+ var gameId, room;
+ gameId = this.now.gameId;
+ room = nowjs.getGroup(gameId);
+ room.removeUser(this.user.clientId);
+ if (this.now.uid != null) {
+ return delete uid2Client[this.now.uid];
+ }
+ };
+ everyone = nowjs.initialize(app);
+ everyone.now.startGame = function(gameId, uid) {
+ var oldClient, room, serialized;
+ if (oldClient = uid2Client[uid]) {
+ onClientDisconnected.call(oldClient);
+ oldClient.now.handleServerEvent('gtfo', ['Duplicate Connection']);
+ }
+ uid2Client[uid] = this;
+ room = nowjs.getGroup(gameId);
+ room.addUser(this.user.clientId);
+ serialized = all_games[gameId].forClient();
+ serialized['clientId'] = this.user.clientId;
+ return this.now.initializeClientGame(serialized);
+ };
+ everyone.disconnected(onClientDisconnected);
+ everyone.now.handleClientEvent = function() {
+ var game, gameId, _ref;
+ gameId = this.now.gameId;
+ game = all_games[gameId];
+ return (_ref = ServerGame.prototype.handleClientEvent).call.apply(_ref, [game, this].concat(__slice.call(arguments)));
+ };
+ }
+}).call(this);
View
129 models/base_game.js
@@ -0,0 +1,129 @@
+(function() {
+ var BaseGame, StateMachine;
+ var __indexOf = Array.prototype.indexOf || function(item) {
+ for (var i = 0, l = this.length; i < l; i++) {
+ if (this[i] === item) return i;
+ }
+ return -1;
+ };
+ StateMachine = require('./state_machine');
+ module.exports = BaseGame = (function() {
+ function BaseGame() {}
+ BaseGame.prototype.resetBoard = function() {
+ this.totalMoves = 0;
+ this.alpha = 2 * this.size - 1;
+ this.num_edges = 2 * this.size * (this.size - 1);
+ this.board = new Array(this.num_edges);
+ this.completedSquares = {};
+ this.players = new StateMachine;
+ return this.scoreCard = {};
+ };
+ BaseGame.prototype.addPlayer = function(clientId, uid) {
+ var _base, _ref;
+ (_ref = (_base = this.scoreCard)[uid]) != null ? _ref : _base[uid] = 0;
+ return this.players.addState(uid);
+ };
+ BaseGame.prototype.removePlayer = function(uid) {
+ return this.players.removeState(uid);
+ };
+ BaseGame.prototype.isVerticalEdge = function(edgeNum) {
+ return (edgeNum % this.alpha) >= Math.floor(this.alpha / 2);
+ };
+ BaseGame.prototype.isOnPerimeter = function(direction, edgeNum) {
+ var _i, _j, _ref, _ref2, _ref3, _results, _results2;
+ switch (direction) {
+ case 'left':
+ return edgeNum % this.alpha === this.size - 1;
+ case 'right':
+ return edgeNum % this.alpha === this.alpha - 1;
+ case 'top':
+ return __indexOf.call((function() {
+ _results = [];
+ for (var _i = 0, _ref = this.size; 0 <= _ref ? _i < _ref : _i > _ref; 0 <= _ref ? _i += 1 : _i -= 1){ _results.push(_i); }
+ return _results;
+ }).apply(this, arguments), edgeNum) >= 0;
+ case 'bottom':
+ return __indexOf.call((function() {
+ _results2 = [];
+ for (var _j = _ref2 = this.num_edges - this.size + 1, _ref3 = this.num_edges; _ref2 <= _ref3 ? _j <= _ref3 : _j >= _ref3; _ref2 <= _ref3 ? _j += 1 : _j -= 1){ _results2.push(_j); }
+ return _results2;
+ }).apply(this, arguments), edgeNum) >= 0;
+ }
+ };
+ BaseGame.prototype.fillEdge = function(edgeNum) {
+ var bottom, left, pointScored, right, top;
+ if (!((0 <= edgeNum && edgeNum < this.num_edges))) {
+ throw "Edge " + edgeNum + " is out of bounds. total: " + this.num_edges;
+ }
+ left = right = top = bottom = false;
+ this.totalMoves++;
+ this.board[edgeNum] = true;
+ if (this.isVerticalEdge(edgeNum)) {
+ if (!this.isOnPerimeter('left', edgeNum)) {
+ left = this.checkSquare('left', edgeNum);
+ }
+ if (!this.isOnPerimeter('right', edgeNum)) {
+ right = this.checkSquare('right', edgeNum);
+ }
+ } else {
+ if (!this.isOnPerimeter('top', edgeNum)) {
+ top = this.checkSquare('top', edgeNum);
+ }
+ if (!this.isOnPerimeter('bottom', edgeNum)) {
+ bottom = this.checkSquare('bottom', edgeNum);
+ }
+ }
+ pointScored = left || right || top || bottom;
+ if (!pointScored) {
+ this.players.nextState();
+ }
+ return pointScored;
+ };
+ BaseGame.prototype.checkSquare = function(direction, edgeNum) {
+ var coordinates, edge, _i, _len;
+ coordinates = (function() {
+ switch (direction) {
+ case 'left':
+ return [edgeNum - 1, edgeNum - this.size, edgeNum + (this.size - 1)];
+ case 'right':
+ return [edgeNum + 1, edgeNum + this.size, edgeNum - (this.size - 1)];
+ case 'top':
+ return [edgeNum - this.alpha, edgeNum - this.size, edgeNum - (this.size - 1)];
+ case 'bottom':
+ return [edgeNum + this.alpha, edgeNum + this.size, edgeNum + (this.size - 1)];
+ }
+ }).call(this);
+ for (_i = 0, _len = coordinates.length; _i < _len; _i++) {
+ edge = coordinates[_i];
+ if (!((0 <= edge && edge < this.num_edges))) {
+ continue;
+ }
+ if (this.board[edge] == null) {
+ return false;
+ }
+ }
+ this.addCompletedSquare(direction, edgeNum);
+ return true;
+ };
+ BaseGame.prototype.addCompletedSquare = function(direction, edgeNum) {
+ var topEdge, uid, _base, _ref;
+ topEdge = (function() {
+ switch (direction) {
+ case 'left':
+ return edgeNum - this.size;
+ case 'right':
+ return edgeNum - this.size + 1;
+ case 'top':
+ return edgeNum - this.alpha;
+ case 'bottom':
+ return edgeNum;
+ }
+ }).call(this);
+ uid = this.players.getCurrentState();
+ this.scoreCard[uid] += 1;
+ ((_ref = (_base = this.completedSquares)[uid]) != null ? _ref : _base[uid] = []).push(topEdge);
+ return topEdge;
+ };
+ return BaseGame;
+ })();
+}).call(this);
View
105 models/client_game.js
@@ -0,0 +1,105 @@
+(function() {
+ var BaseGame, ClientGame, StateMachine, UI;
+ var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) {
+ for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
+ function ctor() { this.constructor = child; }
+ ctor.prototype = parent.prototype;
+ child.prototype = new ctor;
+ child.__super__ = parent.prototype;
+ return child;
+ }, __indexOf = Array.prototype.indexOf || function(item) {
+ for (var i = 0, l = this.length; i < l; i++) {
+ if (this[i] === item) return i;
+ }
+ return -1;
+ }, __slice = Array.prototype.slice;
+ BaseGame = require('./base_game');
+ StateMachine = require('./state_machine');
+ UI = require('./ui').getInstance();
+ module.exports = ClientGame = (function() {
+ __extends(ClientGame, BaseGame);
+ function ClientGame(options) {
+ this.refreshPlayerUI = __bind(this.refreshPlayerUI, this);; var attr, _i, _len, _ref;
+ this.container = options.container;
+ this.gameUrl = window.location.href;
+ _ref = ['size', 'alpha', 'num_edges', 'board', 'totalMoves', 'scoreCard', 'clientId', 'completedSquares'];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ attr = _ref[_i];
+ this[attr] = options[attr];
+ }
+ this.setupPlayerStateMachine(options.players);
+ }
+ ClientGame.prototype.setupPlayerStateMachine = function(serverStateMachine) {
+ this.players = $.extend(new StateMachine, serverStateMachine);
+ this.players.on('stateAdded', this.refreshPlayerUI);
+ this.players.on('stateRemoved', this.refreshPlayerUI);
+ return this.players.on('stateChanged', this.refreshPlayerUI);
+ };
+ ClientGame.prototype.refreshPlayerUI = function() {
+ return $(document).ready(__bind(function() {
+ var li, players, score, txt, uid, _ref;
+ players = this.container.find('.players').empty();
+ _ref = this.scoreCard;
+ for (uid in _ref) {
+ score = _ref[uid];
+ txt = "<fb:profile-pic uid='" + uid + "'></fb:profile-pic>";
+ txt += "<span>" + score + "</span>";
+ li = $("<li/>").html(txt);
+ if (__indexOf.call(this.players.states, uid) < 0) {
+ li.addClass('offline').attr('title', 'offline');
+ }
+ if (this.players.getCurrentState() === uid) {
+ li.addClass('currentTurn').attr('title', 'Current Turn');
+ }
+ players.append(li);
+ }
+ return FB.XFBML.parse(this.container.get(0));
+ }, this));
+ };
+ ClientGame.prototype.emit = function() {
+ var data, eventName;
+ eventName = arguments[0], data = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
+ return window.now.handleClientEvent(eventName, data);
+ };
+ ClientGame.prototype.handleServerEvent = function(eventName, data) {
+ var clientId, edgeNum, msg, uid, _ref;
+ console.log("server said", eventName, data);
+ switch (eventName) {
+ case 'needMorePlayers':
+ return UI.showMessage('You\'re the only one connected\nto this game right now. Invite someone to play\nwith you by sending them a link to this page.');
+ case 'notYourTurn':
+ return UI.showMessage('It\'s not your turn...');
+ case 'playerJoined':
+ clientId = data[0];
+ uid = data[1];
+ return this.addPlayer(clientId, uid);
+ case 'playerLeft':
+ uid = data[0];
+ return this.removePlayer(uid);
+ case 'fillEdge':
+ edgeNum = data[0];
+ return this.fillEdge(edgeNum);
+ case 'completeSquare':
+ return this.refreshPlayerUI();
+ case 'gtfo':
+ msg = data[0];
+ UI.showMessage("Server kicked you. Reason: " + msg, true);
+ return (_ref = window.socket) != null ? _ref.disconnect() : void 0;
+ }
+ };
+ ClientGame.prototype.render = function() {
+ $.get("/game.pde", __bind(function(res) {
+ var jsCode;
+ jsCode = Processing.compile(res);
+ return new Processing(this.container.find("canvas").get(0), jsCode);
+ }, this));
+ return this.renderPlayerUI();
+ };
+ ClientGame.prototype.renderPlayerUI = function() {
+ var list;
+ list = $("<ul class='players'></ul>");
+ return list.appendTo(this.container);
+ };
+ return ClientGame;
+ })();
+}).call(this);
View
89 models/server_game.js
@@ -0,0 +1,89 @@
+(function() {
+ var BaseGame, ServerGame;
+ var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) {
+ for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
+ function ctor() { this.constructor = child; }
+ ctor.prototype = parent.prototype;
+ child.prototype = new ctor;
+ child.__super__ = parent.prototype;
+ return child;
+ }, __slice = Array.prototype.slice;
+ BaseGame = require('./base_game');
+ module.exports = ServerGame = (function() {
+ __extends(ServerGame, BaseGame);
+ function ServerGame(options) {
+ this.id = options.id;
+ this.size = options.size;
+ this.clients = options.clients;
+ this.attachListeners();
+ this.resetBoard();
+ }
+ ServerGame.prototype.attachListeners = function() {
+ var game;
+ game = this;
+ this.clients.on('connect', function() {
+ var client, clientId;
+ client = this;
+ clientId = client.user.clientId;
+ return client.now.getSession(function(session) {
+ if (session == null) {
+ return;
+ }
+ game.addPlayer(clientId, session.uid);
+ return game.emit('playerJoined', clientId, session.uid);
+ });
+ });
+ return this.clients.on('disconnect', function() {
+ game.removePlayer(this.now.uid);
+ return game.emit('playerLeft', this.now.uid);
+ });
+ };
+ ServerGame.prototype.emit = function() {
+ var data, eventName;
+ eventName = arguments[0], data = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
+ return this.clients.now.handleServerEvent(eventName, data);
+ };
+ ServerGame.prototype.handleClientEvent = function(client, eventName, data) {
+ var edgeNum;
+ switch (eventName) {
+ case 'fillEdge':
+ if (this.players.states.length < 2) {
+ client.now.handleServerEvent('needMorePlayers');
+ return false;
+ }
+ if (this.players.getCurrentState() === client.now.uid) {
+ edgeNum = data[0];
+ return this.fillEdge(edgeNum);
+ } else {
+ return client.now.handleServerEvent('notYourTurn');
+ }
+ }
+ };
+ ServerGame.prototype.fillEdge = function(edgeNum) {
+ this.emit('fillEdge', edgeNum);
+ return ServerGame.__super__.fillEdge.apply(this, arguments);
+ };
+ ServerGame.prototype.checkSquare = function(direction, edgeNum) {
+ var squareCompleted;
+ squareCompleted = ServerGame.__super__.checkSquare.apply(this, arguments);
+ if (squareCompleted === false) {
+ return false;
+ }
+ this.emit('completeSquare');
+ return true;
+ };
+ ServerGame.prototype.forClient = function() {
+ return {
+ size: this.size,
+ alpha: this.alpha,
+ num_edges: this.num_edges,
+ board: this.board,
+ completedSquares: this.completedSquares,
+ players: this.players,
+ scoreCard: this.scoreCard,
+ totalMoves: this.totalMoves
+ };
+ };
+ return ServerGame;
+ })();
+}).call(this);
View
42 models/state_machine.js
@@ -0,0 +1,42 @@
+(function() {
+ var EventEmitter, StateMachine;
+ var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) {
+ for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
+ function ctor() { this.constructor = child; }
+ ctor.prototype = parent.prototype;
+ child.prototype = new ctor;
+ child.__super__ = parent.prototype;
+ return child;
+ };
+ EventEmitter = require('events').EventEmitter;
+ module.exports = StateMachine = (function() {
+ __extends(StateMachine, EventEmitter);
+ function StateMachine() {
+ this.states = new Array;
+ this.counter = 0;
+ }
+ StateMachine.prototype.addState = function(newState) {
+ this.states.push(newState);
+ this.emit('stateAdded', newState);
+ return this;
+ };
+ StateMachine.prototype.removeState = function(aState) {
+ this.states = this.states.filter(function(currentState) {
+ return currentState !== aState;
+ });
+ this.emit('stateRemoved', aState);
+ return this;
+ };
+ StateMachine.prototype.nextState = function() {
+ this.counter++;
+ this.emit('stateChanged');
+ return this;
+ };
+ StateMachine.prototype.getCurrentState = function() {
+ var idx;
+ idx = this.counter % this.states.length;
+ return this.states[idx];
+ };
+ return StateMachine;
+ })();
+}).call(this);
View
39 models/ui.js
@@ -0,0 +1,39 @@
+(function() {
+ var UI, instance;
+ var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
+ UI = (function() {
+ function UI() {
+ this.hideMessage = __bind(this.hideMessage, this);; $(document).ready(__bind(function() {
+ this.container = $("<div id='notifications'><p></p></div>");
+ this.container.prependTo($('body'));
+ return this.container.click(this.hideMessage);
+ }, this));
+ }
+ UI.prototype.showMessage = function(msg, sticky) {
+ if (sticky == null) {
+ sticky = false;
+ }
+ this.container.find('p:first').text(msg);
+ this.container.fadeIn('fast');
+ if (!sticky) {
+ return this.restartHideTimer();
+ }
+ };
+ UI.prototype.hideMessage = function() {
+ return this.container.fadeOut('slow');
+ };
+ UI.prototype.restartHideTimer = function() {
+ if (this.timer != null) {
+ clearTimeout(this.timer);
+ }
+ return this.timer = setTimeout(this.hideMessage, 3000);
+ };
+ return UI;
+ })();
+ instance = null;
+ module.exports = {
+ getInstance: function() {
+ return instance || (instance = new UI);
+ }
+ };
+}).call(this);
View
23 package.json
@@ -0,0 +1,23 @@
+{
+ "name": "dots_and_line",
+ "description": "An implementation of the classic game Dots & Lines",
+ "version": "0.0.0",
+ "homepage": "https://github.com/entombedvirus/dots_and_lines",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/entombedvirus/dots_and_lines.git"
+ },
+ "author": "Rohith Ravi <entombedvirus@gmail.com> (https://github.com/entombedvirus)",
+ "directories": {
+ "lib": "."
+ },
+ "engines": {
+ "node": "*"
+ },
+ "dependencies": {
+ "express": "2.2.2",
+ "now": "0.5.3",
+ "browserify": "0.3.1",
+ "jade": "0.10.4"
+ }
+}
View
1  server.js

No commit comments for this range

Something went wrong with that request. Please try again.