Añadidos juegos

This commit is contained in:
2025-08-21 23:42:55 +02:00
parent ec9c7d8d63
commit 90b2643d8d
46 changed files with 3936 additions and 0 deletions

15
4-en-raya/index.html Normal file
View File

@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>4 en Raya vs Máquina</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>4 en Raya vs Máquina</h1>
<div id="board"></div>
<div id="status"></div>
<button id="restart-btn">Reiniciar</button>
<script src="script.js"></script>
</body>
</html>

151
4-en-raya/script.js Normal file
View File

@@ -0,0 +1,151 @@
const ROWS = 6;
const COLS = 7;
const HUMAN = '🟡';
const AI = '❌';
const boardDiv = document.getElementById('board');
const statusDiv = document.getElementById('status');
const restartBtn = document.getElementById('restart-btn');
let board, gameOver, currentPlayer;
function initGame() {
board = Array.from({length: ROWS}, () => Array(COLS).fill(''));
gameOver = false;
currentPlayer = HUMAN;
statusDiv.textContent = "Tu turno (🟡)";
renderBoard();
}
function renderBoard() {
boardDiv.innerHTML = '';
// Creamos todas las celdas primero
for (let row = 0; row < ROWS; row++) {
for (let col = 0; col < COLS; col++) {
const cellDiv = document.createElement('div');
cellDiv.className = 'cell';
cellDiv.textContent = board[row][col];
// Si es turno humano y no está terminado el juego
if (!gameOver && currentPlayer === HUMAN && board[row][col] === '') {
let lowestRow = getLowestEmptyRow(col);
if (lowestRow === row) {
cellDiv.style.cursor = "pointer";
}
}
// El evento click siempre llama para la columna
cellDiv.onclick = () => {
if (!gameOver && currentPlayer === HUMAN) {
playerMove(col);
}
};
boardDiv.appendChild(cellDiv);
}
}
}
function getLowestEmptyRow(col) {
for (let r = ROWS - 1; r >= 0; r--) {
if (board[r][col] === '') return r;
}
return -1;
}
function playerMove(col) {
if (gameOver || currentPlayer !== HUMAN) return;
let row = getLowestEmptyRow(col);
if (row === -1) return; // columna llena
board[row][col] = HUMAN;
renderBoard();
if (checkWinner(HUMAN)) {
statusDiv.textContent = "¡Has ganado! 🎉";
gameOver = true;
return;
}
if (isFull()) {
statusDiv.textContent = "¡Empate!";
gameOver = true;
return;
}
currentPlayer = AI;
statusDiv.textContent = "Turno de la máquina (❌)";
setTimeout(machineMove, 450);
}
function machineMove() {
if (gameOver || currentPlayer !== AI) return;
// IA sencilla: elige columna aleatoria libre
let validCols = [];
for (let c = 0; c < COLS; c++) {
if (board[0][c] === '') validCols.push(c);
}
if (validCols.length === 0) return;
let col = validCols[Math.floor(Math.random() * validCols.length)];
let row = getLowestEmptyRow(col);
board[row][col] = AI;
renderBoard();
if (checkWinner(AI)) {
statusDiv.textContent = "¡La máquina gana! 🤖";
gameOver = true;
return;
}
if (isFull()) {
statusDiv.textContent = "¡Empate!";
gameOver = true;
return;
}
currentPlayer = HUMAN;
statusDiv.textContent = "Tu turno (🟡)";
}
function isFull() {
return board[0].every(cell => cell !== '');
}
function checkWinner(player) {
// Horizontal
for (let r = 0; r < ROWS; r++) {
for (let c = 0; c < COLS - 3; c++) {
if (
board[r][c] === player &&
board[r][c + 1] === player &&
board[r][c + 2] === player &&
board[r][c + 3] === player
) return true;
}
}
// Vertical
for (let c = 0; c < COLS; c++) {
for (let r = 0; r < ROWS - 3; r++) {
if (
board[r][c] === player &&
board[r + 1][c] === player &&
board[r + 2][c] === player &&
board[r + 3][c] === player
) return true;
}
}
// Diagonal descendente \
for (let r = 0; r < ROWS - 3; r++) {
for (let c = 0; c < COLS - 3; c++) {
if (
board[r][c] === player &&
board[r + 1][c + 1] === player &&
board[r + 2][c + 2] === player &&
board[r + 3][c + 3] === player
) return true;
}
}
// Diagonal ascendente /
for (let r = 3; r < ROWS; r++) {
for (let c = 0; c < COLS - 3; c++) {
if (
board[r][c] === player &&
board[r - 1][c + 1] === player &&
board[r - 2][c + 2] === player &&
board[r - 3][c + 3] === player
) return true;
}
}
return false;
}
restartBtn.onclick = initGame;
initGame();

132
4-en-raya/styles.css Normal file
View File

@@ -0,0 +1,132 @@
body {
background: #eef2f3;
font-family: Arial, sans-serif;
text-align: center;
color: #222;
margin: 0;
padding: 0;
}
h1 {
margin-top: 2rem;
color: #d7263d;
font-size: 2.1rem;
line-height: 1.2;
}
/* Tablero responsive */
#board {
display: grid;
grid-template-columns: repeat(7, minmax(35px, 11vw));
grid-template-rows: repeat(6, minmax(35px, 11vw));
gap: 0.6em;
justify-content: center;
margin: 2rem auto 1.3rem auto;
background: #1565c0;
padding: 1.2em 0;
border-radius: 15px;
max-width: 100vw;
box-sizing: border-box;
}
/* Celda responsive */
.cell {
width: 100%;
height: 100%;
background: #fff;
border-radius: 50%;
box-shadow: 0 2px 8px #bbb;
font-size: 4.2em;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background 0.15s;
}
.cell:hover,
.cell:focus {
background: #ffe082;
}
#status {
font-size: 1.1em;
min-height: 2em;
margin-bottom: 1em;
word-break: break-word;
}
#restart-btn {
background: #d7263d;
color: #fff;
font-size: 1em;
border: none;
border-radius: 7px;
padding: 0.7em 2em;
cursor: pointer;
transition: background 0.2s;
margin-bottom: 2em;
}
#restart-btn:hover,
#restart-btn:focus {
background: #920c22;
}
/* Celulares */
@media (max-width: 520px) {
h1 {
font-size: 1.2rem;
margin-top: 1rem;
}
#board {
grid-template-columns: repeat(7, minmax(22px, 12vw));
grid-template-rows: repeat(6, minmax(22px, 12vw));
gap: 0.25em;
padding: 0.5em 0;
border-radius: 10px;
margin: 1rem auto 1rem auto;
max-width: 100vw;
}
.cell {
font-size: 4.2em;
border-radius: 50%;
}
#status {
font-size: 0.97em;
min-height: 1.2em;
margin-bottom: 0.8em;
}
#restart-btn {
font-size: 0.9em;
padding: 0.45em 1em;
border-radius: 5px;
margin-bottom: 1em;
}
}
/* Tablets */
@media (max-width: 900px) {
h1 {
font-size: 1.4rem;
}
#board {
grid-template-columns: repeat(7, minmax(28px, 11vw));
grid-template-rows: repeat(6, minmax(28px, 11vw));
}
.cell {
font-size: 4.2em;
}
}
/* Pantallas grandes */
@media (min-width: 1200px) {
#board {
grid-template-columns: repeat(7, 64px);
grid-template-rows: repeat(6, 64px);
gap: 1em;
}
.cell {
font-size: 2em;
}
}