javascript implementation of Zilch game
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

489 lines
11 KiB

/**
* Game (Model + Controller)
*/
function Game(Interface) {
let self = this;
// get interface
self.Interface = new Interface;
// register event callbacks
self.Interface.on("restart", self.restart.bind(this));
self.Interface.on("takePoints", self.takePoints.bind(this));
self.Interface.on("addPoints", self.addPoints.bind(this));
self.Interface.on("rollDices", self.rollDices.bind(this));
self.Interface.on("toggleDice", self.toggleDice.bind(this));
self.setup();
}
/**
* Restart game (reset)
*/
Game.prototype.restart = function () {
this.Interface.setup();
this.setup();
};
/**
* Setup new game
*/
Game.prototype.setup = function () {
let self = this;
self.player = {
score: 0,
zilch: 0
};
self.cpu = {
score: 0,
zilch: 0
};
self.dices = []
for (let i = 0; i < 6; i++) {
let dice = {};
dice.value = this.random(6);
dice.disabled = true;
self.dices[i] = dice;
}
self.history = [];
self.cpuStarts = self.random(2);
self.playing = !self.cpuStarts;
self.points = 0;
self.animationTime = 500;
self.messageTime = 1500;
self.cpuSpeed = 1500;
self.Interface.setPlaying(self.playing);
self.Interface.setPoints(self.points);
self.Interface.setPlayer(self.player);
self.Interface.setCpu(self.cpu);
self.Interface.setDices(self.dices);
if (self.cpuStarts) {
self.Interface.disableRestart(true);
self.Interface.showMessage("CPU starts!", self.messageTime, function () {
setTimeout(function () {
self.rollDices();
}, self.cpuSpeed);
});
} else {
self.Interface.showMessage("Player starts!", 0, function () {
self.Interface.disableRestart(false);
self.Interface.disableRollDices(false);
});
}
};
/**
* Random helper for integer numbers
*/
Game.prototype.random = function (int) {
return Math.floor((Math.random() * int));
};
/**
* Roll dices
*/
Game.prototype.rollDices = function (all) {
let self = this;
self.Interface.clearMessage();
if (self.newRound) {
self.points = 0;
self.Interface.setPoints(self.points);
self.newRound = false;
}
let rollCount = 0;
for (let i = 0; i < 6; i++) {
self.dices[i] = self.dices[i] || {};
let dice = self.dices[i];
if (all || !dice.disabled) {
dice.value = this.random(6);
if (all) {
dice.disabled = false;
}
dice.selected = false;
rollCount++;
}
}
self.Interface.setDices(self.dices);
if (rollCount == 0) {
self.rollDices(true);
} else if (self.calculatePoints(true) == 0) {
self.Interface.animateDices(self.dices, self.animationTime, function () {
if (self.playing) {
self.player.zilch++;
let history = {};
history['player'] = 'Zilch';
self.history.push(history);
self.points = 0;
if (self.player.zilch > 2) {
if (self.player.score < 500) {
self.player.score = 0;
} else {
self.player.score -= 500;
}
let history = {};
history['player'] = '-500';
self.history.push(history);
self.points = -500;
}
self.Interface.disableTakePoints(true);
self.Interface.disableRollDices(true);
self.Interface.setPoints(self.points);
self.Interface.setPlayer(self.player);
self.Interface.showMessage("Zilch!", self.messageTime, function () {
if (self.player.zilch > 2) {
self.player.zilch = 0;
self.Interface.setPlayer(self.player);
}
self.endRound();
});
} else {
self.cpu.zilch++;
let history = {};
history['cpu'] = 'Zilch';
self.history.push(history);
self.points = 0;
if (self.cpu.zilch > 2) {
if (self.cpu.score < 500) {
self.cpu.score = 0;
} else {
self.cpu.score -= 500;
}
let history = {};
history['cpu'] = '-500';
self.history.push(history);
self.points = -500;
}
self.Interface.disableTakePoints(true);
self.Interface.disableRollDices(true);
self.Interface.setPoints(self.points);
self.Interface.setCpu(self.cpu);
self.Interface.showMessage("Zilch!", self.messageTime, function () {
if (self.cpu.zilch > 2) {
self.cpu.zilch = 0;
self.Interface.setCpu(self.cpu);
}
self.endRound();
});
}
});
} else {
self.Interface.animateDices(self.dices, self.animationTime);
self.Interface.disableTakePoints(true);
self.Interface.disableRollDices(true);
if (!self.playing) {
self.cpuPlay();
}
}
};
/**
* Toggle dice selection
*/
Game.prototype.toggleDice = function (diceIndex) {
let self = this;
let dice = self.dices[diceIndex];
if (!dice || dice.disabled) {
console.error("This should not happen!")
return;
}
dice.selected = !dice.selected;
let points = self.calculatePoints();
let valid = true;
for (let i = 0; i < 6; i++) {
let toggleDice = self.dices[i];
if (toggleDice.selected && !toggleDice.disabled) {
toggleDice.selected = false;
let togglePoints = self.calculatePoints();
if (points > togglePoints) {
toggleDice.invalid = false;
} else if (togglePoints == points) {
toggleDice.invalid = true;
}
toggleDice.selected = true;
} else {
toggleDice.invalid = false;
}
valid &= !toggleDice.invalid;
}
if (valid && points > 0 && self.playing) {
self.Interface.disableRollDices(false);
} else {
self.Interface.disableRollDices(true);
}
if (valid && self.points + points >= 300 && self.playing) {
self.Interface.disableTakePoints(false);
} else {
self.Interface.disableTakePoints(true);
}
self.Interface.setDices(self.dices);
self.Interface.setPoints(self.points + points);
};
/**
* Calculate points on selected dices or all dices
*/
Game.prototype.calculatePoints = function (all) {
let self = this;
let result = [0, 0, 0, 0, 0, 0];
for (let i = 0; i < 6; i++) {
let dice = self.dices[i];
if ((all || dice.selected) && !dice.disabled) {
result[dice.value]++;
}
}
let straight = true;
let pairs = 0;
let triple1 = 0;
let triple2 = 0;
for (let i = 0; i < 6; i++) {
straight &= (result[i] == 1);
if (result[i] == 2) {
pairs++;
}
if (triple1 == 0 && result[i] > 2) {
triple1 = i + 1;
} else if (result[i] > 2) {
triple2 = i + 1;
}
}
let points = 0;
if (straight) {
points += 1500;
} else if (pairs == 3) {
points += 1500;
} else if (triple1) {
let triple1Points = triple1 * (triple1 == 1 ? 1000 : 100);
for (let i = 0; i < result[triple1 - 1] - 3; i++) {
triple1Points *= 2;
}
points += triple1Points;
if (triple2) {
points += triple2 * (triple2 == 1 ? 1000 : 100);
}
}
// left Ones
if (!straight && pairs < 3 && triple1 != 1 && triple2 != 1) {
points += result[0] * 100;
}
// left Fives
if (!straight && pairs < 3 && triple1 != 5 && triple2 != 5) {
points += result[4] * 50;
}
return points;
}
/**
* Add points for current player
*/
Game.prototype.addPoints = function () {
let self = this;
self.points += self.calculatePoints();
for (let i = 0; i < 6; i++) {
let dice = self.dices[i];
if (dice.selected) {
dice.selected = false;
dice.disabled = true;
}
}
self.Interface.setDices(self.dices);
self.Interface.setPoints(self.points);
};
/**
* Take points and end round
*/
Game.prototype.takePoints = function () {
let self = this;
self.addPoints();
if (self.playing) {
self.player.score += self.points;
self.player.zilch = 0;
self.Interface.setPlayer(self.player);
let history = {};
history['player'] = self.points;
self.history.push(history);
} else {
self.cpu.score += self.points;
self.cpu.zilch = 0;
self.Interface.setCpu(self.cpu);
let history = {};
history['cpu'] = self.points;
self.history.push(history);
}
self.Interface.disableTakePoints(true);
self.Interface.disableRollDices(true);
self.Interface.setPoints(self.points);
self.endRound();
};
/**
* End round for current player
*/
Game.prototype.endRound = function () {
let self = this;
self.newRound = true;
for (let i = 0; i < 6; i++) {
let dice = self.dices[i];
if (dice.disabled) {
dice.selected = true;
} else {
dice.disabled = true;
}
}
self.Interface.disableTakePoints(true);
self.Interface.disableRollDices(true);
self.Interface.setDices(self.dices);
self.Interface.setPoints(self.points);
self.Interface.setPlayer(self.player);
self.Interface.setCpu(self.cpu);
// check score
let checkScore = self.playing && self.cpuStarts || !self.playing && !self.cpuStarts;
if (checkScore && self.player.score >= 10000 && self.player.score > self.cpu.score) {
self.Interface.disableRestart(false);
self.Interface.showMessage("Player wins!");
} else if (checkScore && self.cpu.score >= 10000 && self.cpu.score > self.player.score) {
self.Interface.disableRestart(false);
self.Interface.showMessage("CPU wins!");
} else if (self.player.score >= 10000 && self.player.score == self.cpu.score) {
self.Interface.disableRestart(false);
self.Interface.showMessage("Remi!");
} else {
self.playing = !self.playing;
self.Interface.setPlaying(self.playing);
// continue
if (self.playing) {
self.Interface.disableRollDices(false);
self.Interface.disableRestart(false);
self.Interface.showMessage("Player's turn!");
} else {
self.Interface.showMessage("CPU's turn!", self.messageTime, function () {
if (!self.playing) {
setTimeout(function () {
self.rollDices();
}, self.cpuspeed);
}
});
}
}
}
/**
* CPU playing logic
*/
Game.prototype.cpuPlay = function () {
let self = this;
self.Interface.disableRestart(true);
setTimeout(function () {
// first select all available dices
for (let i = 0; i < 6; i++) {
let dice = self.dices[i];
if (!dice.disabled) {
self.toggleDice(i);
}
}
// check if dice gains points
for (let i = 0; i < 6; i++) {
let dice = self.dices[i];
let tmpPoints = self.calculatePoints();
if (!dice.disabled) {
self.toggleDice(i);
if (self.calculatePoints() < tmpPoints) {
self.toggleDice(i);
}
}
}
// count free dices
let freeDices = 0;
for (let i = 0; i < 6; i++) {
let dice = self.dices[i];
if (!dice.disabled && !dice.selected) {
freeDices++;
}
}
setTimeout(function () {
let cpuPoints = self.points + self.calculatePoints();
// strategy: end round if points >= 300 and less than 4 dices left and not loosing
if (cpuPoints >= 300 && freeDices < 4 && freeDices > 0 && (self.player.score < 10000 || (self.cpu.score + cpuPoints) > self.player.score)) {
self.takePoints();
} else {
self.addPoints();
self.rollDices();
}
}, self.cpuSpeed);
}, 500);
}
// create new game
let game = new Game(Interface);