RosettaCodeData/Task/Mastermind/JavaScript/mastermind.js

233 lines
6.2 KiB
JavaScript

class Mastermind {
constructor() {
this.colorsCnt;
this.rptColors;
this.codeLen;
this.guessCnt;
this.guesses;
this.code;
this.selected;
this.game_over;
this.clear = (el) => {
while (el.hasChildNodes()) {
el.removeChild(el.firstChild);
}
};
this.colors = ["🤡", "👹", "👺", "👻", "👽", "👾", "🤖", "🐵", "🐭",
"🐸", "🎃", "🤠", "☠️", "🦄", "🦇", "🛸", "🎅", "👿", "🐲", "🦋"
];
}
newGame() {
this.selected = null;
this.guessCnt = parseInt(document.getElementById("gssCnt").value);
this.colorsCnt = parseInt(document.getElementById("clrCnt").value);
this.codeLen = parseInt(document.getElementById("codeLen").value);
if (this.codeLen > this.colorsCnt) {
document.getElementById("rptClr").selectedIndex = 1;
}
this.rptColors = document.getElementById("rptClr").value === "yes";
this.guesses = 0;
this.game_over = false;
const go = document.getElementById("gameover");
go.innerText = "";
go.style.visibility = "hidden";
this.clear(document.getElementById("code"));
this.buildPalette();
this.buildPlayField();
}
buildPalette() {
const pal = document.getElementById("palette"),
z = this.colorsCnt / 5,
h = Math.floor(z) != z ? Math.floor(z) + 1 : z;
this.clear(pal);
pal.style.height = `${44 * h + 3 * h}px`;
const clrs = [];
for (let c = 0; c < this.colorsCnt; c++) {
clrs.push(c);
const b = document.createElement("div");
b.className = "bucket";
b.clr = c;
b.innerText = this.colors[c];
b.addEventListener("click", () => {
this.palClick(b);
});
pal.appendChild(b);
}
this.code = [];
while (this.code.length < this.codeLen) {
const r = Math.floor(Math.random() * clrs.length);
this.code.push(clrs[r]);
if (!this.rptColors) {
clrs.splice(r, 1);
}
}
}
buildPlayField() {
const brd = document.getElementById("board");
this.clear(brd);
const w = 49 * this.codeLen + 7 * this.codeLen + 5;
brd.active = 0;
brd.style.width = `${w}px`;
document.querySelector(".column").style.width = `${w + 20}px`;
this.addGuessLine(brd);
}
addGuessLine(brd) {
const z = document.createElement("div");
z.style.clear = "both";
brd.appendChild(z);
brd.active += 10;
for (let c = 0; c < this.codeLen; c++) {
const d = document.createElement("div");
d.className = "bucket";
d.id = `brd${brd.active+ c}`;
d.clr = -1;
d.addEventListener("click", () => {
this.playClick(d);
})
brd.appendChild(d);
}
}
palClick(bucket) {
if (this.game_over) return;
if (null === this.selected) {
bucket.classList.add("selected");
this.selected = bucket;
return;
}
if (this.selected !== bucket) {
this.selected.classList.remove("selected");
bucket.classList.add("selected");
this.selected = bucket;
return;
}
this.selected.classList.remove("selected");
this.selected = null;
}
vibrate() {
const brd = document.getElementById("board");
let timerCnt = 0;
const exp = setInterval(() => {
if ((timerCnt++) > 60) {
clearInterval(exp);
brd.style.top = "0px";
brd.style.left = "0px";
}
let x = Math.random() * 4,
y = Math.random() * 4;
if (Math.random() < .5) x = -x;
if (Math.random() < .5) y = -y;
brd.style.top = y + "px";
brd.style.left = x + "px";
}, 10);
}
playClick(bucket) {
if (this.game_over) return;
if (this.selected) {
bucket.innerText = this.selected.innerText;
bucket.clr = this.selected.clr;
} else {
this.vibrate();
}
}
check() {
if (this.game_over) return;
let code = [];
const brd = document.getElementById("board");
for (let b = 0; b < this.codeLen; b++) {
const h = document.getElementById(`brd${brd.active + b}`).clr;
if (h < 0) {
this.vibrate();
return;
}
code.push(h);
}
this.guesses++;
if (this.compareCode(code)) {
this.gameOver(true);
return;
}
if (this.guesses >= this.guessCnt) {
this.gameOver(false);
return;
}
this.addGuessLine(brd);
}
compareCode(code) {
let black = 0,
white = 0,
b_match = new Array(this.codeLen).fill(false),
w_match = new Array(this.codeLen).fill(false);
for (let i = 0; i < this.codeLen; i++) {
if (code[i] === this.code[i]) {
b_match[i] = true;
w_match[i] = true;
black++;
}
}
for (let i = 0; i < this.codeLen; i++) {
if (b_match[i]) continue;
for (let j = 0; j < this.codeLen; j++) {
if (i == j || w_match[j]) continue;
if (code[i] === this.code[j]) {
w_match[j] = true;
white++;
break;
}
}
}
const brd = document.getElementById("board");
let d;
for (let i = 0; i < black; i++) {
d = document.createElement("div");
d.className = "pin";
d.style.backgroundColor = "#a00";
brd.appendChild(d);
}
for (let i = 0; i < white; i++) {
d = document.createElement("div");
d.className = "pin";
d.style.backgroundColor = "#eee";
brd.appendChild(d);
}
return (black == this.codeLen);
}
gameOver(win) {
if (this.game_over) return;
this.game_over = true;
const cd = document.getElementById("code");
for (let c = 0; c < this.codeLen; c++) {
const d = document.createElement("div");
d.className = "bucket";
d.innerText = this.colors[this.code[c]];
cd.appendChild(d);
}
const go = document.getElementById("gameover");
go.style.visibility = "visible";
go.innerText = win ? "GREAT!" : "YOU FAILED!";
const i = setInterval(() => {
go.style.visibility = "hidden";
clearInterval(i);
}, 3000);
}
}
const mm = new Mastermind();
document.getElementById("newGame").addEventListener("click", () => {
mm.newGame()
});
document.getElementById("giveUp").addEventListener("click", () => {
mm.gameOver();
});
document.getElementById("check").addEventListener("click", () => {
mm.check()
});