Mastermind: Difference between revisions

9,118 bytes added ,  4 years ago
no edit summary
(julia example)
No edit summary
Line 591:
</pre>
 
=={{header|Javascript}}==
<lang 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()
});
</lang>
 
To test you'll need a HTML file
<pre>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="./css/style.css" type="text/css">
<title>Mastermind</title>
</head>
<body>
<div id="gameover"></div>
<div class="column">
<div id="board" style="position: relative"></div>
<div style="clear: both"> </div>
<button id="check" style="margin-top:20px">Check!</button>
<button id="giveUp">Give up!</button>
<div id="code" style="margin-top: 40px"></div>
</div>
<div class="columnS">
<div id="ctrls">
<label for="clrCnt">Colors count:</label>
<input type="number" id="clrCnt" max="20" min="2" value="6"></input>
<br />
<label for="codeLen">Code length:</label>
<input type="number" id="codeLen" max="10" min="4" value="4"></input>
<br />
<label for="gssCnt">Guesses count:</label>
<input type="number" id="gssCnt" max="20" min="7" value="12"></input>
<br />
<label for="rptClr">Repeat colors:</label>
<select id="rptClr">
<option value="no">No</option>
<option value="yes">Yes</option>
</select>
<button id="newGame" style="width: 100%">New game</button>
</div>
<div id="palette"></div>
</div>
<script src="./src/index.js" type="module"></script>
</body>
</html>
</pre>
 
And a CSS file
<pre>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
user-select: none;
}
body {
background-color: #222;
text-align: left
}
button {
width: 101px;
height: 26px;
background-color: #444;
color: #ddd;
border: 1px solid #333;
border-radius: 4px;
}
input,
select {
float: right;
width: 60px;
height: 24px;
margin-top: 6px;
font-size: 20px;
}
#palette {
margin-top: 40px;
width: 233px;
border-radius: 5px;
border: 1px solid #fff;
}
#ctrls {
border-radius: 5px;
border: 1px solid #fff;
padding: 10px;
font-size: 20px;
width: 233px;
line-height: 36px;
color: #fff;
}
#gameover {
position: absolute;
top: 90px;
left: 0;
font-size: 100px;
text-align: center;
color: rgb(248, 143, 4);
background: rgba(34, 34, 34, .8);
padding: 10px;
z-index: 999;
}
.column,
.columnS {
float: left;
width: 249px;
margin: 30px;
}
.columnS {
width: 300px;
margin-left: 0;
}
.bucket {
float: left;
width: 42px;
height: 42px;
line-height: 40px;
font-size: 26px;
border: 2px solid #fff;
border-radius: 3px;
margin: 2px;
cursor: pointer;
}
.selected {
border: 2px solid #d00;
}
.pin {
float: left;
width: 14px;
height: 14px;
border-radius: 50%;
margin: 2px;
}
</pre>
 
=={{header|Julia}}==