233 lines
6.2 KiB
JavaScript
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()
|
|
});
|