Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Support variable width and height

commit 13fdae7696c5d9a24b4aa45f8bb0ddee456aca92 1 parent 8f6e199
Rudy Jahchan rudyjahchan authored
Showing with 296 additions and 166 deletions.
  1. +1 −0  .gitignore
  2. +10 −5 Gruntfile.js
  3. +2 −0  lib/client/buffer.js
  4. +15 −8 lib/client/index.js
  5. +6 −0 lib/client/screen.js
  6. +2 −0  lib/client/views/cycle_view.js
  7. +2 −0  lib/client/views/game_list_view.js
  8. +13 −10 lib/client/views/game_view.js
  9. +2 −0  lib/client/views/player_colors.js
  10. +2 −0  lib/client/views/wall_view.js
  11. +2 −0  lib/define_property.js
  12. +6 −4 lib/models/cycle.js
  13. +2 −0  lib/models/directions.js
  14. +41 −26 lib/models/game.js
  15. +2 −0  lib/models/player_attributes.js
  16. +2 −0  lib/models/wall.js
  17. +2 −0  lib/server/client_game_socket.js
  18. +12 −0 lib/server/client_socket.js
  19. +2 −0  lib/server/index.js
  20. +28 −18 lib/vimtronner.js
  21. +15 −6 src/client/index.coffee
  22. +3 −0  src/client/screen.coffee
  23. +11 −10 src/client/views/game_view.coffee
  24. +4 −4 src/models/cycle.coffee
  25. +24 −40 src/models/game.coffee
  26. +5 −0 src/server/client_socket.coffee
  27. +23 −12 src/vimtronner.coffee
  28. +23 −4 test/client_test.coffee
  29. +10 −8 test/models/cycle_test.coffee
  30. +22 −9 test/models/game_test.coffee
  31. +1 −1  test/server/client_socket_test.coffee
  32. +1 −1  test/server_test.coffee
1  .gitignore
View
@@ -10,6 +10,7 @@ lib-cov
pids
logs
results
+maps
npm-debug.log
15 Gruntfile.js
View
@@ -7,13 +7,18 @@ module.exports = function(grunt) {
mochaTest: {
test: {
options: {
- mocha: require('mocha')
+ mocha: require('mocha'),
+ require: 'test/common'
},
- src: ['test/**/*.coffee']
+ src: ['test/**/*_test.coffee']
}
},
coffee: {
compile: {
+ options: {
+ sourceMap: true,
+ sourceMapDir: 'maps/'
+ },
expand: true,
cwd: 'src/',
src: ['**/*.coffee'],
@@ -24,14 +29,14 @@ module.exports = function(grunt) {
watch: {
tests: {
files: ['test/**/*_test.coffee'],
- tasks: ['mochaTest']
+ tasks: ['build']
},
src: {
files: ['src/**/*.coffee'],
- tasks: ['mochaTest', 'coffee']
+ tasks: ['build']
}
}
});
- grunt.registerTask('build', ['mochaTest','coffee']);
+ grunt.registerTask('build', ['coffee', 'mochaTest']);
grunt.registerTask('default', ['mochaTest']);
};
2  lib/client/buffer.js
View
@@ -13,3 +13,5 @@
module.exports = buffer;
}).call(this);
+
+//# sourceMappingURL=../../maps/buffer.js.map
23 lib/client/index.js
View
@@ -12,7 +12,6 @@
Client = (function() {
function Client(address, port) {
- var gameView;
this.address = address != null ? address : "127.0.0.1";
this.port = port != null ? port : 8000;
this.storeCycle = __bind(this.storeCycle, this);
@@ -23,22 +22,28 @@
this.onSigInt = __bind(this.onSigInt, this);
this.onData = __bind(this.onData, this);
this.andJoinGame = __bind(this.andJoinGame, this);
- this.gameView = gameView = new GameView;
}
Client.prototype.join = function(gameAttributes) {
+ var gameView;
this.gameAttributes = gameAttributes;
- this.clearScreen();
+ this.gameAttributes.width = screen.columns;
+ this.gameAttributes.height = screen.rows - 2;
+ this.checkValidity();
+ this.gameView = gameView = new GameView;
return this.connect(this.andJoinGame);
};
- Client.prototype.listGames = function() {
- return this.connect(this.andListGames);
+ Client.prototype.checkValidity = function() {
+ var invalid;
+ invalid = this.gameAttributes.width < 22 || this.gameAttributes.height < 22 || this.gameAttributes.width > screen.columns || this.gameAttributes.height > screen.rows - 2;
+ if (invalid) {
+ throw new Error("Width and height but be no smaller than 22 and no bigger than screen size");
+ }
};
- Client.prototype.clearScreen = function() {
- screen.clear();
- return screen.hideCursor();
+ Client.prototype.listGames = function() {
+ return this.connect(this.andListGames);
};
Client.prototype.connect = function(callback) {
@@ -115,3 +120,5 @@
module.exports = Client;
}).call(this);
+
+//# sourceMappingURL=../../maps/index.js.map
6 lib/client/screen.js
View
@@ -78,6 +78,10 @@
return process.stdout.write('\x1b[39;49m');
};
+ module.exports.resetAll = function() {
+ return process.stdout.write('\x1b[0m');
+ };
+
module.exports.render = function(buffer) {
return process.stdout.write(buffer);
};
@@ -167,3 +171,5 @@
});
}).call(this);
+
+//# sourceMappingURL=../../maps/screen.js.map
2  lib/client/views/cycle_view.js
View
@@ -133,3 +133,5 @@
module.exports = CycleView;
}).call(this);
+
+//# sourceMappingURL=../../../maps/cycle_view.js.map
2  lib/client/views/game_list_view.js
View
@@ -62,3 +62,5 @@
module.exports = GameListView;
}).call(this);
+
+//# sourceMappingURL=../../../maps/game_list_view.js.map
23 lib/client/views/game_view.js
View
@@ -84,13 +84,13 @@
GameView.property('startX', {
get: function() {
- return Math.round(screen.center.x - (this._game.gridSize / 2));
+ return Math.round(screen.center.x - (this._game.width / 2));
}
});
GameView.property('startY', {
get: function() {
- return Math.round(screen.center.y - 2 - (this._game.gridSize / 2));
+ return Math.round(screen.center.y - 2 - (this._game.height / 2));
}
});
@@ -110,6 +110,7 @@
GameView.prototype.render = function() {
screen.clear();
+ screen.hideCursor();
screen.save();
screen.transform(this.startX, this.startY);
if (this.state === Game.STATES.WAITING) {
@@ -127,10 +128,10 @@
GameView.prototype.renderArena = function() {
var endX, endY, x, xRange, y, yRange, _i, _j, _k, _l, _results;
screen.setForegroundColor(3);
- xRange = this.game.gridSize - 1;
- yRange = this.game.gridSize - 1;
- endX = this.game.gridSize;
- endY = this.game.gridSize;
+ xRange = this.game.width - 1;
+ yRange = this.game.height - 1;
+ endX = this.game.width;
+ endY = this.game.height;
screen.moveTo(1, 1);
screen.render(ARENA_WALL_CHARS.TOP_LEFT_CORNER);
for (x = _i = 2; 2 <= xRange ? _i <= xRange : _i >= xRange; x = 2 <= xRange ? ++_i : --_i) {
@@ -163,8 +164,8 @@
var centerX, i, instructions, y, _i, _ref;
this.renderArena();
instructions = ['left............h', 'down............j', 'up..............k', 'right...........l', 'insert mode.....i', 'normal mode...esc'];
- centerX = Math.round(this.game.gridSize / 2);
- y = Math.round(this.game.gridSize / 2) - 4;
+ centerX = Math.round(this.game.width / 2);
+ y = Math.round(this.game.height / 2) - 4;
screen.setForegroundColor(6);
screen.print('vimTronner', centerX, y, screen.TEXT_ALIGN.CENTER);
y += 2;
@@ -187,8 +188,8 @@
GameView.prototype.renderCount = function() {
var countX;
screen.setForegroundColor(3);
- countX = Math.round(this.game.gridSize / 2);
- return screen.print(this.countString, countX, Math.round(this.game.gridSize / 2), screen.TEXT_ALIGN.CENTER);
+ countX = Math.round(this.game.width / 2);
+ return screen.print(this.countString, countX, Math.round(this.game.height / 2), screen.TEXT_ALIGN.CENTER);
};
GameView.prototype.renderCycleViews = function() {
@@ -250,3 +251,5 @@
module.exports = GameView;
}).call(this);
+
+//# sourceMappingURL=../../../maps/game_view.js.map
2  lib/client/views/player_colors.js
View
@@ -17,3 +17,5 @@
};
}).call(this);
+
+//# sourceMappingURL=../../../maps/player_colors.js.map
2  lib/client/views/wall_view.js
View
@@ -44,3 +44,5 @@
module.exports = WallView;
}).call(this);
+
+//# sourceMappingURL=../../../maps/wall_view.js.map
2  lib/define_property.js
View
@@ -4,3 +4,5 @@
};
}).call(this);
+
+//# sourceMappingURL=../maps/define_property.js.map
10 lib/models/cycle.js
View
@@ -148,7 +148,7 @@
}
break;
case directions.DOWN:
- if (this.y !== (this.game.gridSize - 1)) {
+ if (this.y !== (this.game.height - 1)) {
return this.y += 1;
}
break;
@@ -158,7 +158,7 @@
}
break;
case directions.RIGHT:
- if (this.x !== (this.game.gridSize - 1)) {
+ if (this.x !== (this.game.width - 1)) {
return this.x += 1;
}
}
@@ -172,8 +172,8 @@
Cycle.prototype.checkCollisions = function(cycles) {
var bottomWallY, cycle, rightWallX, wall, _i, _j, _len, _len1, _ref;
if (this.state === CYCLE_STATES.RACING || this.state === CYCLE_STATES.INSERTING) {
- bottomWallY = this.game.gridSize - 1;
- rightWallX = this.game.gridSize - 1;
+ bottomWallY = this.game.height - 1;
+ rightWallX = this.game.width - 1;
if (this.y <= 0 || this.x <= 0 || this.y >= bottomWallY || this.x >= rightWallX) {
this.triggerCollision();
return;
@@ -267,3 +267,5 @@
module.exports = Cycle;
}).call(this);
+
+//# sourceMappingURL=../../maps/cycle.js.map
2  lib/models/directions.js
View
@@ -7,3 +7,5 @@
};
}).call(this);
+
+//# sourceMappingURL=../../maps/directions.js.map
67 lib/models/game.js
View
@@ -28,11 +28,11 @@
this.countdown = __bind(this.countdown, this);
this.runGame = __bind(this.runGame, this);
this.loop = __bind(this.loop, this);
- var _ref, _ref1;
+ var _ref, _ref1, _ref2;
this.name = attributes.name;
this.numberOfPlayers = (_ref = attributes.numberOfPlayers) != null ? _ref : 2;
- this.gridSize = (_ref1 = attributes.gridSize) != null ? _ref1 : 22;
- this.playerPositions = this.calculatePlayerPositions();
+ this.width = (_ref1 = attributes.width) != null ? _ref1 : 80;
+ this.height = (_ref2 = attributes.height) != null ? _ref2 : 22;
this.cycles = [];
this.state = Game.STATES.WAITING;
this._count = 3000;
@@ -44,8 +44,6 @@
return null;
}
attributes = playerAttributes[this.cycles.length];
- attributes['x'] = this.playerPositions[this.cycles.length]['x'];
- attributes['y'] = this.playerPositions[this.cycles.length]['y'];
attributes['game'] = this;
cycle = new Cycle(attributes);
this.cycles.push(cycle);
@@ -84,7 +82,18 @@
};
Game.prototype.start = function() {
+ var cycle, i, _fn, _i, _len, _ref;
this.state = Game.STATES.COUNTDOWN;
+ this.playerPositions = this.calculatePlayerPositions();
+ _ref = this.cycles;
+ _fn = function(cycle, i) {};
+ for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
+ cycle = _ref[i];
+ _fn(cycle, i);
+ cycle.x = this.playerPositions[i]['x'];
+ cycle.y = this.playerPositions[i]['y'];
+ }
+ this.loop();
return this.gameLoop = setInterval(this.loop, 100);
};
@@ -158,35 +167,38 @@
});
Game.prototype.calculatePlayerPositions = function() {
- var halfDistance, maxDistance, minDistance;
- minDistance = 3;
- maxDistance = this.gridSize - minDistance;
- halfDistance = Math.round(this.gridSize / 2);
+ var halfXDistance, halfYDistance, maxXDistance, maxYDistance, minXDistance, minYDistance;
+ minXDistance = 3;
+ maxXDistance = this.width - minXDistance;
+ halfXDistance = Math.round(this.width / 2);
+ minYDistance = 3;
+ maxYDistance = this.height - minXDistance;
+ halfYDistance = Math.round(this.height / 2);
return [
{
- x: minDistance,
- y: minDistance
+ x: minXDistance,
+ y: minYDistance
}, {
- x: maxDistance,
- y: maxDistance
+ x: maxXDistance,
+ y: maxYDistance
}, {
- x: minDistance,
- y: maxDistance
+ x: minXDistance,
+ y: maxYDistance
}, {
- x: maxDistance,
- y: minDistance
+ x: maxXDistance,
+ y: minYDistance
}, {
- x: halfDistance,
- y: minDistance
+ x: halfXDistance,
+ y: minYDistance
}, {
- x: halfDistance,
- y: maxDistance
+ x: halfXDistance,
+ y: maxYDistance
}, {
- x: minDistance,
- y: halfDistance
+ x: minXDistance,
+ y: halfYDistance
}, {
- x: maxDistance,
- y: halfDistance
+ x: maxXDistance,
+ y: halfYDistance
}
];
};
@@ -198,7 +210,8 @@
state: this.state,
count: this.count,
numberOfPlayers: this.numberOfPlayers,
- gridSize: this.gridSize,
+ width: this.width,
+ height: this.height,
cycles: (function() {
var _i, _len, _ref, _results;
_ref = this.cycles;
@@ -219,3 +232,5 @@
module.exports = Game;
}).call(this);
+
+//# sourceMappingURL=../../maps/game.js.map
2  lib/models/player_attributes.js
View
@@ -48,3 +48,5 @@
];
}).call(this);
+
+//# sourceMappingURL=../../maps/player_attributes.js.map
2  lib/models/wall.js
View
@@ -38,3 +38,5 @@
module.exports = Wall;
}).call(this);
+
+//# sourceMappingURL=../../maps/wall.js.map
2  lib/server/client_game_socket.js
View
@@ -32,3 +32,5 @@
module.exports = ClientGameSocket;
}).call(this);
+
+//# sourceMappingURL=../../maps/client_game_socket.js.map
12 lib/server/client_socket.js
View
@@ -27,6 +27,7 @@
}
game = this.server.getGame(gameAttributes);
if (game != null) {
+ this.adjustGameSize(game, gameAttributes);
if ((cycle = game.addCycle()) != null) {
this.gameSocketFactory(this.socket, game, cycle);
return callback(null, cycle.number, game.toJSON());
@@ -46,6 +47,15 @@
return this.socket.emit('games', this.server.gameList());
};
+ ClientSocket.prototype.adjustGameSize = function(game, gameAttributes) {
+ if (game.width > gameAttributes.width) {
+ game.width = gameAttributes.width;
+ }
+ if (game.height > gameAttributes.height) {
+ return game.height = gameAttributes.height;
+ }
+ };
+
return ClientSocket;
})();
@@ -53,3 +63,5 @@
module.exports = ClientSocket;
}).call(this);
+
+//# sourceMappingURL=../../maps/client_socket.js.map
2  lib/server/index.js
View
@@ -100,3 +100,5 @@
module.exports = Server;
}).call(this);
+
+//# sourceMappingURL=../../maps/index.js.map
46 lib/vimtronner.js
View
@@ -10,26 +10,36 @@
Client = require('./client');
exports = module.exports = function(argv) {
- var client, number, server, size;
- program.version(JSON.parse(fs.readFileSync(__dirname + '/../package.json', 'utf8')).version).option('-S, --server', 'launches a server').option('-C, --client', 'launches a client').option('-A, --address <address>', 'the address to connect the client', '127.0.0.1').option('-P, --port <port>', 'the port to launch the server or connect the client', 8000).option('-G, --game <game>', 'the game the client wants to join').option('-N, --number <number of players>', 'the number of players required to play (applies to new game only)').option('-Z, --size <size of grid>', 'the size of the game grid (applies to new game only)').parse(argv);
- if (program.server) {
- server = new Server;
- server.listen(program.port);
- }
- if (program.client) {
- client = new Client(program.address, program.port);
- if (program.game != null) {
- number = parseInt(program.number, 10);
- size = parseInt(program.size, 10);
- return client.join({
- name: program.game,
- numberOfPlayers: number,
- gridSize: size
- });
- } else {
- return client.listGames();
+ var client, e, height, number, server, width;
+ program.version(JSON.parse(fs.readFileSync(__dirname + '/../package.json', 'utf8')).version).option('-S, --server', 'launches a server').option('-C, --client', 'launches a client').option('-A, --address <address>', 'the address to connect the client', '127.0.0.1').option('-P, --port <port>', 'the port to launch the server or connect the client', 8000).option('-G, --game <game>', 'the game the client wants to join').option('-N, --number <number of players>', 'the number of players required to play (applies to new game only)').option('-W, --width <size>', 'the grid width').option('-H, --height <size>', 'the grid height').parse(argv);
+ try {
+ if (program.server) {
+ server = new Server;
+ server.listen(program.port);
+ }
+ if (program.client) {
+ client = new Client(program.address, program.port);
+ if (program.game != null) {
+ number = parseInt(program.number, 10);
+ width = parseInt(program.width);
+ height = parseInt(program.height);
+ return client.join({
+ name: program.game,
+ numberOfPlayers: number,
+ width: width,
+ height: height
+ });
+ } else {
+ return client.listGames();
+ }
}
+ } catch (_error) {
+ e = _error;
+ console.log(e.message);
+ return process.exit(1);
}
};
}).call(this);
+
+//# sourceMappingURL=../maps/vimtronner.js.map
21 src/client/index.coffee
View
@@ -5,19 +5,28 @@ GameListView = require './views/game_list_view'
class Client
constructor: (@address="127.0.0.1", @port=8000)->
- @gameView = gameView = new GameView
join: (@gameAttributes)->
- @clearScreen()
+ @gameAttributes.width = screen.columns
+ @gameAttributes.height = screen.rows - 2
+ @checkValidity()
+ @gameView = gameView = new GameView
@connect(@andJoinGame)
+ checkValidity: ->
+ invalid = (
+ @gameAttributes.width < 22 or
+ @gameAttributes.height < 22 or
+ @gameAttributes.width > screen.columns or
+ @gameAttributes.height > screen.rows - 2
+ )
+ (throw new Error(
+ "Width and height but be no smaller than 22 and no bigger than screen size"
+ )) if invalid
+
listGames: ->
@connect(@andListGames)
- clearScreen: ->
- screen.clear()
- screen.hideCursor()
-
connect: (callback)->
@socket = socketio.connect("http://#{@address}:#{@port}")
@socket.on 'connect', callback
3  src/client/screen.coffee
View
@@ -48,6 +48,9 @@ module.exports.moveTo = (x, y) ->
module.exports.resetColors = ->
process.stdout.write '\x1b[39;49m'
+module.exports.resetAll = ->
+ process.stdout.write '\x1b[0m'
+
module.exports.render = (buffer)->
process.stdout.write buffer
21 src/client/views/game_view.coffee
View
@@ -52,9 +52,9 @@ class GameView
when Game.STATES.STARTED then 'Go'
when Game.STATES.FINISHED then 'Game over'
@property 'startX', get: ->
- Math.round(screen.center.x - (@_game.gridSize/2))
+ Math.round(screen.center.x - (@_game.width/2))
@property 'startY', get: ->
- Math.round(screen.center.y - 2 - (@_game.gridSize/2))
+ Math.round(screen.center.y - 2 - (@_game.height/2))
generateCycleViews: ->
@@ -62,6 +62,7 @@ class GameView
render: ->
screen.clear()
+ screen.hideCursor()
screen.save()
screen.transform(@startX, @startY)
if @state == Game.STATES.WAITING
@@ -76,10 +77,10 @@ class GameView
renderArena: ->
screen.setForegroundColor 3
- xRange = @game.gridSize - 1
- yRange = @game.gridSize - 1
- endX = @game.gridSize
- endY = @game.gridSize
+ xRange = @game.width - 1
+ yRange = @game.height - 1
+ endX = @game.width
+ endY = @game.height
screen.moveTo(1,1)
screen.render ARENA_WALL_CHARS.TOP_LEFT_CORNER
for x in [2..xRange]
@@ -111,8 +112,8 @@ class GameView
'insert mode.....i'
'normal mode...esc'
]
- centerX = Math.round(@game.gridSize/2)
- y = Math.round(@game.gridSize/2) - 4
+ centerX = Math.round(@game.width/2)
+ y = Math.round(@game.height/2) - 4
screen.setForegroundColor 6
screen.print('vimTronner', centerX, y, screen.TEXT_ALIGN.CENTER)
y += 2
@@ -130,8 +131,8 @@ class GameView
renderCount: ->
screen.setForegroundColor 3
- countX = Math.round(@game.gridSize/2)
- screen.print @countString, countX, Math.round(@game.gridSize/2), screen.TEXT_ALIGN.CENTER
+ countX = Math.round(@game.width/2)
+ screen.print @countString, countX, Math.round(@game.height/2), screen.TEXT_ALIGN.CENTER
renderCycleViews: ->
cycleView.render() for cycleView in @cycleViews
8 src/models/cycle.coffee
View
@@ -88,19 +88,19 @@ class Cycle
when directions.UP
@y -= 1 unless @y == 0
when directions.DOWN
- @y += 1 unless @y == (@game.gridSize - 1)
+ @y += 1 unless @y == (@game.height - 1)
when directions.LEFT
@x -= 1 unless @x == 0
when directions.RIGHT
- @x += 1 unless @x == (@game.gridSize - 1)
+ @x += 1 unless @x == (@game.width - 1)
checkCollisionWith: (object)->
@x == object.x and @y == object.y
checkCollisions: (cycles)->
if @state == CYCLE_STATES.RACING or @state == CYCLE_STATES.INSERTING
- bottomWallY = (@game.gridSize - 1)
- rightWallX = (@game.gridSize - 1)
+ bottomWallY = (@game.height - 1)
+ rightWallX = (@game.width - 1)
if (@y <= 0 or @x <= 0 or @y >= bottomWallY or @x >= rightWallX)
@triggerCollision()
return
64 src/models/game.coffee
View
@@ -16,8 +16,8 @@ class Game extends EventEmitter
constructor: (attributes)->
@name = attributes.name
@numberOfPlayers = attributes.numberOfPlayers ? 2
- @gridSize = attributes.gridSize ? 22
- @playerPositions = @calculatePlayerPositions()
+ @width = attributes.width ? 80
+ @height = attributes.height ? 22
@cycles = []
@state = Game.STATES.WAITING
@_count = 3000
@@ -26,8 +26,6 @@ class Game extends EventEmitter
return null if @inProgress
attributes = playerAttributes[@cycles.length]
- attributes['x'] = @playerPositions[@cycles.length]['x']
- attributes['y'] = @playerPositions[@cycles.length]['y']
attributes['game'] = @
cycle = new Cycle(attributes)
@@ -54,6 +52,12 @@ class Game extends EventEmitter
start: ->
@state = Game.STATES.COUNTDOWN
+ @playerPositions = @calculatePlayerPositions()
+ for cycle, i in @cycles
+ do (cycle, i)->
+ cycle.x = @playerPositions[i]['x']
+ cycle.y = @playerPositions[i]['y']
+ @loop()
@gameLoop = setInterval @loop, 100
loop: =>
@@ -91,42 +95,21 @@ class Game extends EventEmitter
set: (value)-> @_count = 1000.0 * value
calculatePlayerPositions: ->
- minDistance = 3
- maxDistance = @gridSize - minDistance
- halfDistance = Math.round(@gridSize / 2)
+ minXDistance = 3
+ maxXDistance = @width - minXDistance
+ halfXDistance = Math.round(@width / 2)
+ minYDistance = 3
+ maxYDistance = @height - minXDistance
+ halfYDistance = Math.round(@height / 2)
[
- {
- x: minDistance
- y: minDistance
- }
- {
- x: maxDistance
- y: maxDistance
- }
- {
- x: minDistance
- y: maxDistance
- }
- {
- x: maxDistance
- y: minDistance
- }
- {
- x: halfDistance
- y: minDistance
- }
- {
- x: halfDistance
- y: maxDistance
- }
- {
- x: minDistance
- y: halfDistance
- }
- {
- x: maxDistance
- y: halfDistance
- }
+ { x: minXDistance, y: minYDistance }
+ { x: maxXDistance, y: maxYDistance }
+ { x: minXDistance, y: maxYDistance }
+ { x: maxXDistance, y: minYDistance }
+ { x: halfXDistance, y: minYDistance }
+ { x: halfXDistance, y: maxYDistance }
+ { x: minXDistance, y: halfYDistance }
+ { x: maxXDistance, y: halfYDistance }
]
toJSON: -> {
@@ -134,7 +117,8 @@ class Game extends EventEmitter
state: @state
count: @count,
numberOfPlayers: @numberOfPlayers
- gridSize: @gridSize
+ width: @width
+ height: @height
cycles: (cycle.toJSON() for cycle in @cycles)
}
5 src/server/client_socket.coffee
View
@@ -10,6 +10,7 @@ class ClientSocket
onJoin: (gameAttributes, callback=(error, cycle)->)=>
game = @server.getGame(gameAttributes)
if game?
+ @adjustGameSize game, gameAttributes
if (cycle = game.addCycle())?
@gameSocketFactory(@socket, game, cycle)
callback null, cycle.number, game.toJSON()
@@ -20,4 +21,8 @@ class ClientSocket
onList: => @socket.emit 'games', @server.gameList()
+ adjustGameSize: (game, gameAttributes)->
+ (game.width = gameAttributes.width) if game.width > gameAttributes.width
+ (game.height = gameAttributes.height) if game.height > gameAttributes.height
+
module.exports = ClientSocket
35 src/vimtronner.coffee
View
@@ -12,18 +12,29 @@ exports = module.exports = (argv) ->
.option('-P, --port <port>', 'the port to launch the server or connect the client', 8000)
.option('-G, --game <game>', 'the game the client wants to join')
.option('-N, --number <number of players>', 'the number of players required to play (applies to new game only)')
- .option('-Z, --size <size of grid>', 'the size of the game grid (applies to new game only)')
+ .option('-W, --width <size>', 'the grid width')
+ .option('-H, --height <size>', 'the grid height')
.parse(argv)
- if program.server
- server = new Server
- server.listen(program.port)
+ try
+ if program.server
+ server = new Server
+ server.listen(program.port)
- if program.client
- client = new Client(program.address, program.port)
- if program.game?
- number = parseInt(program.number, 10)
- size = parseInt(program.size, 10)
- client.join({name: program.game, numberOfPlayers: number, gridSize: size})
- else
- client.listGames()
+ if program.client
+ client = new Client(program.address, program.port)
+ if program.game?
+ number = parseInt(program.number, 10)
+ width = parseInt(program.width)
+ height = parseInt(program.height)
+ client.join({
+ name: program.game
+ numberOfPlayers: number
+ width: width
+ height: height
+ })
+ else
+ client.listGames()
+ catch e
+ console.log e.message
+ process.exit 1
27 test/client_test.coffee
View
@@ -1,10 +1,28 @@
Client = require '../src/client'
Cycle = require '../src/models/cycle'
+GameView = require '../src/client/views/game_view'
-describe Client, ->
+describe 'Client', ->
beforeEach ->
@client = new Client
+ describe '#join', ->
+ beforeEach ->
+ sinon.stub(@client, 'connect')
+ @gameAttributes = {}
+ @client.join @gameAttributes
+
+ it 'sets the width and height of the game', ->
+ expect(@client.gameAttributes).to.eq(@gameAttributes)
+ expect(@client.gameAttributes.height).to.eq(process.stdout.rows - 2)
+ expect(@client.gameAttributes.width).to.eq(process.stdout.columns)
+
+ it 'creates a game screen', ->
+ expect(@client.gameView).to.be.instanceOf GameView
+
+ it 'connects and waits to join a game', ->
+ expect(@client.connect).to.have.been.calledWith @client.andJoinGame
+
describe '#storeCycle', ->
context 'given a cycle', ->
beforeEach ->
@@ -17,15 +35,16 @@ describe Client, ->
describe '#andJoinGame', ->
beforeEach ->
@emit = sinon.stub()
+ @client.gameAttributes = { foo: 'bar' }
@on = sinon.stub()
- @client.game = 'aGame'
@client.socket = { @emit, @on }
context 'when joining a game', ->
beforeEach -> @client.andJoinGame()
- it 'requests to join the game', ->
- expect(@emit).to.have.been.calledWith 'join', @client.gameAttributes
+ it 'requests to join the game with the game and terminal attributes', ->
+ expect(@emit).to.have.been.calledWith 'join',
+ @client.gameAttributes
context 'and when there is an error', ->
beforeEach ->
18 test/models/cycle_test.coffee
View
@@ -98,8 +98,9 @@ describe 'Cycle', ->
describe '#step', ->
beforeEach ->
- gridSize = Math.floor(Math.random() * 100) + 20
- @game = new Game({name: 'game', gridSize: gridSize})
+ width = Math.floor(Math.random() * 100) + 80
+ height = Math.floor(Math.random() * 100) + 22
+ @game = new Game({name: 'game', width: width, height: height})
@cycle = new Cycle({direction: directions.RIGHT, game: @game})
context 'given the cycle is exploding', ->
@@ -137,7 +138,7 @@ describe 'Cycle', ->
context 'given the cycle has hit the right wall', ->
beforeEach ->
- @oldX = (@game.gridSize - 1)
+ @oldX = (@game.width - 1)
@cycle.x = @oldX
it 'does not increment the x', ->
@@ -146,7 +147,7 @@ describe 'Cycle', ->
context 'given the cycle has hit the bottom wall', ->
beforeEach ->
- @oldY = (@game.gridSize - 1)
+ @oldY = (@game.height - 1)
@cycle.direction = directions.DOWN
@cycle.y = @oldY
@@ -157,8 +158,9 @@ describe 'Cycle', ->
describe '#checkCollisions', ->
beforeEach ->
- gridSize = Math.floor(Math.random() * 100) + 20
- @game = new Game(name: 'game', gridSize: gridSize)
+ width = Math.floor(Math.random() * 100) + 80
+ height = Math.floor(Math.random() * 100) + 22
+ @game = new Game(name: 'game', width: width, height: height)
@cycle = new Cycle({
direction: directions.RIGHT,
state: Cycle.STATES.RACING,
@@ -168,7 +170,7 @@ describe 'Cycle', ->
context 'given the cycle has hit the right arena wall', ->
beforeEach ->
- @cycle.x = (@game.gridSize - 1)
+ @cycle.x = (@game.width - 1)
@cycle.checkCollisions([])
it 'triggers a collision', ->
@@ -192,7 +194,7 @@ describe 'Cycle', ->
context 'given the cycle has hit the bottom arena wall', ->
beforeEach ->
- @cycle.y = (@game.gridSize - 1)
+ @cycle.y = (@game.height - 1)
@cycle.checkCollisions([])
it 'triggers a collision', ->
31 test/models/game_test.coffee
View
@@ -21,8 +21,11 @@ describe 'Game', ->
it 'allows 2 players', ->
expect(@game.numberOfPlayers).to.eq(2)
- it 'has a grid size of 22', ->
- expect(@game.gridSize).to.eq(22)
+ it 'has a grid width of 80', ->
+ expect(@game.width).to.eq(80)
+
+ it 'has a grid height of 22', ->
+ expect(@game.height).to.eq(22)
context 'given a number of players', ->
beforeEach ->
@@ -33,15 +36,23 @@ describe 'Game', ->
it 'allows that many players', ->
expect(@game.numberOfPlayers).to.eq(@numberOfPlayers)
- context 'given a grid size', ->
+ context 'given a grid width', ->
beforeEach ->
- @gridSize = 75
- attributes = { name: 'new name', gridSize: @gridSize }
+ @width = 75
+ attributes = { name: 'new name', width: @width }
@game = new Game(attributes)
- it 'sets that grid size', ->
- expect(@game.gridSize).to.eq(@gridSize)
+ it 'sets that grid width', ->
+ expect(@game.width).to.eq(@width)
+ context 'given a grid height', ->
+ beforeEach ->
+ @height = 75
+ attributes = { name: 'new name', height: @height }
+ @game = new Game(attributes)
+
+ it 'sets that grid height', ->
+ expect(@game.height).to.eq(@height)
describe '#addCycle', ->
context 'when the game is not waiting for players', ->
@@ -144,7 +155,7 @@ describe 'Game', ->
it 'initiates a game loop to trigger every 100 milliseconds', ->
@clock.tick(301)
- expect(@gameLoop).to.have.been.calledThrice
+ expect(@gameLoop.callCount).to.eq(4)
describe '#loop', ->
beforeEach ->
@@ -264,7 +275,9 @@ describe 'Game', ->
@json = @game.toJSON()
it 'returns the JSON with the game properties', ->
- expect(@json[property]).to.eq(@game[property]) for property in ['name', 'state', 'count', 'numberOfPlayers', 'gridSize']
+ expect(@json[property]).to.eq(@game[property]) for property in [
+ 'name', 'state', 'count', 'numberOfPlayers', 'width', 'height'
+ ]
it 'returns the JSON for each cycle in the game', ->
expect(@json['cycles']).to.have.members (cycle.toJSON() for cycle in @game.cycles)
2  test/server/client_socket_test.coffee
View
@@ -4,7 +4,7 @@ Server = require '../../src/server'
Game = require '../../src/models/game'
Cycle = require '../../src/models/cycle'
-describe ClientSocket, ->
+describe 'ClientSocket', ->
beforeEach ->
@socket = {
on: sinon.stub(), join: sinon.stub(), emit: sinon.stub(), leave: sinon.stub()
2  test/server_test.coffee
View
@@ -4,7 +4,7 @@ Server = require '../src/server'
http = require 'http'
socketio = require('socket.io-client')
-describe Server, ->
+describe 'Server', ->
beforeEach -> @server = new Server
describe '#getGame', ->
Please sign in to comment.
Something went wrong with that request. Please try again.