//store local reference for brevity
var Signal = signals.Signal;
/*
// simple signals demo code here as an example
//custom object that dispatch signals
var dice = {
threw: new Signal(), //past tense is the recommended signal naming convention
carched: new Signal()
};
function onThrew(param1, param2) {
console.log(param1 + param2);
}
dice.threw.add(onThrew); //add listener
dice.threw.dispatch('user1', ' - dice no. = 6'); //dispatch signal passing custom parameters
dice.threw.remove(onThrew); //remove a single listener
*/
var DiceGame = function(settings) {
this.settings = $.extend(DiceGame.defaultSettings, settings);
var activePlayer = {};
this.addPlayer = function() {
var index = this.players.push({
name: 'player' + (this.players.length + 1),
//custom object that dispatch signals
dice: {
threw: new Signal(), //past tense is the recommended signal naming convention
catched: new Signal()
},
score: 0,
dicesThrown: 0
});
activePlayer = this.players[index-1];
activePlayer.index = index-1;
this.setActivePlayer(activePlayer);
// add display listener
activePlayer.dice.threw.add(this.onDiceThrew, this);
activePlayer.dice.catched.add(this.onDiceCatched, this);
//console.log(this.players, index, this.$activePlayerInfo, activePlayer);
};
this.getActivePlayer = function() {
return activePlayer;
};
this.setActivePlayer = function(player, index){
if ( typeof index != 'undefined' ) {
console.log(index, this.players[index]);
activePlayer = this.players[index];
}
else {
activePlayer = player;
}
this.updatePlayerInfo(activePlayer.name);
this.$activePlayerScore.html(activePlayer.score);
};
this.initGame = function() {
this.$activePlayerInfo = $(this.settings.elActivePlayer);
this.$activePlayerScore = $(this.settings.elActivePlayerScore);
this.$gameInfo = $(this.settings.elGameInfo);
this.$playField = $(this.settings.elPlayField);
// add click handlers (bind to DiceGame obj. with this)
$('#newGame').click(this.reset.bind(this));
$('#addPlayer').click(this.addPlayer.bind(this));
$('#changePlayer').click(this.nextPlayer.bind(this));
$('#throw').click(this.throwDice.bind(this));
$('#catch').click(this.catchDice.bind(this));
// add two players
_.each(new Array(this.settings.defaultPlayerCount), function(){
this.addPlayer();
}, this);
this.setActivePlayer(null, 0); // can change current player by index
}
this.initGame();
};
DiceGame.defaultSettings = {
elActivePlayer: '#activePlayer',
elActivePlayerScore: '#activePlayerScore',
elGameInfo: '#gameInfo',
elPlayField: '#playField',
defaultPlayerCount: 2,
maxThrownCount: 2
};
DiceGame.prototype = {
players: [],
diceList: [],
updatePlayerInfo: function(text) {
this.$activePlayerInfo.html(text);
},
reset: function() {
this.diceList = [];
$.each(this.players, function(index, item) {
console.log(item);
item.score = 0;
item.dicesThrown = 0;
});
this.setActivePlayer(null, 0); // can change current player by index
this.refreshPlayField();
//this.showGameInfo('');
this.hideGameInfo();
},
nextPlayer: function() {
var index = this.getActivePlayer().index;
index++;
if (index >= this.players.length ) {
//'roll over' required!
index = 0;
}
//var playerCopy = this.players.slice(0);
this.setActivePlayer(this.players[index]); // next player
},
onDiceThrew: function(diceNo) {
console.log('threw dice', diceNo);
var newDice = {player: this.getActivePlayer(),
diceValue: diceNo};
if ( newDice.player.dicesThrown < this.settings.maxThrownCount ) {
this.diceList.push(newDice);
this.$playField.append($('<p/>').text(newDice.player.name + ' - threw dice: ' +newDice.diceValue));
//console.log('threw', this.diceList);
newDice.player.dicesThrown++;
}
else {
//alert(newDice.player.dicesThrown+ ' dices thrown. None left.');
//show message that all dices are thrown
this.showGameInfo(newDice.player.dicesThrown+ ' dices thrown. None left.');
return;
}
console.log(newDice);
this.nextPlayer(); // change to next player
},
checkGameOver: function() {
// all thrown and nothing to catch --> game is over
var winner = _.max(this.players, function(player) {
console.log(player);
return player.score;
});
console.log("winner", winner, this.players);
var otherPlayers = _.omit(this.players, function(value) {
console.log('value', value, value===winner);
return value === winner;});
var scoresStr = '';
_.each(otherPlayers, function(player) {
scoresStr += player.name + ': ' + player.score + '<br/>';
});
// check if we have a draw.
//this.players[0].score = 5; // needed for testing
//this.players[1].score = 5;
var draw = _.every(this.players, function(player) {
return player.score === winner.score;
});
console.log(draw);
if (draw) {
this.showGameInfo('Game over!<br/>Draw with score ' +
winner.score, true);
}
else
{
// call showGameInfo with true --> keeps message displayed
this.showGameInfo('Game over!<br/>' + winner.name +
' wins the game with score ' + winner.score
+ '!<br/>Other scores:<br/>' + scoresStr, true);
}
},
onDiceCatched: function() {
// catch one dice of other player
var player = this.getActivePlayer();
var diceList = this.diceList.slice(0); // copy dice list
var allowedDice = _.filter(diceList, function(dice) {
return dice.player.name !== player.name;
});
var catched = allowedDice[Math.floor(Math.random()*allowedDice.length)];
// console.log('catched dice = ', catched);
// add score to active player
if ( catched ) {
player.score += catched.diceValue;
this.$activePlayerScore.html(player.score);
// update play field
var newDiceList = this.removeItem(diceList, catched);
this.diceList = newDiceList.slice(0); // copy new list to the dice list
this.refreshPlayField();
var allDone = _.every(this.players.dicesThrown, function(element) {
return element == this.settings.maxThrownCount;
});
if ( this.diceList.length == 0 && allDone ){
this.checkGameOver();
}
}
else {
// nothing catched
// check if game is over? if yes, who is the winner?
if ( player.dicesThrown >= this.settings.maxThrownCount )
{
this.checkGameOver();
return;
}
}
this.nextPlayer(); // change to next player
},
removeItem: function(array, id) {
// remove dice from list
return _.reject(array, function(item) {
//console.log(item, id, item===id);
return item === id; // or some complex logic
});
},
refreshPlayField: function() {
var $field = this.$playField,
$row = $('<p/>');
$field.empty();
$.each(this.diceList, function(index, item) {
console.log(index, item);
$row.text(item.player.name + ' - threw dice: ' +item.diceValue)
$field.append($row.clone());
});
},
showGameInfo: function(message, keep) {
var $info = this.$gameInfo;
$info.html(message);
// show info with jQuery animation
$info
.stop()
.animate({opacity:1}, 'fast');
if ( !keep ) { // don't auto hidde --> required for game over
$info
.delay(2000) // display time of message
.animate({opacity:0},'fast');
}
},
hideGameInfo: function() {
// required to hide gameover message
this.$gameInfo.stop()
.animate({opacity:0}, 'fast'); // also stop every animation if any is active
},
throwDice: function() {
var player = this.getActivePlayer();
player.dice.threw.dispatch(Math.floor(Math.random()*6+1));
},
catchDice: function() {
console.log('catch dice method');
var player = this.getActivePlayer();
player.dice.catched.dispatch();
}
}
$(function() {
// start game after DOM ready
var game = new DiceGame();
});
.playerInfo {
position: absolute;
top: 0px;
right: 10px;
border: 1px solid black;
width: 200px;
}
#gameInfo {
opacity: 0;
margin: 0 auto;
color: red;
text-align: center;
width: 300px;
height: 100px;
/* center div horizontally and vertically */
position:absolute;
left:50%;
top:50%;
margin:-50px 0 0 -150px;
border: 0px solid black;
background-color: #FAFFBF;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore.js"></script>
<script src="https://cdn.rawgit.com/millermedeiros/js-signals/master/dist/signals.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="newGame">New Game</button>
<button id="addPlayer">New Player</button>
<!-- <button id="changePlayer">Change player</button> -->
<button id="throw">Throw dice</button>
<button id="catch">Catch dice</button>
<div class="playerInfo">
Active player: <span id="activePlayer"></span><br/>
Score: <span id="activePlayerScore"></span>
</div>
<div id="gameInfo"></div>
<div id="playField"></div>