Large diffs are not rendered by default.

@@ -0,0 +1,104 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>

<!-- Ensure that everything scales appropriately on a mobile device -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">

<!-- Let's borrow a cool looking Font from Google -->
<link href='https://fonts.googleapis.com/css?family=Quicksand:300,400,700' rel='stylesheet' type='text/css'>

<link href="roomstyle.css" rel="stylesheet">
</head>

<body>


<div id="gameArea">
<!-- This is where the templates defined below will be used -->
</div>

<!-- Main Title Screen that appears when the page loads for the first time -->
<script id="intro-screen-template" type="text/template">

<div class="titleWrapper">

<div class="title">
ANAGRAMMATIX
</div>

<div class="buttons">

<button id="btnCreateGame" class="btn left">CREATE</button>
<button id="btnJoinGame" class="btn right">JOIN</button>

</div>

</div>

</script>

<!-- This screen appears when a user clicks "CREATE" on the Title Screen -->
<script id="create-game-template" type="text/template">
<div class="createGameWrapper">

<div class="info">Open this site on your mobile device:</div>
<div id="gameURL" class="infoBig">Error!</div>

<div class="info">Then click <strong>JOIN</strong> and <br/> enter the following Game ID:</div>
<div id="spanNewGameCode" class="gameId">Error!</div>

<div id="playersWaiting"></div>
</div>
</script>

<!-- This scrreen appears when a player clicks "JOIN" on the Title Screen -->
<script id="join-game-template" type="text/template">
<div class="joinGameWrapper">
<div class="info">
<label for="inputPlayerName">Your Name:</label>
<input id="inputPlayerName" type="text" />
</div>

<div class="info">
<label for="inputGameId">Game ID:</label>
<input id="inputGameId" type="text"/>
</div>

<div class="info buttons">
<button id="btnStart" class="btn">Start</button>
<div id="playerWaitingMessage"></div>
</div>
</div>
</script>

<!-- This is the 'Host' screen. It displays the word for each player to match -->
<script id="host-game-template" type="text/template">
<div id="wordArea">
<div id="hostWord">5</div>
</div>
<div id="playerScores">
<div id="player1Score" class="playerScore">
<span class="score">0</span><span class="playerName">Player 1</span>
</div>
<div id="player2Score" class="playerScore">
<span class="playerName">Player 2</span><span class="score">0</span>
</div>
</div>
</script>

<!-- JavaScript Libraries -->

<!-- jQuery! -->
<script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>

<!-- If Socket.IO is used with Express, then the /socket.io/ path will
serve the proper Socket.IO javascript files used by the browser -->
<script src="/socket.io/socket.io.js"></script>

<!-- app.js is where all the client-side Anagrammatix game logic -->
<script src="gamelogic.js"></script>

</body>
</html>
@@ -0,0 +1,318 @@
/*
Dark Green : #78BD4C
Mid Green : #A8FF56
Lite : #ECFFE0
Dark Purple : #A22FB0
*/

html, body {
background-color: #78BD4C;
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}



/* ******************************
BUTTONS!
(Inspired by Bootstrap 3.0)
****************************** */

.btn {
display: inline-block;
height: 100%;
width: 49%;
margin-bottom: 0;
color: #ECFFE0;
font-family: 'Quicksand', sans-serif;
font-weight: 700;
font-size: 2em;
line-height: 1.2;
text-align: center;
background-color: #8AD453;
white-space: nowrap;
vertical-align: middle;
cursor: pointer;
border: 1px solid transparent;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-o-user-select: none;
user-select: none;
}

.btn:focus {
outline: thin dotted #333;
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}

.btn:hover,
.btn:focus {
color: #AE37B2;
text-decoration: none;
}

.btn:active,
.btn.active {
outline: 0;
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
}

.left {
float: left;
}

.right {
float: right;
}

/* ******************************
TITLE SCREEN
(intro-screen-template)
****************************** */

#gameArea {
height: 100%;
width: 100%;
}

.titleWrapper {
font-family: 'Quicksand', sans-serif;
font-weight: 400;
position: absolute;
height: 50%;
width: 96%;
margin: auto;
bottom: 0;
left: 0;
top: 0;
right: 0;
}

.title {
margin: 0px auto;
text-align: center;
width: 100%;
font-family: 'Quicksand', sans-serif;
color: #ECFFE0;
font-weight: 300;
}

.buttons {
width: 100%;
text-align: center;
}

/* ******************************
START SCREEN
(create-game-template)
****************************** */

.createGameWrapper, .joinGameWrapper, .gameOver {
font-family: 'Quicksand', sans-serif;
margin: 0 auto;
text-align: center;
}

.createGameWrapper .info{
color: #ECFFE0;
font-weight: 400;
font-size: 2em;
margin-top: 1.5em;
}

.createGameWrapper{
color: #AE37B2;
font-weight: 300;
}

.info label {
display: block;
}

.info input {
text-align: center;
padding: 10px;
width: 200px;
height: 60px;
font-family: 'Quicksand', sans-serif;
color: #A22FB0;
font-weight: 300;
font-size: 54px;
border: 1px dotted white;
border-radius: 10px;
background: transparent;
}

.info input#inputPlayerName {
width: 90%;
}


/* ******************************
JOIN SCREEN
(join-game-template)
****************************** */

.joinGameWrapper {
margin: 0;
padding: 0;
height: 100%;
min-height: 320px;
}

.joinGameWrapper .info {
font-size: 1.5em;
color: #ECFFE0;
height: 30%;
padding-top: 1%;
}

.joinGameWrapper .btn {
width: 100%;
height: 50%;
}

#playerWaitingMessage {
font-size: .8em;
}

.createGameWrapper #gameURL {
font-size: 4em;
}

.createGameWrapper .gameId {
font-size: 8em;
}



/* ******************************
PLAYER GAME SCREEN
****************************** */


#ulAnswers {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}

#ulAnswers li {
width: 100%;
height: 16.6%;
}

.btnAnswer {
width: 100%;
border-bottom: 1px dotted white;
font-weight: 400;
font-size: 3em;
color: #AE37B2;
}



/* ******************************
HOST SCREEN
(host-game-template)
****************************** */

/* Absolute Centering: http://coding.smashingmagazine.com/2013/08/09/absolute-horizontal-vertical-centering-css/ */
#wordArea {
font-family: 'Quicksand', sans-serif;
font-weight: 400;
position: absolute;
height: 50%;
width: 50%;
margin: auto;
bottom: 0;
left: 0;
top: 0;
right: 0;
}

#hostWord {
height: 100%;
width: 100%;
}

#hostWord h2, #btnPlayerRestart h3 {
font-size: 161px;
line-height: 1em;
font-family: 'Quicksand', sans-serif;
font-weight: 400;
margin: 0;
padding: 0;
text-transform: uppercase;
}

#playerScores {
height: 10%;
width: 100%;
position: fixed;
top: 0;
}

.playerScore {
width: 50%;
padding: 0;
margin: 0;
font-family: 'Quicksand', sans-serif;
font-weight: 400;
height: 100%;
}

.playerScore span {
display: inline-block;
font-size: 1.4EM;
padding: 2%;
min-width: 10%;
margin: 0;
}

.playerScore .score {
text-align: center;
background-color: #A8FF56;
}

.playerScore .playerName {
width: 77%;
background-color: #ECFFE0;
}

#player1Score {
float: left;
}

#player2Score {
float: right;
text-align: right;
}


/* ******************************
TITLE SCREEN
(intro-screen-template)
****************************** */

.gameOver {
display: block;
height: 20%;
padding-top: 10%;
font-size: 2em;
}

.btnGameOver {
width: 100%;
height: 10%;
position: fixed;
bottom: 0;
}


Empty file.
279 wixoss.js
@@ -0,0 +1,279 @@
var io;
var gameSocket;

/**
* This function is called by index.js to initialize a new game instance.
*
* @param sio The Socket.IO library
* @param socket The socket object for the connected client.
*/
exports.initGame = function(sio, socket){
io = sio;
gameSocket = socket;
gameSocket.emit('connected', { message: "You are connected!" });

// Host Events
gameSocket.on('hostCreateNewGame', hostCreateNewGame);
gameSocket.on('hostRoomFull', hostPrepareGame);
gameSocket.on('hostCountdownFinished', hostStartGame);
gameSocket.on('hostNextRound', hostNextRound);

// Player Events
gameSocket.on('playerJoinGame', playerJoinGame);
gameSocket.on('playerAnswer', playerAnswer);
gameSocket.on('playerRestart', playerRestart);
}

/* *******************************
* *
* HOST FUNCTIONS *
* *
******************************* */

/**
* The 'START' button was clicked and 'hostCreateNewGame' event occurred.
*/
function hostCreateNewGame() {
// Create a unique Socket.IO Room
var thisGameId = ( Math.random() * 100000 ) | 0;

// Return the Room ID (gameId) and the socket ID (mySocketId) to the browser client
this.emit('newGameCreated', {gameId: thisGameId, mySocketId: this.id});

// Join the Room and wait for the players
this.join(thisGameId.toString());
};

/*
* Two players have joined. Alert the host!
* @param gameId The game ID / room ID
*/
function hostPrepareGame(gameId) {
var sock = this;
var data = {
mySocketId : sock.id,
gameId : gameId
};
//console.log("All Players Present. Preparing game...");
io.sockets.in(data.gameId).emit('beginNewGame', data);
}

/*
* The Countdown has finished, and the game begins!
* @param gameId The game ID / room ID
*/
function hostStartGame(gameId) {
console.log('Game Started.');
sendWord(0,gameId);
};

/**
* A player answered correctly. Time for the next word.
* @param data Sent from the client. Contains the current round and gameId (room)
*/
function hostNextRound(data) {
if(data.round < wordPool.length ){
// Send a new set of words back to the host and players.
sendWord(data.round, data.gameId);
} else {
// If the current round exceeds the number of words, send the 'gameOver' event.
io.sockets.in(data.gameId).emit('gameOver',data);
}
}
/* *****************************
* *
* PLAYER FUNCTIONS *
* *
***************************** */

/**
* A player clicked the 'START GAME' button.
* Attempt to connect them to the room that matches
* the gameId entered by the player.
* @param data Contains data entered via player's input - playerName and gameId.
*/
function playerJoinGame(data) {
//console.log('Player ' + data.playerName + 'attempting to join game: ' + data.gameId );

// A reference to the player's Socket.IO socket object
var sock = this;

// Look up the room ID in the Socket.IO manager object.
var room = gameSocket.manager.rooms["/" + data.gameId];

// If the room exists...
if( room != undefined ){
// attach the socket id to the data object.
data.mySocketId = sock.id;

// Join the room
sock.join(data.gameId);

//console.log('Player ' + data.playerName + ' joining game: ' + data.gameId );

// Emit an event notifying the clients that the player has joined the room.
io.sockets.in(data.gameId).emit('playerJoinedRoom', data);

} else {
// Otherwise, send an error message back to the player.
this.emit('error',{message: "This room does not exist."} );
}
}

/**
* A player has tapped a word in the word list.
* @param data gameId
*/
function playerAnswer(data) {
// console.log('Player ID: ' + data.playerId + ' answered a question with: ' + data.answer);

// The player's answer is attached to the data object. \
// Emit an event with the answer so it can be checked by the 'Host'
io.sockets.in(data.gameId).emit('hostCheckAnswer', data);
}

/**
* The game is over, and a player has clicked a button to restart the game.
* @param data
*/
function playerRestart(data) {
// console.log('Player: ' + data.playerName + ' ready for new game.');

// Emit the player's data back to the clients in the game room.
data.playerId = this.id;
io.sockets.in(data.gameId).emit('playerJoinedRoom',data);
}

/* *************************
* *
* GAME LOGIC *
* *
************************* */

/**
* Get a word for the host, and a list of words for the player.
*
* @param wordPoolIndex
* @param gameId The room identifier
*/
function sendWord(wordPoolIndex, gameId) {
var data = getWordData(wordPoolIndex);
io.sockets.in(data.gameId).emit('newWordData', data);
}

/**
* This function does all the work of getting a new words from the pile
* and organizing the data to be sent back to the clients.
*
* @param i The index of the wordPool.
* @returns {{round: *, word: *, answer: *, list: Array}}
*/
function getWordData(i){
// Randomize the order of the available words.
// The first element in the randomized array will be displayed on the host screen.
// The second element will be hidden in a list of decoys as the correct answer
var words = shuffle(wordPool[i].words);

// Randomize the order of the decoy words and choose the first 5
var decoys = shuffle(wordPool[i].decoys).slice(0,5);

// Pick a random spot in the decoy list to put the correct answer
var rnd = Math.floor(Math.random() * 5);
decoys.splice(rnd, 0, words[1]);

// Package the words into a single object.
var wordData = {
round: i,
word : words[0], // Displayed Word
answer : words[1], // Correct Answer
list : decoys // Word list for player (decoys and answer)
};

return wordData;
}

/*
* Javascript implementation of Fisher-Yates shuffle algorithm
* http://stackoverflow.com/questions/2450954/how-to-randomize-a-javascript-array
*/
function shuffle(array) {
var currentIndex = array.length;
var temporaryValue;
var randomIndex;

// While there remain elements to shuffle...
while (0 !== currentIndex) {

// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;

// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}

return array;
}

/**
* Each element in the array provides data for a single round in the game.
*
* In each round, two random "words" are chosen as the host word and the correct answer.
* Five random "decoys" are chosen to make up the list displayed to the player.
* The correct answer is randomly inserted into the list of chosen decoys.
*
* @type {Array}
*/
var wordPool = [
{
"words" : [ "sale","seal","ales","leas" ],
"decoys" : [ "lead","lamp","seed","eels","lean","cels","lyse","sloe","tels","self" ]
},

{
"words" : [ "item","time","mite","emit" ],
"decoys" : [ "neat","team","omit","tame","mate","idem","mile","lime","tire","exit" ]
},

{
"words" : [ "spat","past","pats","taps" ],
"decoys" : [ "pots","laps","step","lets","pint","atop","tapa","rapt","swap","yaps" ]
},

{
"words" : [ "nest","sent","nets","tens" ],
"decoys" : [ "tend","went","lent","teen","neat","ante","tone","newt","vent","elan" ]
},

{
"words" : [ "pale","leap","plea","peal" ],
"decoys" : [ "sale","pail","play","lips","slip","pile","pleb","pled","help","lope" ]
},

{
"words" : [ "races","cares","scare","acres" ],
"decoys" : [ "crass","scary","seeds","score","screw","cager","clear","recap","trace","cadre" ]
},

{
"words" : [ "bowel","elbow","below","beowl" ],
"decoys" : [ "bowed","bower","robed","probe","roble","bowls","blows","brawl","bylaw","ebola" ]
},

{
"words" : [ "dates","stead","sated","adset" ],
"decoys" : [ "seats","diety","seeds","today","sited","dotes","tides","duets","deist","diets" ]
},

{
"words" : [ "spear","parse","reaps","pares" ],
"decoys" : [ "ramps","tarps","strep","spore","repos","peris","strap","perms","ropes","super" ]
},

{
"words" : [ "stone","tones","steno","onset" ],
"decoys" : [ "snout","tongs","stent","tense","terns","santo","stony","toons","snort","stint" ]
}
]