Skip to content

Instantly share code, notes, and snippets.

@kylebakerio
Last active November 30, 2015 19:58
Show Gist options
  • Save kylebakerio/e1b1227d285b78f67b56 to your computer and use it in GitHub Desktop.
Save kylebakerio/e1b1227d285b78f67b56 to your computer and use it in GitHub Desktop.
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var morgan = require('morgan');
var app = express();
app.use(express.static(__dirname + '/client'));
app.use('/bower_components', express.static(__dirname + '/bower_components'));
app.use(morgan('dev'));
var games = [];
app.get('/', function (req, res) {
res.send("This should be a frontend interface for the bowling API, yo.");
});
// takes in an ID and returns
app.get('/games/:id', function (req,res) {
// return full game object
if (typeof req.gameNum !== "number") res.send(/*code for invalid request*/);
else if (typeof games[req.gameNum]) res.send(/*code for resource doesn't exist*/);
else res.send(plainScores(req.gameNum));
})
// idempotent; takes in data on individual rolls that are explicitly defined, returns the round that has been 'patched'. Can create or update.
app.patch('/score', function (req, res) {
// example expected input: req.update === {gameNum: 13, player: "John", round: 0, roll: 0, pins: 12}
if (typeof req.update !== "object" || typeof req.update.gameNum !== "number") res.send(/*code for invalid request*/);
else if (typeof games[req.update.gameNum]) res.send(/*code for resource doesn't exist*/);
else {
updateScore(req.update.gameNum, req.update.player, req.update.round, req.update.roll, req.update.pins);
res.send(games[req.update.gameNum][req.update.player][req.update.round]);
}
});
// takes in only the game's ID and the pins of the last roll, and returns... The whole game?
app.patch('/score', function (req, res) {
// example expected input: req === {names: ["John", "Sarah"], timeout: 21600000}
// have the client indicate time to keep game alive.
if ( !Array.isArray(req.names) || req.names.length < 1 ) res.send(/*code for invalid request*/);
else {
var gameNum = newGame(req.names);
res.send({gameID: gameNum});
// setTimeout(games.splice(gameNum, 1), req.timeout); // prevents games from being saved forever.
}
});
// takes an array of names, creates a server side game object, and returns the ID of that object.
app.post('/new-game', function (req, res) {
// example expected input: req === {names: ["John", "Sarah"], timeout: 21600000}
// have the client indicate time to keep game alive.
if ( !Array.isArray(req.names) || req.names.length < 1 ) res.send(/*code for invalid request*/);
else {
var gameNum = newGame(req.names);
res.status(201).send({gameID: gameNum});
// setTimeout(games.splice(gameNum, 1), req.timeout); // prevents games from being saved forever.
}
});
app.delete('/game', function (req,res) {
// game is finished, delete. you will need the timeoutID as well, which needs to be saved to the gameNum instance (global.clearTimeout(games[gameNum].timeoutID))
if (typeof req.gameNum !== "number") res.send(/*code for invalid request*/);
else if (typeof games[req.gameNum]) res.send(/*code for resource doesn't exist*/);
res.send(games.splice([req.gameNum], 1)); // status code? proper to return finished game according to REST? splice works correctly?
});
var server = app.listen(3017, function () {
var port = server.address().port;
console.log('Example app listening at http://%s:%s', /*host,*/ port);
});
//
// bowling functions
//
function newGame (names) {
var game = {}; // create new game object
names.forEach( (name) => {game[name] = []} ); // every player gets an empty array to store their rounds in
games.push(game); // store newly created game locally on server
return games.length-1; // return the index of the just-created game for client use
}
function updateScore (gameNum, player, round, roll, pins) {
// example expected input: req.update === {gameNum: 13, player: 0, round: 0, roll: 0, pins: 12}
// if this is a new round, and there aren't existing scores for this round
if (roll === 0 && typeof games[gameNum][player].rounds[round] === "undefined") {
// create an array for this round
games[gameNum][player].rounds[round] = [];
}
// within the array for this round, assign the index that corresponds to this 'roll' to a function that returns the face value when called
games[gameNum][player].rounds[round][roll] = () => {return pins};
// if this is a strike
if (roll === 0 && pins === 12) {
// push function into this round that returns bonus ball 1 OR zero if not yet played
games[gameNum][player].rounds[round].push(
() => {
return typeof games[gameNum][player].rounds[round+1] !== "undefined" ? games[gameNum][player].rounds[round+1][0]() : 0;
}
);
// push function into this round that returns bonus ball 2 OR zero if not yet played
games[gameNum][player].rounds[round].push(
() => {
return typeof games[gameNum][player].rounds[round+1] !== "undefined" &&
typeof games[gameNum][player].rounds[round+1][1] !== "undefined" ?
games[gameNum][player].rounds[round+1][1]() : 0;
}
);
}
// if this is a spare
else if (roll === 1 && games[game][player].rounds[round][0]() + games[game][player].rounds[round][1]() === 12) {
// push function into this round that returns bonus ball 1 OR zero if not yet played
games[game][player].rounds[round].push(
() => {
return typeof games[game][player].rounds[round+1] !== "undefined" ? games[game][player].rounds[round+1][0]() : 0;
}
);
}
}
// returns the same game object, with the subarrays containing rolls populated with
// corresponding integers instead of functions.
function plainScores (gameIndex) {
var scores = {};
for (player in games[gameIndex]) {
scores[player].rounds = [];
for (var i = 0; i < games[gameIndex][player].rounds.length; i++){ // for each round
scores[player].rounds[i] = games[gameIndex][player].rounds[i].map((func) => { return func()});
}
}
return scores;
}
// Example reference game structure as locally stored:
/*
game[0] = [ // a game with one or many players, in an array of games
{ // a player
name: "John",
rounds: [
[ // round 1
() => {return 11}, // an individual roll
() => {return 1}, // another individual roll (and so on)
() => {return games[0 <--this game ][0 <--this player ].rounds[1 <--the next round ][0 <--the first roll of that round] (unless undefined, in which case return 0)},
],
[ // round 2
() => {return 12},
() => {return games[0][0].rounds[2][0] (unless undefined, in which case return 0)},
() => {return games[0][0].rounds[2][1] (unless undefined, in which case return 0)}
]
]
},
{ // another player
name: "Sally",
rounds: [
[
() => {return 11},
() => {return 0}
],
[
() => {return 3},
() => {return 9},
() => {return games[0][1].rounds[2][0] (unless undefined, in which case return 0)}
]
]
}
]
*/
@kylebakerio
Copy link
Author

dillema: if the order of the players matters, I can't use an object. I could use a ES6 map, or an array. Bummer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment