347 lines
12 KiB
JavaScript
347 lines
12 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 title = generateElement(
|
|
{element: "h1", id: "title", textContent: "Tic Tac Toe"});
|
|
|
|
const player1NameLabel = generateElement(
|
|
{element: "label", _for: "p1name", textContent: "Player 1 name"});
|
|
const player1Name = generateElement(
|
|
{element: "input", type: "text", name: "p1name", id: "p1name", required: true});
|
|
|
|
const player2NameLabel = generateElement(
|
|
{element: "label", _for: "p2name", textContent: "Player 2 name"});
|
|
const player2Name = generateElement(
|
|
{element: "input", type: "text", name: "p2name", id: "p2name", required: true});
|
|
|
|
|
|
const markerInfo = generateElement(
|
|
{element: "label", textContent: "Marker for player 1:"});
|
|
|
|
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 markerX = generateElement(
|
|
{element: "input", type: "radio", name: "marker", value: "X", id: "mx"});
|
|
const markerXLabel = generateElement(
|
|
{element: "label", _for: "mx", textContent: "X"});
|
|
|
|
const markerInfoAddition = generateElement(
|
|
{element: "label", innerText: "\n(other one will go to player 2)"});
|
|
|
|
|
|
const firstInfo = generateElement(
|
|
{element: "label", textContent: "Who goes first?"});
|
|
|
|
const firstPlayer1 = generateElement(
|
|
{element: "input", type: "radio", name: "first", value: "1", id: "fp1", checked: true, required: true});
|
|
const firstPlayer1Label = generateElement(
|
|
{element: "label", _for: "fp1", textContent: "1"});
|
|
|
|
const firstPlayer2 = generateElement(
|
|
{element: "input", type: "radio", name: "first", value: "2", id: "fp2"});
|
|
const firstPlayer2Label = generateElement(
|
|
{element: "label", _for: "fp2", textContent: "2"});
|
|
|
|
const submit = generateElement(
|
|
{element: "button", type: "submit", textContent: "Save"});
|
|
|
|
form.append(
|
|
title,
|
|
player1NameLabel, player1Name,
|
|
player2NameLabel, player2Name,
|
|
markerInfo,
|
|
markerO, markerOLabel,
|
|
markerX, markerXLabel,
|
|
markerInfoAddition,
|
|
document.createElement("br"),
|
|
firstInfo,
|
|
firstPlayer1, firstPlayer1Label,
|
|
firstPlayer2, firstPlayer2Label,
|
|
submit,
|
|
);
|
|
|
|
return form;
|
|
}
|
|
|
|
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",
|
|
},
|
|
}, vals[3])
|
|
}
|
|
|
|
(function popupStartInput() {
|
|
const {popup, popupContent} = generatePopup(false);
|
|
const form = generateForm();
|
|
popupContent.append(form);
|
|
form.addEventListener("submit", function(event) {getFormOutput(event, popup)});
|
|
})()
|
|
|
|
const game = function(playersInput, first) {
|
|
const mainGameDiv = document.querySelector("#main-game");
|
|
const infoDiv = document.querySelector("#info");
|
|
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 updateInfo() {
|
|
const player1Info = document.querySelector("#p1info");
|
|
player1Info.textContent =
|
|
`1) ${players.player1.name} (${players.player1.marker}) - ${players.player1.points} points`;
|
|
|
|
const player2Info = document.querySelector("#p2info");
|
|
player2Info.textContent =
|
|
`2) ${players.player2.name} (${players.player2.marker}) - ${players.player2.points} points`;
|
|
|
|
const playerTurnInfo = document.querySelector("#pturn");
|
|
playerTurnInfo.textContent =
|
|
`${activePlayer.number}) ${activePlayer.player.name} (${activePlayer.player.marker})`;
|
|
|
|
console.log(activePlayer.number);
|
|
}
|
|
|
|
// -----------------
|
|
|
|
|
|
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;
|
|
this.player == players.player1
|
|
? this.number = 1
|
|
: this.number = 2;
|
|
},
|
|
set(player) {
|
|
if (player instanceof Player) {
|
|
this.player = player;
|
|
this.player == players.player1
|
|
? this.number = 1
|
|
: this.number = 2;
|
|
} 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");
|
|
}
|
|
}
|
|
|
|
// -----------------
|
|
|
|
function setupButtons() {
|
|
const resetPointsBtn = document.querySelector("#reset-points");
|
|
const resetEverythingBtn = document.querySelector("#reset-everything");
|
|
|
|
resetPointsBtn.addEventListener("click", () => {
|
|
gameboard.fill(null);
|
|
players.player1.points = 0;
|
|
players.player2.points = 0;
|
|
updateInfo();
|
|
displayController();
|
|
})
|
|
|
|
resetEverythingBtn.addEventListener("click", () => {
|
|
if(confirm("For sure?")) {
|
|
window.location.reload();
|
|
}
|
|
})
|
|
}
|
|
|
|
// -----------------
|
|
|
|
(function initializeLaunch() {
|
|
pubsub.subscribe("fieldChange", displayController);
|
|
pubsub.subscribe("fieldChange", checkWin);
|
|
pubsub.subscribe("continueGame", () => {activePlayer.change(); updateInfo()});;
|
|
// pubsub.subscribe("continueGame", );
|
|
// pubsub.subscribe("fieldChange", updateInfo);
|
|
pubsub.subscribe("draw", popupDraw);
|
|
pubsub.subscribe("winTrue", popupWin);
|
|
pubsub.subscribe("draw", () => {gameboard.fill(null);})
|
|
pubsub.subscribe("winTrue", () => {gameboard.fill(null);})
|
|
activePlayer.set(
|
|
first == "1" ? players.player1 : players.player2
|
|
)
|
|
displayController();
|
|
updateInfo();
|
|
setupButtons();
|
|
})();
|
|
}
|
|
})() |