From 890822f422470a7fcaa489e26c6390c7a6a3198b Mon Sep 17 00:00:00 2001 From: Isa696 Date: Fri, 1 Dec 2023 18:38:08 -0300 Subject: [PATCH] Tic Tac Toe JS vanilla made as practice, 2P mode & Vs cpu mode --- index.html | 29 ++++++++++ main.js | 128 +++++++++++++++++++++++++++++++++++++++++ style.css | 164 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 321 insertions(+) create mode 100644 index.html create mode 100644 main.js create mode 100644 style.css diff --git a/index.html b/index.html new file mode 100644 index 0000000..45f5aa4 --- /dev/null +++ b/index.html @@ -0,0 +1,29 @@ + + + + + + + Ta Te Ti + + +
+
+ +
+
+

Ta Te Ti

+ +
Jugaror X turno
+ +
+ +
+ +
+ + + + diff --git a/main.js b/main.js new file mode 100644 index 0000000..a36ab92 --- /dev/null +++ b/main.js @@ -0,0 +1,128 @@ +document.addEventListener('DOMContentLoaded', () => { + const gameModeCheckbox = document.querySelector('.checkbox-wrapper-25 input'); + const gameModeButton = document.getElementById('game-mode'); + + const board = document.getElementById('board'); + const status = document.getElementById('status'); + const cells = []; + + let currentPlayer = 'X'; + let winner = null; + let singlePlayerMode = false; + + function startSinglePlayerGame() { + singlePlayerMode = true; + resetGame(); + } + + function resetGame() { + currentPlayer = 'X'; + winner = null; + + // Limpiar el tablero y reiniciar las celdas + cells.forEach(cell => { + cell.textContent = ''; + cell.classList.remove('cell-winner'); + }); + + status.textContent = singlePlayerMode ? 'Tu turno "X"' : 'Turno "X"'; + + // Si es el modo de un solo jugador y es el turno de la CPU, que realice su movimiento + if (singlePlayerMode && currentPlayer === 'O') { + makeCPUMove(); + } + } + + function handleCellClick(event) { + const clickedCell = event.target; + const index = clickedCell.dataset.index; + + // Check if the cell is already taken or if there is a winner + if (!cells[index].textContent && !winner) { + cells[index].textContent = currentPlayer; + + // Check for a winner after each move + if (checkWinner()) { + status.textContent = `Jugador ${winner} Gana!`; + } else if (isBoardFull()) { + status.textContent = "Es Empate!"; + } else { + currentPlayer = currentPlayer === 'X' ? 'O' : 'X'; + status.textContent = singlePlayerMode ? `Turno "${currentPlayer}"` : `Turno "${currentPlayer}"`; + + if (singlePlayerMode && currentPlayer === 'O') { + // Es el turno de la CPU en el modo de un solo jugador + setTimeout(() => { + makeCPUMove(); + }, 1000); + } + } + } + } + + function makeCPUMove() { + // Filtra las celdas disponibles + const availableCells = cells.filter(cell => !cell.textContent); + + if (availableCells.length > 0) { + // Elige una celda aleatoria para la CPU + const randomIndex = Math.floor(Math.random() * availableCells.length); + const selectedCell = availableCells[randomIndex]; + + // Simula el clic en la celda seleccionada por la CPU + selectedCell.click(); + } + } + + function checkWinner() { + const winningCombos = [ + [0, 1, 2], [3, 4, 5], [6, 7, 8], // Rows + [0, 3, 6], [1, 4, 7], [2, 5, 8], // Columns + [0, 4, 8], [2, 4, 6] // Diagonals + ]; + + for (const combo of winningCombos) { + const [a, b, c] = combo; + if (cells[a].textContent && cells[a].textContent === cells[b].textContent && cells[a].textContent === cells[c].textContent) { + winner = cells[a].textContent; + highlightWinnerCells(combo); + return true; + } + } + + return false; + } + + function isBoardFull() { + return cells.every(cell => cell.textContent); + } + + function highlightWinnerCells(cellsToHighlight) { + cellsToHighlight.forEach(index => { + cells[index].classList.add('cell-winner'); + }); + } + + // Inicializar el tablero de juego + for (let i = 0; i < 9; i++) { + const cell = document.createElement('div'); + cell.classList.add('cell'); + cell.dataset.index = i; + cell.addEventListener('click', handleCellClick); + board.appendChild(cell); + cells.push(cell); + } + + // Agregar evento de cambio al checkbox + gameModeCheckbox.addEventListener('change', function () { + singlePlayerMode = this.checked; + resetGame(); + }); + + // Agregar evento de clic al botón de reinicio + const btnReset = document.querySelector('.btn-reset'); + btnReset.addEventListener('click', resetGame); + + // Agregar evento de clic al botón de modo de juego + gameModeButton.addEventListener('click', startSinglePlayerGame); +}); diff --git a/style.css b/style.css new file mode 100644 index 0000000..a72d3b2 --- /dev/null +++ b/style.css @@ -0,0 +1,164 @@ +* { + padding: 0; + margin: 0; + font-family: 'Itim', cursive; +} + +body { + font-family: 'Arial', sans-serif; + text-align: center; + background-color: #ffffff; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='600' viewBox='0 0 900 600'%3E%3Cg %3E%3Cpath fill='%232E163B' d='M306.9 210.2c-1.2-22.8-13.5-42.7-40.8-41.1c-18.3 1.1-35.9 3.6-47.5 20.1c-5.2 7.4-10.6 15.6-11.4 24.9c-0.5 5.8 0.2 12 1.2 17.7c9 49.6 85.3 46.7 96.4 0.2C306.6 224.9 307.3 217.4 306.9 210.2z'/%3E%3Cpath fill='%2338194a' d='M137.2 481.3c-13.2-9.9-31.2-13.3-48.5-3.2c-12.6 7.3-19.1 17.4-21.1 28.2c-0.7 2.4-1.2 4.7-1.5 7c-8.2 35.4 33.7 78.9 72.6 48.6C167.6 539.3 164.4 501.6 137.2 481.3z'/%3E%3Cg fill='%23411c59' %3E%3Cpath d='M547.9 588.3c-7.1-34.2-61.6-52.7-87.5-16.9c-11.2 11.3-12.7 26.3-7.6 39.7c1.8 7.5 5.5 13.9 10.4 19.1c19.4 20.3 53.4 26.2 72.8 1.9C545.9 619.7 553.9 604.2 547.9 588.3z'/%3E%3Cpath d='M547.9-11.7c-7.1-34.2-61.6-52.7-87.5-16.9c-11.2 11.3-12.7 26.3-7.6 39.7c1.8 7.5 5.5 13.9 10.4 19.1c19.4 20.3 53.4 26.2 72.8 1.9C545.9 19.7 553.9 4.2 547.9-11.7z'/%3E%3C/g%3E%3Cpath fill='%234b1e69' d='M849.7 498c-22.3 1.3-43.2 7.5-52.7 29.5c-3.3 7.7-7.3 15.7-7 24.3c2 55.6 86.1 63.4 98.8 10.1C890.6 554.6 877.3 496.4 849.7 498z'/%3E%3Cpath fill='%23532079' d='M762 291.1c-8.2-6.1-19.1-1.9-27.3 2.2c-7.4 3.7-14.4 8.2-21.6 12.1c-6.6 3.6-13.7 7-19.8 11.5c-18.3 13.5-2.5 45.1 10.6 56.4c17 14.6 41.6 15.9 59.6 2.1C794.1 351.8 790.7 312.4 762 291.1z'/%3E%3Cpath fill='%235c218a' d='M863.3 170.3c-4.5-15.7-17.9-28.8-33.4-34.4c-16.2-5.8-38.4-2.9-51.8 8.1c-14.9 12.2-14.5 31.7-11.4 49c9.6 53.9 84.3 47.7 97-1.3C865.6 184.4 865.3 177.1 863.3 170.3z'/%3E%3Cpath fill='%2363219c' d='M598.4 86.1c-10.2 15.5-9.3 34.2-0.9 50.4c2.6 5 6.2 9.5 10.4 13.2c14.2 12.6 35.5 17.1 53.2 9.5c14.3-6.1 23.9-19.8 26.7-34.7C707.4 75.6 629.7 38.5 598.4 86.1z'/%3E%3Cpath fill='%236b21ae' d='M509.8 413.3c-17.3 22.6-11.8 59 17.5 75.3c22.6 12.6 52.2 1.7 63.8-20.9c21.4-42-9.2-85-56.5-71C523.8 399.9 515.6 405.8 509.8 413.3z'/%3E%3Cpath fill='%237120c1' d='M607.4 232.3c-0.5-0.4-1-0.8-1.4-1.2c-16.5-12.8-30.2-22.1-50.3-8.4c-15.5 10.6-29 30.3-31.4 49.1c-4.2 33.6 30.6 46.9 58.6 40.6C619.6 304.2 640.6 259.5 607.4 232.3z'/%3E%3Cpath fill='%23771fd4' d='M410.6 95c-36.5 1.3-74.1 41.8-43.1 74.3c19.8 20.9 54.4 20.7 74.6 0.5c20.5-20.4 18.4-53.1-6.9-68.6C427.7 96.6 419.2 94.7 410.6 95z'/%3E%3Cpath fill='%237c22e3' d='M291.3 23c-0.1-0.1-0.1-0.1-0.2-0.2c-14.2-16.9-38.3-25.6-61.4-12.3c-13.5 7.8-20.5 18.7-22.7 30.2c-5.7 18 1.5 34.2 14.2 44.8c15.4 16.8 40.3 24.1 64.2 5.5c9.6-7.4 15-16.3 17.2-25.4C308.6 48.8 302.7 33.6 291.3 23z'/%3E%3Cpath fill='%23822ee9' d='M419.1 440.6c-16.9-14.5-41.8-21.5-61.7-9.5c-18.3 11.1-1 100.1 32.2 93.5c23.8-4.7 45.3-22.4 48.1-44.3C439.6 466.1 431.5 451.3 419.1 440.6z'/%3E%3Cpath fill='%23883bee' d='M127 227c-12-4.3-25.4-2.1-38.7 11.4C71 255.9 61.4 286.1 80.4 306c21.3 22.3 86.9 27.5 89.6-14.9c0.5-8.9-2.7-17.9-6.5-25.8C155.1 248.3 142.1 232.5 127 227z'/%3E%3Cpath fill='%238f48f3' d='M281.5 407.6c-0.3-0.4-0.7-0.7-1-1c-19.3-17.6-59.1-0.6-78.1 10.3c-23.8 13.7-8.2 41.1 5.4 55.8c16.3 17.6 42.7 25.2 68 5.8C291.3 466.6 295.5 422.7 281.5 407.6z'/%3E%3Cpath fill='%239656f7' d='M137.9 110.2c-10.4-25.7-43.3-32.1-67-23.6C60.1 90.4 50 97.8 45.1 108.6c-21.2 47.3 44.9 81.1 78.5 51c9.5-8.5 17.3-18.9 17.4-32.4C141 120.8 139.9 115.1 137.9 110.2z'/%3E%3Cpath fill='%239d65fa' d='M344.3 284.7c-10 14.9-9.2 34.1-0.9 49.5c3.4 6.3 8.6 13.8 16.1 15.8c7.1 1.9 15.1 0.7 22.1-0.6c15.7-3 45.6-10.5 52.3-26.8C453.5 274.4 375.6 237.9 344.3 284.7z'/%3E%3Cg fill='%23a574fd' %3E%3Cpath d='M-29.2 431.8c23.4 12.4 54.1 1.7 66.1-20.6c9.6-17.8 10.4-40.4-3.3-56.5c-10.5-12.4-44.2-25.8-58.5-11.3c-3 3.1-5.1 7.1-6.9 10.9C-41.1 373.2-55 418.1-29.2 431.8z'/%3E%3Cpath d='M870.8 431.8c23.4 12.4 54.1 1.7 66.1-20.6c9.6-17.8 10.4-40.4-3.3-56.5c-10.5-12.4-44.2-25.8-58.5-11.3c-3 3.1-5.1 7.1-6.9 10.9C858.9 373.2 845 418.1 870.8 431.8z'/%3E%3C/g%3E%3Cpath fill='%23AE84FF' d='M671.4 460.5c-10.7 1.7-20.2 8.3-26.2 22.2c-21.5 49.5 45.4 84.9 79.4 53.3c16.3-15.2 24-31 6.5-48.1c-5.9-5.8-12.3-11-19.1-15.6C699.5 463.7 684.5 458.4 671.4 460.5z'/%3E%3C/g%3E%3C/svg%3E"); + background-attachment: fixed; +} + +header { + display: flex; + height: 30px; + align-items: center; + justify-content: flex-end; +} + +.reset-container { + margin-top: 1rem; + display: flex; + align-items: center; + justify-content: center; +} + +#board { + margin: 0 auto; + display: grid; + grid-template-columns: 33% 33% 33%; + grid-template-rows: 33% 33% 33%; + max-width: 300px; + background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0)); + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); + border-radius: 20px; + border: 1px solid rgba(255, 255, 255, 0.18); + box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37); +} + +.cell { + border-radius: 6px; + width: 98px; + height: 98px; + font-size: 24px; + border: 2px solid #333; + cursor: pointer; +} + +.cell:hover { + background-color: #a7a6a6; +} + +#status { + margin-top: 20px; + font-size: 18px; +} + +.cell-winner { + background-color: #d2aaff; +} + +.checkbox-wrapper-25 input[type="checkbox"] { + background-image: -webkit-linear-gradient(hsla(0, 0%, 0%, .1), hsla(0, 0%, 100%, .1)), + -webkit-linear-gradient(left, #f66 50%, #6cf 50%); + background-size: 100% 100%, 200% 100%; + background-position: 0 0, 15px 0; + border-radius: 25px; + box-shadow: inset 0 1px 4px hsla(0, 0%, 0%, .5), + inset 0 0 10px hsla(0, 0%, 0%, .5), + 0 0 0 1px hsla(0, 0%, 0%, .1), + 0 -1px 2px 2px hsla(0, 0%, 0%, .25), + 0 2px 2px 2px hsla(0, 0%, 100%, .75); + cursor: pointer; + height: 25px; + padding-right: 25px; + width: 75px; + appearance: none; + transition: .25s; +} + +.checkbox-wrapper-25 input[type="checkbox"]:after { + background-color: #eee; + background-image: -webkit-linear-gradient(hsla(0, 0%, 100%, .1), hsla(0, 0%, 0%, .1)); + border-radius: 25px; + box-shadow: inset 0 1px 1px 1px hsla(0, 0%, 100%, 1), + inset 0 -1px 1px 1px hsla(0, 0%, 0%, .25), + 0 1px 3px 1px hsla(0, 0%, 0%, .5), + 0 0 2px hsla(0, 0%, 0%, .25); + width: 50px; + height: 25px; + display: block; + content: 'VS'; + font-weight: bold; + display: flex; + align-items: center; + justify-content: center; +} + +.checkbox-wrapper-25 input[type="checkbox"]:checked { + background-position: 0 0, 35px 0; + padding-left: 25px; + padding-right: 0; +} + +.checkbox-wrapper-25 input[type="checkbox"]:checked:after { + content: 'CPU'; /* Contenido cuando el checkbox está marcado */ +} +.btn-reset { + position: relative; + width: 120px; + height: 40px; + background-color: #000; + display: flex; + align-items: center; + color: white; + flex-direction: column; + justify-content: center; + border: none; + padding: 12px; + gap: 12px; + border-radius: 8px; + cursor: pointer; +} + +.btn-reset::before { + content: ''; + position: absolute; + inset: 0; + left: -4px; + top: -1px; + margin: auto; + width: 128px; + height: 48px; + border-radius: 10px; + background: linear-gradient(-45deg, #e81cff 0%, #40c9ff 100%); + z-index: -10; + pointer-events: none; + transition: all 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275); +} + +.btn-reset::after { + content: ""; + z-index: -1; + position: absolute; + inset: 0; + background: linear-gradient(-45deg, #fc00ff 0%, #00dbde 100%); + transform: translate3d(0, 0, 0) scale(0.95); + filter: blur(20px); +} + +.btn-reset:hover::after { + filter: blur(30px); +} + +.btn-reset:hover::before { + transform: rotate(-180deg); +} + +.btn-reset:active::before { + scale: 0.7; +} \ No newline at end of file