Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Refactor struct, cli

  • Loading branch information...
commit bf50a84baad17bd97bb3256dbc14e22c7b5e9196 1 parent 49a3c53
Anatoliy Chakkaev authored
View
4 app.js
@@ -16,7 +16,7 @@ var session_key = 'connect.sidw';
app.configure(function(){
app.use(express.staticProvider(__dirname + '/public'));
- app.set('views', __dirname + '/views');
+ app.set('views', __dirname + '/app/views');
app.use(express.cookieDecoder());
app.use(express.session({ store: store, key: session_key }));
app.use(facebooker.connect);
@@ -36,7 +36,7 @@ app.configure('production', function(){
// Controller
-var c = require('./lib/controller.js');
+var c = require('./app/controller.js');
// Routes
View
15 lib/controller.js → app/controller.js
@@ -1,4 +1,4 @@
-var m = require('./models.js');
+var m = require('../lib/models.js');
module.exports = {
loadUser: function (req, res, next) {
@@ -27,12 +27,13 @@ module.exports = {
},
index: function (req, res) {
console.log(req.just_connected ? 'just connected' : 'not just connected');
- res.render('index.jade', { locals: {
- title: 'Reversi game',
- player: req.player,
- user: req.session.fb.user,
- opponent: {id: 1, name: 'name'},
- secret: req.cookies['connect.sidw']
+ res.render('index.jade', { locals:
+ { title: 'Reversi game'
+ , player: req.player
+ , user: req.session.fb.user
+ , opponent: req.player.game.cached_opponent
+ , starter: req.player.game.cached_starter
+ , secret: req.cookies['connect.sidw']
}
});
},
View
137 app/models/game.js
@@ -0,0 +1,137 @@
+/**
+ * Class Game
+ **/
+function Game() { };
+
+Game.attributes =
+{ type: 'string'
+, color: 'string'
+, position: 'string'
+, starter: 'player'
+, cached_starter: 'json'
+, opponent: 'player'
+, cached_opponent: 'json'
+};
+
+/**
+ * Static class methods
+ **/
+
+Game.find_free_or_create = function (params, callback) {
+
+ function create_game() {
+ exports.Game.create(params, function () {
+ callback.apply(this);
+ });
+ }
+
+ this.connection.rpop('wait:' + params.type, function (err, value) {
+ if (value) {
+ exports.Game.find(value, function (err) {
+ if (err) {
+ create_game();
+ } else {
+ callback.apply(this);
+ }
+ });
+ } else {
+ create_game();
+ }
+ });
+};
+
+/**
+ * Instance methods
+ **/
+Game.prototype = {
+ initialize: function () {
+ if (this.type) {
+ var game = require('../../lib/games/' + this.type);
+ if (!this.color) {
+ this.color = 'b';
+ }
+ this.game = new game.createGame(this);
+ }
+ },
+ join: function (player, callback) {
+ var self = this;
+ if (this.starter) {
+ console.log('Клиент ' + player.id + ' присоединяется к игре вторым');
+ self.set_opponent(player, function () {
+ player.update_attribute('color', 'w', callback);
+ console.log('Уведомляем ожидающего клиента ' + self.starter + ' что началась игра: ');
+ self.connection.publish('player:' + self.starter + ':channel',
+ JSON.stringify({
+ action: 'opponent_connected',
+ user: this.cached_opponent
+ })
+ );
+ });
+ } else {
+ // push game to waiting queue
+ self.connection.lpush('wait:' + this.type, this.id);
+ self.set_starter(player, function () {
+ player.update_attribute('color', 'b', callback);
+ });
+ }
+ },
+ set_starter: function (player, callback) {
+ this.generic_user_setter('starter', player, callback);
+ },
+ set_opponent: function (player, callback) {
+ this.generic_user_setter('opponent', player, callback);
+ },
+ generic_user_setter: function (role, player, callback) {
+ var self = this;
+ self.update_attribute(role, player.id, function () {
+ player.get('user', function (user) {
+ self.update_attribute('cached_' + role, user.public_params(), function () {
+ callback.call(self);
+ });
+ });
+ });
+ },
+ state: function (player) {
+ if (!this.opponent) return 'wait_opponent';
+ if (this.game.board.terminal_board) return 'end_game';
+ if (this.color == player.color) {
+ return 'move';
+ } else {
+ return 'wait';
+ }
+ },
+ boardToJSON: function () {
+ return JSON.stringify(this.game.board.position);
+ },
+ move: function (player, coords, callback) {
+ var game = this;
+ var pwned = game.game.pwned_by();
+ if (this.game.move(coords)) {
+ this.position = this.boardToJSON();
+ this.color = this.game.pwned_by();
+ this.save(function () {
+ game.connection.publish('player:' +
+ (
+ pwned != player.color ?
+ player.id :
+ (
+ player.id == game.opponent ?
+ game.starter :
+ game.opponent
+ )
+ ) + ':channel', JSON.stringify({
+ action: 'move',
+ coords: coords
+ })
+ );
+ if (game.game.board.terminal_board) {
+ var response = JSON.stringify({action: 'end', info: game.game.board.board_stats});
+ game.connection.publish('player:' + this.opponent + ':channel', response);
+ game.connection.publish('player:' + this.starter + ':channel', response);
+ }
+ });
+ }
+ }
+};
+
+exports.Game = Game;
View
67 app/models/player.js
@@ -0,0 +1,67 @@
+function Player() {
+};
+Player.attributes = {
+ game_id: 'int',
+ color: 'string',
+ user: 'user'
+};
+
+Player.prototype = {
+ connect: function (socket) {
+ var player = this;
+ player.pubsub_client = exports.Player.redis.createClient();
+ player.channel = 'player:' + player.id + ':channel';
+ console.log('client #', player.id, 'subscribed to channel', this.channel);
+ player.pubsub_client.subscribeTo(player.channel, function (channel, message) {
+ console.log('publish to channel', player.channel, 'detected by subscriber', player.id);
+ socket.send(message.toString());
+ });
+ },
+ disconnect: function () {
+ console.log('free channel', this.channel);
+ this.pubsub_client.unsubscribeFrom(this.channel);
+ console.log('close connection to database');
+ this.pubsub_client.close();
+ },
+ perform: function (message) {
+ console.log('player', this.id, 'perform');
+ var player = this;
+ switch (message.action) {
+ case 'move':
+ this.game.reload(function () {
+ this.move(player, message.coords);
+ });
+ break;
+ default:
+ console.log(message);
+ break;
+ }
+ },
+ loadGame: function loadGame(type, callback) {
+ var user = this;
+ if (this.game_id) {
+ exports.Game.find(this.game_id, function () {
+ user.game = this;
+ if (this.game.board.terminal_board) {
+ user.update_attribute('game_id', 0, function () {
+ user.loadGame(type, callback);
+ });
+ } else {
+ callback();
+ }
+ });
+ } else {
+ exports.Game.find_free_or_create({type: type}, function () {
+ user.join(this, callback);
+ });
+ }
+ },
+ join: function (game, callback) {
+ this.update_attribute('game_id', game.id, function () {
+ this.game = game;
+ game.join(this, callback);
+ });
+ }
+};
+
+exports.Player = Player;
View
16 app/models/user.js
@@ -0,0 +1,16 @@
+function User() {
+
+};
+
+User.attributes = {
+ info: 'json'
+};
+
+User.prototype.public_params = function () {
+ return {
+ id: this.id,
+ name: this.info.name
+ };
+};
+
+exports.User = User;
View
32 app/views/index.jade
@@ -0,0 +1,32 @@
+:javascript
+ | var BOARD = {
+ | player: '#{player.color}',
+ | color: '#{player.game.color || 'b'}',
+ | state: '#{player.game.state(player)}',
+ | position: #{player.game.boardToJSON()},
+ | secret: '#{secret}'
+ | };
+
+//script( src: 'http://cdn.socket.io/stable/socket.io.js' )
+script( src: 'socket.io.js' )
+script( src: 'jquery.js?' + (new Date).getTime())
+script( src: 'reversi.js?' + (new Date).getTime())
+script( src: 'reversi-cli.js?' + (new Date).getTime())
+
+#starter.user_bar( style: starter ? '' : 'display:none' )
+ .avatar
+ img( src: 'https://graph.facebook.com/' + starter.id + '/picture?type=large')
+ small.username
+ #{starter.name}
+ .color.black black
+
+#board
+ .info
+ canvas( width: '300', height: '300' )
+
+#opponent_info.user_bar( style: opponent ? '' : 'display:none' )
+ .avatar
+ img( src: 'https://graph.facebook.com/' + (opponent ? opponent.id : 1) + '/picture?type=large')
+ small.username
+ #{opponent ? opponent.name : ''}
+ .color.white white
View
0  views/layout.jade → app/views/layout.jade
File renamed without changes
View
1  lib/facebooker.js
@@ -1,4 +1,3 @@
-console.log(exports);
var m = require('./models.js');
function top_redirect_to(url, res) {
View
187 lib/models.js
@@ -1,183 +1,18 @@
-exports.User = function () { };
-exports.User.attributes = {
- info: 'json'
-};
+var fs = require('fs');
-exports.Player = function () { };
-exports.Player.attributes = {
- game_id: 'int',
- color: 'string',
- user: 'user'
-};
+var exps = {};
-exports.Player.prototype = {
- connect: function (socket) {
- var player = this;
- player.pubsub_client = exports.Player.redis.createClient();
- player.channel = 'player:' + player.id + ':channel';
- console.log('client #', player.id, 'subscribed to channel', this.channel);
- player.pubsub_client.subscribeTo(player.channel, function (channel, message) {
- console.log('publish to channel', player.channel, 'detected by subscriber', player.id);
- socket.send(message.toString());
- });
- },
- disconnect: function () {
- console.log('free channel', this.channel);
- this.pubsub_client.unsubscribeFrom(this.channel);
- console.log('close connection to database');
- this.pubsub_client.close();
- },
- perform: function (message) {
- console.log('player', this.id, 'perform');
- var player = this;
- switch (message.action) {
- case 'move':
- this.game.reload(function () {
- this.move(player, message.coords);
- });
- break;
- default:
- console.log(message);
- break;
- }
- },
- loadGame: function loadGame(type, callback) {
- var user = this;
- if (this.game_id) {
- exports.Game.find(this.game_id, function () {
- user.game = this;
- if (this.game.board.terminal_board) {
- user.update_attribute('game_id', 0, function () {
- user.loadGame(type, callback);
- });
- } else {
- callback();
- }
- });
- } else {
- exports.Game.find_free_or_create({type: type}, function () {
- user.join(this, callback);
- });
- }
- },
- join: function (game, callback) {
- this.update_attribute('game_id', game.id, function () {
- this.game = game;
- game.join(this, callback);
- });
+fs.readdirSync('./app/models/').forEach(function (f) {
+ exps[f] = require('../app/models/' + f);
+ for (var i in exps[f]) {
+ exports[i] = exps[f][i];
}
-};
+});
-exports.User = function () { };
-exports.User.attributes = {
- info: 'json'
-};
-
-exports.Game = function () { };
-exports.Game.attributes = {
- type: 'string',
- color: 'string',
- position: 'string',
- starter: 'int',
- opponent: 'int'
-};
-exports.Game.find_free_or_create = function (params, callback) {
-
- function create_game() {
- exports.Game.create(params, function () {
- callback.apply(this);
- });
- }
-
- this.connection.rpop('wait:' + params.type, function (err, value) {
- if (value) {
- exports.Game.find(value, function (err) {
- if (err) {
- create_game();
- } else {
- callback.apply(this);
- }
- });
- } else {
- create_game();
- }
- });
-};
-exports.Game.prototype = {
- initialize: function () {
- if (this.type) {
- var game = require('./games/' + this.type);
- if (!this.color) {
- this.color = 'b';
- }
- this.game = new game.createGame(this);
- }
- },
- join: function (player, callback) {
- var self = this;
- if (this.starter) {
- console.log('Клиент ' + player.id + ' присоединяется к игре вторым');
- this.update_attribute('opponent', player.id, function () {
- player.get('user', function (user) {
- console.log('Уведомляем ожидающего клиента ' + self.starter + ' что началась игра: ');
- self.connection.publish('player:' + self.starter + ':channel',
- JSON.stringify({
- action: 'opponent_connected',
- user: user.to_hash ? user.to_hash() : user
- })
- );
- });
- player.update_attribute('color', 'w', callback);
- });
- } else {
- // push game to waiting queue
- this.connection.lpush('wait:' + this.type, this.id);
- this.update_attribute('starter', player.id, function () {
- player.update_attribute('color', 'b', callback);
- });
- }
- },
- state: function (player) {
- if (!this.opponent) return 'wait_opponent';
- if (this.game.board.terminal_board) return 'end_game';
- if (this.color == player.color) {
- return 'move';
- } else {
- return 'wait';
- }
- },
- boardToJSON: function () {
- return JSON.stringify(this.game.board.position);
- },
- move: function (player, coords, callback) {
- var game = this;
- var pwned = game.game.pwned_by();
- if (this.game.move(coords)) {
- this.position = this.boardToJSON();
- this.color = this.game.pwned_by();
- this.save(function () {
- game.connection.publish('player:' +
- (
- pwned != player.color ?
- player.id :
- (
- player.id == game.opponent ?
- game.starter :
- game.opponent
- )
- ) + ':channel', JSON.stringify({
- action: 'move',
- coords: coords
- })
- );
- if (game.game.board.terminal_board) {
- var response = JSON.stringify({action: 'end', info: game.game.board.board_stats});
- game.connection.publish('player:' + this.opponent + ':channel', response);
- game.connection.publish('player:' + this.starter + ':channel', response);
- }
- });
- }
+for (var e in exps) {
+ for (var c in exports) {
+ exps[e][c] = exports[c];
}
-};
+}
require('../vendor/orm/lib/orm.js').mix_persistence_methods(exports);
View
24 public/reversi-cli.js
@@ -3,7 +3,7 @@ $.fn.reversi = function (player, current_color, board, drawer) {
};
$(function () {
var undef;
- var cell_size = 60;
+ var cell_size = 40;
var padding = 10;
var board_size = cell_size * 8 + padding * 2;
var board = $('#board canvas')[0];
@@ -191,12 +191,16 @@ $(function () {
s[res.player == 'w' ? 'B' : 'W'] = s['0'];
game = $('#board').reversi(res.player, res.color == 'b', res.position, update_board);
game.join();
+ var no_socket = false;
game.after_move = function (coords) {
if (!game.pwned_by(res.player)) {
info.html('Opponent\'s turn.');
+ } else {
+ info.html('Your turn.');
+ }
+ if (!no_socket) {
+ SOCKET.send({action: "move", coords: coords});
}
- console.log('send to socket: move,', coords);
- SOCKET.send({action: "move", coords: coords});
};
var SOCKET = new io.Socket(document.location.hostname);
SOCKET.connect();
@@ -216,23 +220,21 @@ $(function () {
SOCKET.on('message', function (msg) {
if (typeof msg == 'string') {
- console.log(msg);
msg = JSON.parse(msg);
}
switch (msg.action) {
case 'opponent_connected':
+ game.join();
info.html('Opponent joined. You can move.');
var $opp = $('#opponent_info');
- console.log($opp);
- $opp.find('.avatar img').attr('src', 'http://graph.facebook.com/' + msg.user.info.id + '/picture');
- $opp.find('.username').html(msg.user.info.name);
- game.join();
+ $opp.find('.avatar img').attr('src', 'http://graph.facebook.com/' + msg.user.id + '/picture');
+ $opp.find('.username').html(msg.user.name);
break;
case 'move':
- console.log('move to', msg.coords);
- info.html('Your turn.');
game.join();
- game.move(msg.coords, true);
+ no_socket = true;
+ game.move(msg.coords);
+ no_socket = false;
break;
case 'end':
info.html('End game. You ' + (
View
11 public/stylesheets/style.css
@@ -2,3 +2,14 @@ body {
padding: 50px;
font: 14px "Lucida Grande", "Helvetica Nueue", Arial, sans-serif;
}
+
+.user_bar {
+ width: 120px;
+ float: left;
+}
+.user_bar .avatar {
+ padding: 10px;
+}
+#board {
+ float: left;
+}
2  vendor/orm
@@ -1 +1 @@
-Subproject commit 35ea08b591d672a6a24c8ac26df59d9d493e252e
+Subproject commit cc001e25cd513c7905337a5f76666fffc788e58c
View
30 views/index.jade
@@ -1,30 +0,0 @@
-:javascript
- | var BOARD = {
- | player: '#{player.color}',
- | color: '#{player.game.color || 'b'}',
- | state: '#{player.game.state(player)}',
- | position: #{player.game.boardToJSON()},
- | secret: '#{secret}'
- | };
-
-//script( src: 'http://cdn.socket.io/stable/socket.io.js' )
-script( src: 'socket.io.js' )
-script( src: 'jquery.js' )
-script( src: 'reversi.js' )
-script( src: 'reversi-cli.js' )
-
-.user_bar
- .avatar
- img( src: 'https://graph.facebook.com/' + user.id + '/picture')
- small.username
- #{user.name}
-
-#board
- .info
- canvas( width: '300', height: '300' )
-
-#opponent_info.user_bar
- .avatar
- img( src: 'https://graph.facebook.com/' + opponent.id + '/picture')
- small.username
- #{opponent.name}
Please sign in to comment.
Something went wrong with that request. Please try again.