@ -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"> | <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> | </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> | ||||
<!-- / --> | |||||
<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> | </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; | |||||
} | |||||
}; |