@ -1,84 +1,29 @@ | |||
<!DOCTYPE html> | |||
<html lang="en"> | |||
<head> | |||
<!-- Meta --> | |||
<meta charset="UTF-8" /> | |||
<title>Trend Spotter | Game</title> | |||
<!-- / --> | |||
<!-- Styles --> | |||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"> | |||
<link href="https://fonts.googleapis.com/css?family=Josefin+Sans:100,300,400,600,700" rel="stylesheet"> | |||
<link href="https://fonts.googleapis.com/css?family=Poppins:100,300,400,500,700,800,900" rel="stylesheet"> | |||
<link rel="stylesheet" href="app.css"> | |||
<!-- / --> | |||
</head> | |||
<body> | |||
<div class=""> | |||
<div class="row w-100"> | |||
<div class="col-12"> | |||
<div class="logo w-100">trend spot</div> | |||
</div> | |||
</div> | |||
<div class="container-fluid game"> | |||
<div class="row"> | |||
<!-- Main --> | |||
<div class="col-8 game__main"> | |||
<div class="game__round">Round 4/7</div> | |||
<div class="row w-100"> | |||
<div class="col-8"> | |||
<input class="w-100 game__phrase--entry" type="text"> | |||
</div> | |||
<div class="col-4"> | |||
<div class="game__phrase--clue">car</div> | |||
</div> | |||
<div class="col-xs-12 col-sm-7"> | |||
<a class="logo"> | |||
<div>WHAT</div> | |||
<div>THE </div> | |||
<div>TREND?!</div> | |||
</a> | |||
<div class="game__main"> | |||
<form onSubmit={this.sendNickname}> | |||
<input class="login__input" maxLength="30" placeholder="Nickname" /> | |||
<span> | |||
<button class="game__submit">Let's Play!</button> | |||
</span> | |||
</form> | |||
</div> | |||
<button class="game__submit">Submit my answer!</button> | |||
<!--<div class="game__user-score">jesseg89: 20,005 points</div>--> | |||
<div class="game__room">You're in <em>dave61's room</em> | 12/20 players</div> | |||
<a href="lobby.html" class="game__exit">Leave Game</a> | |||
</div> | |||
<!-- / --> | |||
<div class="col-xs-12 col-sm-5 game__sidebar"> | |||
<canvas class="scene scene--full" id="scene" ></canvas> | |||
<div class="col-4 col-sm-3 game__sidebar"> | |||
<div class="game__timer">60 seconds</div> | |||
<ol class="game__players"> | |||
<li class="game__player"> | |||
<span class="game__player-name">John Daniels</span> | |||
<span class="game__player-score">10,000 points</span> | |||
<span class="game__player-ready">X</span> | |||
</li> | |||
<li class="game__player"> | |||
<span class="game__player-name">John Daniels</span> | |||
<span class="game__player-score">10,000 points</span> | |||
<span class="game__player-ready">X</span> | |||
</li> | |||
<li class="game__player"> | |||
<span class="game__player-name">John Daniels</span> | |||
<span class="game__player-score">10,000 points</span> | |||
<span class="game__player-ready">X</span> | |||
</li> | |||
</ol> | |||
</div> | |||
</div> | |||
</div> | |||
<!-- Scripts --> | |||
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script> | |||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script> | |||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script> | |||
<script src="scripts/index.js"></script> | |||
<!-- / --> | |||
</body> | |||
</html> | |||
</div> |
@ -0,0 +1,14 @@ | |||
<div class="container"> | |||
<div class="row"> | |||
<ul> | |||
{for room in rooms} | |||
<li class="lobby__room"> | |||
<span class="lobby__room-name">{room.name}</span> | |||
<span class="lobby__room-occupancy">{room.occupancy}</span> | |||
<span class="lobby__room-status">{room.status}</span> | |||
</li> | |||
{/for} | |||
</ul> | |||
</div> | |||
<button>Create Room<button> | |||
</div> |
@ -0,0 +1,73 @@ | |||
//gets the trending data | |||
const trendingAPI = require("./trendsAPI.js"); | |||
class Player | |||
{ | |||
constructor(s) | |||
{ | |||
//name of the user | |||
this.name = null; | |||
//players socket | |||
this.socket = s; | |||
//score of the player | |||
this.score = 0; | |||
//reference to the room -- might not need this | |||
this.room = null; | |||
//the word the user selected for current round | |||
this.submission = ''; | |||
this.roundScore = 0; | |||
//logs the user data so we can record it to data base at end of round | |||
this.log = []; | |||
} | |||
/** | |||
* generate the json object used in 'roomUpdate' socket io event | |||
* | |||
* return {name: score: word:} | |||
*/ | |||
genJASON() | |||
{ | |||
var result = new Object(); | |||
result.name = this.name; | |||
result.score = this.score; | |||
result.word = this.submission; | |||
return result; | |||
} | |||
/** | |||
* data -- literally a string | |||
* @param data | |||
*/ | |||
selectWord(data) | |||
{ | |||
var w = data + " " + this.room.currentWord; | |||
this.submission = data; | |||
//console.log(w); | |||
this.room.update(); | |||
return new Promise(function(resolve, reject) | |||
{ | |||
trendingAPI.getPopularity(w).then(function(result) | |||
{ | |||
console.log("api result for " + result + w); | |||
resolve(result); | |||
}).catch(function(err){ | |||
console.log(err); | |||
}) | |||
}); | |||
} | |||
} | |||
module.exports = Player; |
@ -0,0 +1,281 @@ | |||
//used for the getting the word array | |||
const utils = require("./utils.js"); | |||
/** | |||
* Object used for storing rooms | |||
* @param capacityP -- the number of people that can be in room | |||
* @param pass -- the room password -- null if none | |||
* @param owner -- the person who is creating the room | |||
*/ | |||
class Room | |||
{ | |||
constructor(capacityP, pass, owner) | |||
{ | |||
//max capacity of room -- default is 4 for now | |||
this.capacity = capacityP; | |||
//name of the room | |||
this.roomName = owner.name; | |||
//list of words used in the game | |||
//7 for now will change later to be room specific | |||
this.words = utils.getRandomWords(7); | |||
this.currentWord = this.words.pop(); | |||
//list players -- so we can push requests to them | |||
this.users = []; | |||
//increments when rounds pass | |||
this.currentRound = 0; | |||
// the password of the room -- null if no password | |||
this.password = pass; | |||
/** | |||
1 = Waiting for users | |||
2 = Word shown, Waiting for response from users | |||
3 = Showing Result | |||
4 = Game Over, Display Final Results | |||
*/ | |||
this.state = 1; | |||
this.addUser(owner); | |||
} | |||
/** | |||
* generate the json object used in 'roomUpdate' socket io event | |||
* | |||
* return {name: score: word:} | |||
*/ | |||
genJASON() | |||
{ | |||
var result = new Object(); | |||
result.name = this.roomName; | |||
result.users = this.users; | |||
return result; | |||
} | |||
/** | |||
* creates json to send in the 'roomUpdate' socket event | |||
* | |||
* {users: gameState: roundWinner: currentWord: } | |||
*/ | |||
generateRoomUpdate() | |||
{ | |||
var result = new Object(); | |||
result.users = []; | |||
this.users.forEach(function(u) | |||
{ | |||
result.users.push(u.genJASON()); | |||
}); | |||
//sort the users based on score | |||
var countOuter = 0; | |||
var countInner = 0; | |||
var countSwap = 0; | |||
// var swapped; | |||
// do | |||
// { | |||
// countOuter++; | |||
// swapped = false; | |||
// for(var i = 0; i < result.users.length; i++) | |||
// { | |||
// countInner++; | |||
// if(result.users[i].score && result.users[i + 1].score && | |||
// result.users[i].score > result.users[i + 1].score) | |||
// { | |||
// countSwap++; | |||
// var temp = result.users[i]; | |||
// result.users[i] = result.users[j]; | |||
// result.users[j] = temp; | |||
// swapped = true; | |||
// } | |||
// } | |||
// } while(swapped); | |||
result.gameState = this.state; | |||
//sets round winner | |||
var rWinner = -1; | |||
for(var i = 0; i < this.users.length; i++) | |||
{ | |||
if(rWinner < this.users[i].roundScore) | |||
{ | |||
result.roundWinner = this.users[i].name; | |||
rWinner = this.users[i].roundScore; | |||
} | |||
} | |||
result.currentWord = this.currentWord; | |||
return result; | |||
} | |||
/** | |||
* adds a user to a room | |||
* @param p | |||
* return 0 if they could join | |||
*/ | |||
addUser(player) | |||
{ | |||
//console.log("user added"); | |||
//check if room is not full | |||
this.users.push(player); | |||
player.room = this; | |||
if(this.users.length == this.capacity) | |||
{ | |||
this.state = 2; | |||
} | |||
console.log("user added to room " + player.name); | |||
//console.log(this.users); | |||
this.update(); | |||
} | |||
/** | |||
* Removes a specific user from the room and adjusts the size of the array | |||
* if the array is empty, the room closes | |||
* @param p | |||
*/ | |||
removeUser(p) | |||
{ | |||
console.log("remove users fnc called"); | |||
var temp = new Array(); | |||
for(var i = 0; i < temp.length; i++) | |||
{ | |||
if(p.name === this.users[i].name) | |||
{ | |||
} | |||
else | |||
{ | |||
temp.push(this.users[i]); | |||
} | |||
} | |||
this.users = temp; | |||
//if room is empty remove the room from rooms list | |||
if(this.users.length == 0) | |||
{ | |||
console.log("room scrubbed"); | |||
delete rooms[this.roomName]; | |||
} | |||
this.update(); | |||
} | |||
/** | |||
* Whether or not a user can join this room -- checks for number of people are | |||
* already in the room and the password | |||
* @param p | |||
* @returns {boolean} | |||
*/ | |||
canJoin(p) | |||
{ | |||
if(this.password == null) | |||
{ | |||
return (this.users.length < this.capacity); | |||
} | |||
else | |||
{ | |||
return (this.users.length < this.capacity) && (p === this.password); | |||
} | |||
} | |||
/** | |||
* starts new round for the room -- called once all the players have submitted | |||
*/ | |||
newRound() | |||
{ | |||
console.log("new round started"); | |||
if(this.words.length == 0) | |||
{ | |||
this.state == 4; | |||
} | |||
else | |||
{ | |||
this.currentRound++; | |||
this.users.forEach(function(u) | |||
{ | |||
u.submission = ''; | |||
}); | |||
this.currentWord = this.words.pop(); | |||
this.state = 2; | |||
} | |||
this.sendRoomUpdate(); | |||
} | |||
//updates room variables | |||
update() | |||
{ | |||
switch(this.state) | |||
{ | |||
case 1: //waiting for users to join | |||
{ | |||
if(this.users.length == this.capacity) | |||
{ | |||
this.newRound(); | |||
} | |||
break; | |||
} | |||
case 2: // waiting for responses | |||
{ | |||
var flag = true; | |||
var test = ""; | |||
this.users.forEach(function(u) | |||
{ | |||
test+=u.submission; | |||
if(u.submission === '') | |||
{ | |||
flag = false; | |||
} | |||
}); | |||
console.log("big stuff " + test); | |||
if(flag) | |||
{ | |||
this.state = 3; | |||
this.newRound(); | |||
// setTimeout(function() { | |||
// | |||
// }, 4000); | |||
} | |||
break; | |||
} | |||
case 3: // showing results -- time out fnc | |||
{ | |||
console.log("error &&&&&&&&&&&&&&&&&&"); | |||
break; | |||
} | |||
case 4: //game over display final result | |||
{ | |||
//sqlStuff.dumpRoom(this); | |||
break; | |||
} | |||
default: | |||
{ | |||
console.log("You don goof up") | |||
} | |||
} | |||
console.log(this.state + " state"); | |||
this.sendRoomUpdate(); | |||
} | |||
} | |||
module.exports = Room; |
@ -0,0 +1,89 @@ | |||
const googt = require('google-trends-api'); | |||
const DAY = 1000 * 60 * 60 * 24; // 1 day in milliseconds | |||
const YEAR = DAY * 365; // 1 year in milliseconds | |||
const GEO = 'US'; //the scope of the trends | |||
/** | |||
desc: helper function for getYearStats, gets list of popularity for days in | |||
the month. | |||
*/ | |||
function getMonthStats(word, month){ | |||
return new Promise(function(resolve, reject){ | |||
//set up query for 1 month length | |||
googt.interestOverTime({ | |||
keyword:word, | |||
startTime:new Date(Date.now() - (YEAR * month/12)), | |||
endTime:new Date(Date.now() - (YEAR * (month-1)/12)) | |||
}).then(function(results){ | |||
//parse the json, fill return array w tuples of date + value | |||
var times = JSON.parse(results).default.timelineData; | |||
var ret = []; | |||
for(var i = 0; i < times.length; ++i){ | |||
var tup = new Object(); | |||
tup.time = times[i].formattedTime; | |||
tup.value = times[i].value[0]; | |||
ret[i] = tup; | |||
} | |||
resolve(ret); | |||
}); | |||
}); | |||
} | |||
module.exports= | |||
{ | |||
/* | |||
desc: returns an integer score for the word over the day | |||
*/ | |||
getPopularity: function(word) | |||
{ | |||
//must be a promise since call to trends API is async | |||
return new Promise(function(resolve, reject){ | |||
//specifies the keyword, time interval, granularity, and region | |||
googt.interestOverTime({keyword:word, | |||
startTime:new Date(Date.now() - DAY),granularTimeResolution:true, | |||
geo:GEO | |||
}) | |||
.then(function(results){ | |||
//turn into json object | |||
data = JSON.parse(results).default.timelineData; | |||
//add up values | |||
var total = 0; | |||
data.forEach(function(element){ | |||
total += element.value[0]; | |||
}) | |||
//tell function to return | |||
console.log("********************" + total); | |||
//pl.selectWord2(total); | |||
resolve(total); | |||
}).catch(function(err){ | |||
reject("Google Trends Query Failed"); | |||
}); | |||
}); | |||
}, | |||
/** | |||
desc: returns a list of tuples (date, value) representing word's | |||
popularity for the past year | |||
*/ | |||
/* | |||
getYearStats: async function(word){ | |||
var ret = []; | |||
for (var i = 9; i > 0; --i) { | |||
await getMonthStats(word,i).then(function(data){ | |||
ret = ret.concat(data); | |||
}); | |||
console.log(i); | |||
} | |||
return ret; | |||
} | |||
*/ | |||
}; |
@ -0,0 +1,37 @@ | |||
var fs = require('fs'); | |||
const WORD_FILE_PATH = '../../words/words.txt'; | |||
//loads words from word file | |||
var words = []; | |||
var data = fs.readFileSync(WORD_FILE_PATH, 'utf8'); | |||
var lines = data.split('\n'); | |||
lines.forEach(function(element){ | |||
words.push(element); | |||
}); | |||
module.exports= | |||
{ | |||
/** | |||
* returns a specific amount of words -- unique | |||
* @param num the number of words | |||
* @returns {Array} the random, unique words | |||
*/ | |||
getRandomWords : function(num) | |||
{ | |||
var rwords = []; | |||
for(var i = 0; i < num; ++i){ | |||
var randindex = Math.round((Math.random() * (words.length - 1))); | |||
var newword = words[randindex]; | |||
var uniq = true; | |||
rwords.forEach(function(element){ | |||
if(newword === element){ | |||
--i; | |||
uniq = false; | |||
} | |||
}); | |||
if(uniq)rwords.push(newword); | |||
} | |||
return rwords; | |||
} | |||
}; |