Experiments in Trivia
Bored, want to see how fast I can develop a simple multiplayer trivia app in my blog environment using Firebase.
Let’s have a QuizBot manage a timer and a state machine that allows others to answer questions in the Chat window that are posed.
Simple Quiz Experiment
For kicks, I’ll use the code from [Christmas Presence]() earlier in this blog to keep track of the number of participants and their locations.
{[totalViewers]} viewers are viewing
-
Geo: {[viewer.city]}, {[viewer.region]}, {[viewer.country]} -- {[viewer.loc]}
Net: {[viewer.ip]} {[viewer.hostname]} {[viewer.org]}
The code for the above is below:
<div>
<script>
angular.module('BlogApp')
.controller('PresenceController', ['$scope', 'PresenceService',
function($scope, PresenceService) {
$scope.totalViewers = 0;
$scope.allViewers = [];
$scope.$on('onOnlineUser', function() {
$scope.$apply(function() {
$scope.totalViewers = PresenceService.getOnlineUserCount();
$scope.allViewers = PresenceService.getOnlineUserList();
});
});
}
])
.factory('PresenceService', ['$rootScope', '$http',
function($rootScope, $http) {
var onlineUsers = [];
var numOnlineUsers = 0;
var myUserInfo = {};
// Create our references
var listRef = new Firebase('https://doctorbud.firebaseIO.com/simplequizpresence1');
var userRef = listRef.push(); // This creates a unique reference for each user
var presenceRef = new Firebase('https://doctorbud.firebaseIO.com/.info/connected');
var jsonp = $http.jsonp('https://ipinfo.io/');
jsonp.then(
function(response) {
myUserInfo.city = response.city;
myUserInfo.country = response.country;
myUserInfo.hostname = response.hostname;
myUserInfo.ip = response.ip;
myUserInfo.loc = response.loc;
myUserInfo.org = response.org;
myUserInfo.region = response.region;
});
// Add ourselves to presence list when online.
presenceRef.on('value', function(snap) {
if (snap.val()) {
userRef.set(myUserInfo);
// Remove ourselves when we disconnect.
userRef.onDisconnect().remove();
}
});
// Get the user count and notify the application
listRef.on('value', function(snap) {
numOnlineUsers = snap.numChildren();
onlineUsers = [];
snap.forEach(function(childSnapshot) {
// This code will be called twice.
var name = childSnapshot.name();
var childData = childSnapshot.val();
onlineUsers.push(childData);
});
$rootScope.$broadcast('onOnlineUser');
});
var getOnlineUserCount = function() {
return numOnlineUsers;
}
var getOnlineUserList = function() {
return onlineUsers;
}
return {
getOnlineUserCount: getOnlineUserCount,
getOnlineUserList: getOnlineUserList
}
}
]);
</script>
<div ng-controller="PresenceController" class="card bg-well p-1" style="padding:20px;max-width:600px;">
<h6>{{totalViewers}} viewers are viewing</h6>
<div scroll-glue class="overflowable" style="font-size:small; color:#1111AA;background-color:#DDDDDD;">
<ul>
<li ng-repeat='viewer in allViewers'>
Geo: {{viewer.city}}, {{viewer.region}}, {{viewer.country}} -- {{viewer.loc}}
<br/>
Net: {{viewer.ip}} {{viewer.hostname}} {{viewer.org}}
</li>
</ul>
</div>
</div>
</div>
The Trivia Game
Here is the main event, a trivia game.
{[msg.from]}: {[msg.body]}
Machine Time: {[ MA.getMachineTime() ]}
Machine State: {[ MA.getMachineState() ]}
Machine Running: {[ MA.isRunning() ]}
Question Number: {[ questionNumber ]}
Countdown: {[ countdown ]}
Answers: {[ answers ]}
State: {[ state ]}
The code for the above is below:
<div>
<script>
function GameController($scope, $firebase) {
$scope.messages = $firebase(new Firebase('https://doctorbud.firebaseIO.com/simplequizchatmessages'));
$scope.answers = $firebase(new Firebase('https://doctorbud.firebaseIO.com/simplequizchatanswers'));
$scope.state = $firebase(new Firebase('https://doctorbud.firebaseIO.com/simplequizchatstate'));
$scope.countdown = $firebase(new Firebase('https://doctorbud.firebaseIO.com/simplequizchatcountdown'));
$scope.questionNumber = $firebase(new Firebase('https://doctorbud.firebaseIO.com/simplequizchatquestionNumber'));
$scope.addMessage = function(e) {
var curState = $scope.state[$scope.state.$getIndex()[0]];
console.log('stateMachine: ', curState);
if (e.keyCode != 13) return;
if ($scope.msg === "#clear")
{
$scope.messages.$set([]);
$scope.answers.$set([]);
}
else
{
if (curState == 'asked')
{
$scope.answers.$add({from: $scope.name, body: $scope.msg});
$scope.messages.$add({from: $scope.name, body: $scope.name + ' has answered.'});
}
else
{
$scope.messages.$add({from: $scope.name, body: $scope.msg});
}
$scope.msg = "";
}
};
$scope.addBotMessage = function(msg) {
$scope.messages.$add({from: "QuizBot", body: msg});
};
$scope.resetGame = function() {
$scope.messages.$set([]);
$scope.answers.$set([]);
$scope.state.$remove();
$scope.state.$add("asking");
$scope.countdown = 10;
$scope.questionNumber = 4;
};
$scope.stateMachine = function() {
var curState = $scope.state[$scope.state.$getIndex()[0]];
console.log('stateMachine: ', curState);
if (curState == 'asking')
{
$scope.addBotMessage('Question... What is ' + $scope.questionNumber + ' + ' + $scope.questionNumber + '?');
$scope.state.$remove();
$scope.state.$add("asked");
}
else if (curState == 'asked')
{
if ($scope.countdown > 0)
{
$scope.addBotMessage('T:' + $scope.countdown);
$scope.countdown = $scope.countdown - 1;
}
else
{
$scope.state.$remove();
$scope.state.$add("scoring");
}
}
else if (curState == 'scoring')
{
$scope.addBotMessage('Scores for Q:' + $scope.questionNumber);
console.log('$scope.answers=', $scope.answers);
var keys = $scope.answers.$getIndex();
keys.forEach(
function(key, i) {
var answer = $scope.answers[key];
console.log($scope.answers[key]);
$scope.addBotMessage(' ' + answer.from + ' answered "' + answer.body + '"');
});
$scope.questionNumber = $scope.questionNumber - 1;
$scope.countdown = 10;
$scope.answers.$remove();
$scope.state.$remove();
$scope.state.$add("asking");
}
};
}
</script>
<div style="padding:20px;max-width:500px; background-color: aliceblue;" ng-controller="GameController">
<div scroll-glue class="overflowable" id="messagesDiv" style="color:#00AA00;background-color:#000000;">
<div ng-repeat="msg in messages"><em>{{msg.from}}</em>: {{msg.body}}</div>
</div>
<br/>
<input type="text" ng-model="name" placeholder="Name" size="10">
<input type="text" ng-model="msg" ng-keydown="addMessage($event)" placeholder="Message..." size="50">
<h6>Machine Time: {{ MA.getMachineTime() }}</h6>
<h6>Machine State: {{ MA.getMachineState() }}</h6>
<h6>Machine Running: {{ MA.isRunning() }}</h6>
<h6>Question Number: {{ questionNumber }}</h6>
<h6>Countdown: {{ countdown }}</h6>
<h6>Answers: {{ answers }}</h6>
<h6>State: {{ state }}</h6>
<mlmmachine
ptr="MA"
ng-init="resetGame()"
reset-fn="resetGame()"
step-fn="stateMachine()"
class="mlm background">
<mlmpanel></mlmpanel>
</mlmmachine>
</div>
</div>