Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
76ad334
logic coppied over from spike
MSpake Jun 10, 2019
4bef4f5
most of the game logic integrated
MSpake Jun 10, 2019
9c112b1
removal and total working
MSpake Jun 10, 2019
501bb2a
game endsat the same time for both players
MSpake Jun 10, 2019
018b5b1
comments update
MSpake Jun 10, 2019
cf0a33e
Merge pull request #2 from 401-advanced-javascript-nimble/feature/sca…
MSpake Jun 10, 2019
a6d05ba
can handle invalid input (client side)
MSpake Jun 10, 2019
fa4a810
removed test client
MSpake Jun 10, 2019
2e3413c
Merge pull request #4 from 401-advanced-javascript-nimble/feature/sca…
MSpake Jun 10, 2019
8b6ac70
game flow updates
MSpake Jun 11, 2019
98f9f59
messages
MSpake Jun 11, 2019
9f50f6b
messages
MSpake Jun 11, 2019
0d12ff5
ends game when a player disconnects
MSpake Jun 11, 2019
e96b573
reafactored to allow multiple games at once
MSpake Jun 11, 2019
fa4bfe1
mid-game disconnect handled
MSpake Jun 11, 2019
b40122c
Merge pull request #7 from 401-advanced-javascript-nimble/feature/mor…
MSpake Jun 11, 2019
9f25d98
working on countdown timer, need refactor
kozlowskicd Jun 11, 2019
c674709
got countdown timer functional
kozlowskicd Jun 12, 2019
a5c5582
sends a win event
MSpake Jun 12, 2019
c431c5c
sending win to correct person
MSpake Jun 12, 2019
5f680ee
Merge pull request #9 from 401-advanced-javascript-nimble/feature/stats
MSpake Jun 12, 2019
4ac4ced
refactor for new countdown timer
kozlowskicd Jun 12, 2019
5f0381c
Merge branch 'develop' into feature/timer
MSpake Jun 12, 2019
5b4c808
Merge pull request #10 from 401-advanced-javascript-nimble/feature/timer
MSpake Jun 12, 2019
de69fc3
fixed server side timer
MSpake Jun 12, 2019
f9f3591
Merge pull request #11 from 401-advanced-javascript-nimble/feature/fi…
rebecca-pete Jun 12, 2019
97b1688
game class tests
MSpake Jun 12, 2019
bbb9472
mid-way through testing
MSpake Jun 13, 2019
6731cfc
complete refactor, now modular
MSpake Jun 13, 2019
fa3f0f4
Merge pull request #12 from 401-advanced-javascript-nimble/feature/te…
MSpake Jun 13, 2019
33f328f
tests complete
MSpake Jun 13, 2019
3d2d6c3
small change and one more test
MSpake Jun 13, 2019
e9a0003
Merge pull request #13 from 401-advanced-javascript-nimble/feature/te…
MSpake Jun 13, 2019
a2e7659
small bugfix
MSpake Jun 13, 2019
6c05a95
Merge pull request #14 from 401-advanced-javascript-nimble/feature/te…
MSpake Jun 13, 2019
bcf8332
updated readme
rebecca-pete Jun 13, 2019
7343975
updated readme
rebecca-pete Jun 13, 2019
c95c4fc
updated readme
rebecca-pete Jun 13, 2019
1010716
Merge branch 'feature/README-becky' into develop
rebecca-pete Jun 13, 2019
4905ab6
updated readme
rebecca-pete Jun 13, 2019
912c8b0
updated readme
rebecca-pete Jun 13, 2019
2e87d59
Merge pull request #15 from 401-advanced-javascript-nimble/README-bp
rebecca-pete Jun 13, 2019
b86c8da
refactor timer to run independantly client-side
kozlowskicd Jun 13, 2019
b61b6e5
Merge branch 'develop' into feature/newTimer
kozlowskicd Jun 13, 2019
3688721
Merge pull request #16 from 401-advanced-javascript-nimble/feature/ne…
MSpake Jun 14, 2019
8b74474
Update server.js
MSpake Jun 14, 2019
dffebcb
Update you lost message
joejemmely Jun 14, 2019
79b95ec
Merge pull request #17 from 401-advanced-javascript-nimble/develop
MSpake Jun 14, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
**/node_modules/*
**/vendor/*
**/*.min.js
**/coverage/*
**/build/*
25 changes: 25 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"env": {
"browser": true,
"node": true,
"commonjs": true,
"jest": true,
"es6": true
},
"globals": {
"fail":true
},
"extends": "eslint:recommended",
"parserOptions": {
"sourceType": "module",
"ecmaVersion": 2018
},
"rules": {
"no-console": "off",
"indent": [ "error", 2 ],
"quotes": ["error", "single", { "allowTemplateLiterals": true }],
"comma-dangle": ["error", "always-multiline"],
"semi": [ "error", "always" ],
"no-unused-vars": [1, {"vars": "local", "args": "none"}]
}
}
145 changes: 145 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# 401 JS
db
.env
temp
build

# Created by https://www.gitignore.io/api/vim,osx,node,linux,windows
### Linux ###
*~

# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*

# KDE directory preferences
.directory

# Linux trash folder which might appear on any partition or disk
.Trash-*

# .nfs files are created when an open file is removed but is still being accessed
.nfs*

### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Typescript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env


### OSX ###
*.DS_Store
.AppleDouble
.LSOverride

# Icon must end with two \r
Icon

# Thumbnails
._*

# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent

# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

### Vim ###
# swap
[._]*.s[a-v][a-z]
[._]*.sw[a-p]
[._]s[a-v][a-z]
[._]sw[a-p]
# session
Session.vim
# temporary
.netrwhist
# auto-generated tag files
tags

### Windows ###
# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
ehthumbs_vista.db

# Folder config file
Desktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/

# Windows Installer files
*.cab
*.msi
*.msm
*.msp

# Windows shortcuts
*.lnk

# End of https://www.gitignore.io/api/vim,osx,node,linux,windows
74 changes: 73 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,73 @@
# socket_server
# 401 Midterm - Nimble

## Socket Server

#### Authors: Becky, Chris, Joé, Morgana

## Links & Resources
* [GitHub Repo](https://github.com/401-advanced-javascript-nimble/socket_server)
* [Socket Server Deploylment](https://401-advanced-javascript-nimble-socket-server.azurewebsites.net)

### Documentation

### Modules
* `server.js` -- Requires **dotenv** and **socket.io** and creates a socket server instance. Reacts to a socket connection, reacts to player moves, and reacts when a user opts to disconnect.
* `game.js` -- Module that defines the Game class and related methods. Specifically, the starting amount in each stack, the **takeItemsRemaining** method to remove items from a stack, **tallyTotalItemsRemaining** to keep track of overall remaining items, and **decrement** to show the time remaining for each turn.
* `events.js` -- Module that exports an object with events the socket server will be listening for, namely, move, turn, gameOver, message, countdown, and win.
* `lib/connection_wrapper.js` -- Module that contains a curried 'start of game' function. It includes logic that keeps track of how many players are available for a game. If only one player has joined, they receive the message, 'Waiting for second player...'. If a second player joins, a new game is created. The message event 'Starting game' is sent to player one, followed by a turn event. The message event 'Starting game' is sent to player two, followed by the message event 'Waiting for player to move'.
* `lib/disconnect_wrapper.js` -- Module that contains a curried 'disconnect' function. When a player disconnects, emits a 'Player disconnected, ending game' and 'Game Over!' message to players.
* `lib/emit_wrapper.js` -- Module with logic for the emitWrapper function that takes in four parameters: **io** (the socket server instance), **event**, (the event to listen for), **payload** (usually data associated with an event), and **target** (the socket id for a specific player). If a target exists, the emitted event is sent to that specific player. Otherwise the emitted event is sent to all listening parties.
* `lib/game_cycle.js` -- Module that defines and exports the gameCycle function which takes in five parameters: **io** (the socket server instance), **currentGame** (the current game instance), **stackChoice** (the stack from which the current player chose to remove items), **numberToTake** (the amount the player chose to remove), and **socketID** (can represent either player). When items in all stacks equal zero, emits events to the winner and loser.

* `lib/move_wrapper.js` -- Module that contains a curried 'on move' function. It includes logic for the moveWrapper function that takes in three parameters: **socket** (can represent either player), **games** (an object containing instances), and **payload** (an array of data containing the game id and user's selections for their turn).

### Setup
#### `.env` Requirements
* PORT -- port to use (when running locally)

### Running the App
* Clone or download the repo at (https://github.com/401-advanced-javascript-nimble/socket_server)
* Run `npm i`
* Run `node server.js`

### Operating Instructions
* Part of a three part system. Please see these repos:
* [API Server Repo](https://github.com/401-advanced-javascript-nimble/API_server)
* [Client Repo](https://github.com/401-advanced-javascript-nimble/client)

#### Tests
* **How do you run tests?** `npm test`
* **What assertions were made?**
Server
Event Emitter
Wraps the emit event
Does not require a target
Game creation
When a single socket connects, it stores the socket and sends a wait message
When a second socket connects, it creates a game, sets the countdown, and clears the players array ingroom)
On move
Can correctly target the player/socket that 'moved'
Game Cycle
if the stacks are empty, the game ends
targets the correct player for win/loss
On Disconnect
if a player disconnects mid-game, it ends the game

Game Class
instantiating
can instantiate with an id and io
instantiating without id and io results in undefineds
starting properties
should have stacks
can add players
has a turn time limit
has a property to store the total number of things in the stacks
Methods
can randomly generate amounts for the stacks
can tally the total items in the stacks
can remove a given amount from a given stack
can decrement the time left
if time runs out, it ends the game

#### UML
![UML](./assets/Nimble_UML.jpg)
108 changes: 108 additions & 0 deletions __tests__/game.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
'use strict';

const Game = require('../game.js');

class MockIo {
constructor() {

}
to(target) {
this.target = target;
return this;
}
emit(event, payload) {
this.event = event;
this.payload = payload;
return this;
}
}

const testIo = new MockIo;

describe( 'Game Class', () => {

describe('instantiating', () => {
it('can instantiate with an id and io', () => {
const gameWithId = new Game(7, testIo);
expect(gameWithId.id).toBe(7);
expect(gameWithId.io).toBeDefined;
});

it('instantiating without id and io results in undefineds', () => {
const emptyGame = new Game();
expect(emptyGame.id).not.toBeDefined();
expect(emptyGame.io).not.toBeDefined();
});
});

describe('starting properties', () => {
const testGame = new Game(42);

it('should have stacks', () => {
expect(testGame.stacks).toBeDefined();
expect(testGame.stacks.a).toBeDefined();
expect(Object.keys(testGame.stacks)).toEqual(expect.arrayContaining(['a', 'b', 'c']));
expect(typeof testGame.stacks.a).toBe('number');
});

it('can add players', () => {
expect(testGame.players).toBeDefined();

testGame.players.push('fred');
testGame.players.push('george');

expect(testGame.players[0]).toBe('fred');
expect(testGame.players[1]).toBe('george');
});

it('has a turn time limit', () => {
expect(testGame.timeLeft).toBeDefined();
expect(typeof testGame.timeLeft).toBe('number');
expect(testGame.timeLeft > 0).toBeTruthy();
expect(testGame.countdown).toBeDefined();
});

it('has a property to store the total number of things in the stacks', () => {
expect(testGame.totalItemsRemaining).toBeDefined();
expect(typeof testGame.totalItemsRemaining).toBe('number');
});
});

describe('Methods', () => {
const testGame = new Game(12, testIo);

it('can randomly generate amounts for the stacks', () => {
expect(typeof testGame.generateRandomAmount()).toBe('number');
expect(testGame.generateRandomAmount() >= 0).toBeTruthy();
});

it('can tally the total items in the stacks', () => {
const a = testGame.stacks.a;
const b = testGame.stacks.b;
const c = testGame.stacks.c;
const total = a + b + c;

testGame._tallyTotalItemsRemaining();
expect(testGame.totalItemsRemaining).toEqual(total);
});

it('can remove a given amount from a given stack', () => {
const startingValue = testGame.stacks.a;
testGame.takeItemsFromStack('a', 4);
expect(testGame.stacks.a).toEqual(startingValue - 4);
});

it('can decrement the time left', () => {
const startingTime = testGame.timeLeft;
testGame.players.push('mock player');
testGame.decrement('mock player');
expect(testGame.timeLeft).toEqual(startingTime - 1);
});

it('if time runs out, it ends the game', () => {
testGame.timeLeft = 0;
testGame.decrement('mock player');
expect(testGame.io.payload).toBe('Game Over!');
});
});
});
Loading