"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() } })()