From 87be725167c3ca3162ba42f80466cf791151ea23 Mon Sep 17 00:00:00 2001 From: Smig <89040888+smiggiddy@users.noreply.github.com> Date: Thu, 14 Dec 2023 18:37:25 -0500 Subject: [PATCH] Realtictactoe (#8) * feat: setup initial game methods * feat: add update position method * feat: created basic prompt for input * feat: cli game loop complete * feat: boiler plate html added * feat: added gameplay * feat: added game evaluation * feat: added grid and basic styling * feat: game functionality added * feat: project complete --- tictactoe/css/style.css | 86 ++++++++++++ tictactoe/index.html | 35 +++++ tictactoe/js/main.js | 291 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 412 insertions(+) create mode 100644 tictactoe/css/style.css create mode 100644 tictactoe/index.html create mode 100644 tictactoe/js/main.js diff --git a/tictactoe/css/style.css b/tictactoe/css/style.css new file mode 100644 index 0000000..a305a85 --- /dev/null +++ b/tictactoe/css/style.css @@ -0,0 +1,86 @@ +:root { + font-size: 32px; + font-family: 'Roboto', sans-serif; + --dark-color: #607274; + --light-color: #FAEED1; + --gray-color: #F4F4F2; + --light-grey-color: #E8E8E8; +} + +body,html { + min-width: 100vw; + margin: 0; + padding: 0; +} + +header { + display: flex; + min-width: 100vw; + justify-content: center; + align-content: center; + background-color: var(--dark-color); + color: var(--gray-color); +} + + +header h1 { + font-size: 2rem; +} + + +.container { + display: flex; + flex-direction: column; + align-items: center; + background-color: var(--light-grey-color); + height: 100vh; +} + +.content { + display: flex; + justify-content: space-between; + align-content: center; + flex-direction: column; + gap: 20px +} + +.game-status { + display: flex; + justify-content: center; + align-content: center; +} + +.content>.game-area { + display: grid; + grid-area: 1 / 1 / 4 / 4; + grid-template-rows: repeat(3, 150px); + grid-template-columns: repeat(3, 150px); + justify-items: center; + align-items: center; + border: solid; +} + +.block { + font-family: 'Silkscreen', sans-serif; + font-weight: 700; + height: 150px; + width: 150px; + display: flex; + justify-content: center; + align-items: center; + position: relative; + border: solid; + font-size: 3rem; +} + +.block:hover { + cursor: pointer; +} + +.btn { + padding: 16px 20px; + font-size: 0.5rem; + width: 200px; + align-self: center; + cursor: pointer; +} diff --git a/tictactoe/index.html b/tictactoe/index.html new file mode 100644 index 0000000..c858046 --- /dev/null +++ b/tictactoe/index.html @@ -0,0 +1,35 @@ + + + + + + + + + + Tic-Tac-Toe + + +
+
+
+

Tic-Tac-Toe

+
+
+
+
+
+ +
+
+ +
+
+
+ +
+ + + diff --git a/tictactoe/js/main.js b/tictactoe/js/main.js new file mode 100644 index 0000000..70c4441 --- /dev/null +++ b/tictactoe/js/main.js @@ -0,0 +1,291 @@ +const tictactoeBoard = (function() { + + let gameBoard = new Array(["", "", ""], ["", "", ""], ["", "", ""]); + + const getGameBoard = () => gameBoard; + // const printGameBoard = () => console.log(gameBoard[0] + "\n" + gameBoard[1] + "\n" + gameBoard[2]); + + const resetGameBoard = () => { + gameBoard.forEach(item => { + item[0] = ''; + item[1] = ''; + item[2] = ''; + }) + } + + const posititionAvailable = (position) => { + switch (position) { + case 1: + return isEmpty(gameBoard[0][0]); + case 2: + return isEmpty(gameBoard[0][1]); + case 3: + return isEmpty(gameBoard[0][2]); + case 4: + return isEmpty(gameBoard[1][0]); + case 5: + return isEmpty(gameBoard[1][1]); + case 6: + return isEmpty(gameBoard[1][2]); + case 7: + return isEmpty(gameBoard[2][0]); + case 8: + return isEmpty(gameBoard[2][1]); + case 9: + return isEmpty(gameBoard[2][2]); + default: + Alert('Must enter a number 1 - 9'); + break; + } + } + + const isEmpty = position => position === ""; + + const placeOnBoard = (position, marker) => { + // places marker on the gameboard + marker = marker.getValue(); // get value from object + + switch (position) { + case 1: + gameBoard[0][0] = marker; + break; + case 2: + gameBoard[0][1] = marker; + break; + case 3: + gameBoard[0][2] = marker; + break; + case 4: + gameBoard[1][0] = marker; + break; + case 5: + gameBoard[1][1] = marker; + break; + case 6: + gameBoard[1][2] = marker; + break; + case 7: + gameBoard[2][0] = marker; + break; + case 8: + gameBoard[2][1] = marker; + break; + case 9: + gameBoard[2][2] = marker; + break; + default: + break; + } + } + + return { + resetGameBoard, + // printGameBoard, + getGameBoard, + placeOnBoard, + posititionAvailable + }; +})(); + + +const playerInfo = (function() { + class Player { + constructor(name, piece) { + this.piece = piece; + this.name = name; + } + } + + const player = (name, piece) => { + return new Player(name, piece); + }; + + return { player } +})(); + + +function block() { + value = "-"; + const addToken = player => { + // player is a player info object + value = player.piece; + }; + + const getValue = () => value; + + return { + addToken, + getValue + }; +}; + +const gameController = (() => { + // Controls the overall flow of the game + let players = [ + playerInfo.player('Player 1', 'X'), + playerInfo.player('Player 2', 'O') + ] + + let gameOver; + let xTurn = true; // True = X's turn, False = O's turn + let round = 0; // 9 Total Rounds for Tic Tac Toe + + const resetGame = () => { + round = 0; + xTurn = true; + gameOver = false; + tictactoeBoard.resetGameBoard(); + } + + const gameStatus = () => gameOver; + const gameRound = () => round; + + const switchPlayerTurn = () => { + xTurn = !xTurn; + } + + const playRound = position => { + let marker = new block() + let positionOpen = tictactoeBoard.posititionAvailable(position); + + if (round < 10 && positionOpen) { + + let player = xTurn ? players[0] : players[1]; + marker.addToken(player); + tictactoeBoard.placeOnBoard(position, marker); // position on board + + // Check for Winner + gameOver = evalGameOutcome(tictactoeBoard.getGameBoard()); + + if (gameOver) { + console.log(`${player.name}: ${player.piece} won!`) + return + } + switchPlayerTurn(); + + } else { + return + } + round += 1; + } + + const evalGameOutcome = gameBoard => { + // create a new array of the vertical indexes in the game board + let vertArray = []; + gameBoard.forEach((_, index) => vertArray.push(gameBoard.map(e => e[index]))); + + // create an array of diagnal pieces + let diagArray = [ + [gameBoard[0][0], gameBoard[1][1], gameBoard[2][2]], + [gameBoard[0, 2], gameBoard[1][1], gameBoard[2][0]] + ]; + + let checkGameBoard = [gameBoard, diagArray, vertArray]; + for (i = 0; i < 3; i++) { + let outcome = _evalGameOutcome(checkGameBoard[i]); + if (outcome) { + return true; + }; + }; + return false; + }; + + const _evalGameOutcome = arr => { + // Checks if array values are equal to determine winner + let isWinner = checkArr => checkArr.reduce(function(a, b) { return a === b ? a : false; }); + + const outcome = arr.find(element => { + let result = isWinner(element); + if (result != false) { + return true; + } else { + return false; + } + }); + return outcome; + }; + + return { playRound, resetGame, gameStatus, gameRound } +})(); + + +const screenController = (() => { + const contentDiv = document.querySelector('.content') + const gameDiv = document.querySelector('.game-area'); + const gameStatus = document.querySelector('.game-status') + const game = tictactoeBoard.getGameBoard(); + const resetButton = document.createElement('button'); + + resetButton.classList.add(['btn']); + resetButton.textContent = 'New Game'; + contentDiv.appendChild(resetButton); + + const updateScreen = () => { + status() + displayBoard(); + } + + const status = () => { + let pTags = gameStatus.querySelectorAll('p'); + if (pTags) pTags.forEach(e => e.remove()); + + let message = document.createElement('p'); + let gameOn = gameController.gameStatus() ? "Play again?" : ""; + let round = gameController.gameRound(); + + if (round <= 9 && gameOn) { + message.textContent = gameOn; + } else if (round >= 9 && !gameOn) { + message.textContent = "Draw, play again?"; + } + + gameStatus.appendChild(message); + + } + + + const displayBoard = () => { + // Check if someone won the game + + let count = 0; // This is for the data blocks + gameDiv.querySelectorAll('.block').forEach(e => e.remove()); + game.forEach((e) => { + e.forEach((element) => { + count += 1; + const block = document.createElement('div'); + block.classList.add('block'); + block.setAttribute('data-block', count); + block.textContent = element; + block.addEventListener('click', clickHandlerBoard); + gameDiv.appendChild(block); + }); + }); + } + + + + function clickHandlerBoard(e) { + const selectedBlock = e.target.dataset.block; + const empty = e.target.textContent; + const gameStatus = gameController.gameStatus(); + + if (!selectedBlock || empty !== "" || gameStatus) return; + + gameController.playRound(Number(selectedBlock)); + updateScreen(); + }; + + function clickResetButton() { + gameController.resetGame(); + status(); + updateScreen(); + } + + resetButton.addEventListener('click', clickResetButton); + + + // Initial Load + updateScreen(); +})(); + +