odin-tic-tac-toe/script.js

242 lines
8.8 KiB
JavaScript

"use strict";
(function() {
function generateElement(args) {
const elementOutput = document.createElement(args.element);
for (let arg in args) {
if (typeof arg !== "undefined") {
if (arg == "_for") {
elementOutput.setAttribute("for", args[arg]);
} else {
elementOutput[arg] = args[arg];
}
}
}
return elementOutput;
}
function generateForm() {
const form = document.createElement("form");
const player1NameLabel = generateElement({element:"label",_for:"p1name",textContent:"Player 1 name"});
const player1Name = generateElement({element:"input",type:"text",name:"p1name",placeholder:"p1name",id:"p1name"});
const markerX = generateElement({element:"input",type:"radio",name:"marker",value:"X",id:"mx"});
const markerXLabel = generateElement({element:"label",_for:"mx",textContent:"X"});
const markerO = generateElement({element:"input",type:"radio",name:"marker",value:"O",id:"mo",checked:true,required:true});
const markerOLabel = generateElement({element:"label",_for:"mo",textContent:"O"});
const player2NameLabel = generateElement({element:"label",_for:"p2name",textContent:"Player 2 name"});
const player2Name = generateElement({element:"input",type:"text",name:"p2name",placeholder:"p2name",id:"p2name"});
const submit = generateElement({element:"button",type:"submit",textContent:"Save"});
form.append(player1NameLabel, player1Name, player2NameLabel, player2Name,markerO,markerOLabel,markerX,markerXLabel,submit);
return {form, player1Name, player2Name, markerX, markerXLabel, markerO, markerOLabel, submit};
}
function addDismissivePopup(popup) {
function dismissPopup() {
popup.remove();
}
popup.addEventListener("click", function(event) {
if (this !== event.target) return;
dismissPopup();
}, false);
function dismissPopupKey(event) {
if (event.key.toLowerCase() == "escape") {
popup.remove();
document.body.removeEventListener("keydown", dismissPopupKey);
}
}
const dismissBtn = document.createElement("button");
dismissBtn.setAttribute("type", "button");
dismissBtn.classList.add("dismiss-button");
dismissBtn.textContent = "Dismiss";
dismissBtn.addEventListener("click", dismissPopup);
document.body.addEventListener("keydown", dismissPopupKey);
return dismissBtn;
}
function generatePopup(dismissive) {
const popup = document.createElement("div");
popup.classList.add("popup");
const popupContent = document.createElement("div");
popupContent.classList.add("popup-content");
popup.append(popupContent);
document.body.append(popup);
if (dismissive) {
const dismissBtn = addDismissivePopup(popup, popupContent);
return {popup, popupContent, dismissBtn};
}
return {popup, popupContent};
}
function getFormOutput(event, popup) {
event.preventDefault();
const form = event.target;
const formFetch = new FormData(form);
let vals = [];
for (let value of formFetch.values()) {
vals.push(value);
}
popup.remove();
game({
player1: {
name: vals[0],
marker: vals[2],
},
player2: {
name: vals[1],
marker: vals[2] == "O" ? "X" : "O",
},
})
}
(function popupStartInput() {
const {popup, popupContent} = generatePopup(false);
const {form, player1Name, player2Name,markerX,markerO,submit} = generateForm();
popupContent.append(form);
form.addEventListener("submit", function(event) {getFormOutput(event, popup)});
})()
const game = function(playersInput) {
const mainGameDiv = document.querySelector("#main-game");
let gameboard = new Array(9);
gameboard.fill(null);
// -----------------
function checkWin() {
const combinations = [
"123", "456", "789",
"147", "258", "369",
"159", "357",
];
let combinationsValidate = {};
const allEqualInArray = arr => arr.every( v => v === arr[0] )
const player = activePlayer.player;
let win = false;
combinations.forEach(combination => {
combinationsValidate[combination] = [];
combination.split('').forEach(box => {
combinationsValidate[combination].push(gameboard[+box - 1] == player.marker);
})
if (allEqualInArray(combinationsValidate[combination]) && combinationsValidate[combination][0]) {
player.addPoint();
console.log(`${JSON.stringify({name:player.name, marker:player.marker, points:player.points})} won`);
pubsub.publish("winTrue");
return;
}
});
if (!win) {
if (gameboard.find(field => field === null) === null) {
pubsub.publish("continueGame");
} else {
pubsub.publish("draw");
}
}
}
// -----------------
function popupWin() {
const {popup, popupContent, dismissBtn} = generatePopup(true);
popupContent.textContent = `${activePlayer.player.name} (${activePlayer.player.marker}) won!`;
popupContent.append(dismissBtn);
}
function popupDraw() {
const {popup, popupContent, dismissBtn} = generatePopup(true);
popupContent.textContent = `It's a draw!`;
popupContent.append(dismissBtn);
}
// -----------------
function clearController() {
while(mainGameDiv.lastElementChild) {
mainGameDiv.lastElementChild.remove();
}
}
function displayController() {
clearController();
let boxes = [];
for (let i = 0; i < 9; i++) {
let boxDiv = document.createElement("div");
boxDiv.classList.add("box");
boxDiv.setAttribute("data-id", i);
boxDiv.textContent = gameboard[boxDiv.getAttribute("data-id")];
boxDiv.addEventListener("click", function(event) {
changeField(boxDiv.getAttribute("data-id"));
});
boxes.push(boxDiv);
}
boxes.forEach(box => mainGameDiv.appendChild(box));
}
// -----------------
class Player {
constructor(name, marker) {
this.name = name;
this.marker = marker;
this.points = 0;
}
changeName(newName) {
this.name = newName;
}
changeMarker(newMarker) {
this.marker = newMarker;
}
addPoint() {
this.points++;
}
}
let players = {
player1: new Player(playersInput.player1.name, playersInput.player1.marker),
player2: new Player(playersInput.player2.name, playersInput.player2.marker),
}
let activePlayer = Object.create({
change() {
this.player == players.player1
? this.player = players.player2
: this.player = players.player1;
},
set(player) {
if (player instanceof Player) {
this.player = player;
} else {
throw new Error("No such player exists");
}
}
});
// -----------------
function changeField(field) {
if (gameboard[field] === null) {
gameboard[field] = activePlayer.player.marker;
pubsub.publish("fieldChange");
} else if (gameboard[field] === undefined) {
console.warn("No such field exists");
} else {
console.warn("Value already set");
}
}
// -----------------
pubsub.subscribe("fieldChange", displayController);
pubsub.subscribe("fieldChange", checkWin);
pubsub.subscribe("continueGame", () => {activePlayer.change()});
pubsub.subscribe("draw", popupDraw);
pubsub.subscribe("winTrue", popupWin);
pubsub.subscribe("draw", () => {gameboard.fill(null);})
pubsub.subscribe("winTrue", () => {gameboard.fill(null);})
displayController();
activePlayer.change()
}
})()