Añadidos juegos
This commit is contained in:
15
puzle-numeros/index.html
Normal file
15
puzle-numeros/index.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Puzzle de Números</title>
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Puzzle de Números</h1>
|
||||
<div id="board"></div>
|
||||
<div id="status"></div>
|
||||
<button id="restart-btn">Reiniciar</button>
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
97
puzle-numeros/script.js
Normal file
97
puzle-numeros/script.js
Normal file
@@ -0,0 +1,97 @@
|
||||
const SIZE = 4;
|
||||
const boardDiv = document.getElementById('board');
|
||||
const statusDiv = document.getElementById('status');
|
||||
const restartBtn = document.getElementById('restart-btn');
|
||||
let board, won;
|
||||
|
||||
function initGame() {
|
||||
board = [];
|
||||
won = false;
|
||||
let numbers = Array.from({length: SIZE*SIZE}, (_, i) => i);
|
||||
do {
|
||||
shuffle(numbers);
|
||||
} while(!isSolvable(numbers));
|
||||
// Llenar el tablero
|
||||
for (let r=0; r<SIZE; r++) {
|
||||
let row = [];
|
||||
for (let c=0; c<SIZE; c++)
|
||||
row.push(numbers[r*SIZE + c]);
|
||||
board.push(row);
|
||||
}
|
||||
statusDiv.textContent = "Ordena las fichas del 1 al 15";
|
||||
renderBoard();
|
||||
}
|
||||
|
||||
function shuffle(array) {
|
||||
for (let i = array.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[array[i], array[j]] = [array[j], array[i]];
|
||||
}
|
||||
}
|
||||
|
||||
// Verifica si el puzzle es resoluble (paridad)
|
||||
function isSolvable(arr) {
|
||||
let invCount = 0;
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
if (arr[i] === 0) continue;
|
||||
for (let j = i+1; j < arr.length; j++) {
|
||||
if (arr[j] !== 0 && arr[i] > arr[j]) invCount++;
|
||||
}
|
||||
}
|
||||
let emptyRow = Math.floor(arr.indexOf(0) / SIZE);
|
||||
return (invCount + emptyRow) % 2 === 0;
|
||||
}
|
||||
|
||||
function renderBoard() {
|
||||
boardDiv.innerHTML = '';
|
||||
for (let r = 0; r < SIZE; r++) {
|
||||
for (let c = 0; c < SIZE; c++) {
|
||||
const val = board[r][c];
|
||||
const tile = document.createElement('div');
|
||||
tile.className = 'tile' + (val === 0 ? ' empty' : '');
|
||||
tile.textContent = val === 0 ? '' : val;
|
||||
if (val !== 0 && !won) {
|
||||
tile.onclick = () => moveTile(r, c);
|
||||
}
|
||||
boardDiv.appendChild(tile);
|
||||
}
|
||||
}
|
||||
if (checkWin() && !won) {
|
||||
won = true;
|
||||
statusDiv.textContent = "¡Felicidades! Puzzle resuelto 🎉";
|
||||
}
|
||||
}
|
||||
|
||||
function moveTile(r, c) {
|
||||
let neighbours = [
|
||||
[r-1, c],
|
||||
[r+1, c],
|
||||
[r, c-1],
|
||||
[r, c+1]
|
||||
];
|
||||
for (let [nr, nc] of neighbours) {
|
||||
if (nr >=0 && nr < SIZE && nc >=0 && nc < SIZE && board[nr][nc] === 0) {
|
||||
// Intercambia
|
||||
[board[nr][nc], board[r][c]] = [board[r][c], board[nr][nc]];
|
||||
renderBoard();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkWin() {
|
||||
let n = 1;
|
||||
for (let r = 0; r < SIZE; r++) {
|
||||
for (let c = 0; c < SIZE; c++) {
|
||||
if (r === SIZE-1 && c === SIZE-1) {
|
||||
if (board[r][c] !== 0) return false;
|
||||
} else {
|
||||
if (board[r][c] !== n++) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
restartBtn.onclick = initGame;
|
||||
initGame();
|
133
puzle-numeros/styles.css
Normal file
133
puzle-numeros/styles.css
Normal file
@@ -0,0 +1,133 @@
|
||||
html {
|
||||
box-sizing: border-box;
|
||||
font-size: 16px;
|
||||
}
|
||||
*, *:before, *:after {
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
body {
|
||||
background: #f4f4f4;
|
||||
font-family: Arial, sans-serif;
|
||||
text-align: center;
|
||||
color: #222;
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* Encabezado */
|
||||
h1 {
|
||||
margin-top: 2rem;
|
||||
color: #3498db;
|
||||
font-size: clamp(1.6rem, 4vw, 2.7rem);
|
||||
}
|
||||
|
||||
/* Tablero responsive */
|
||||
#board {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
grid-template-rows: repeat(4, 1fr);
|
||||
gap: 0.7rem;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 2.2rem auto 1.3rem auto;
|
||||
width: 100%;
|
||||
max-width: 410px;
|
||||
aspect-ratio: 1 / 1;
|
||||
background: #e9ecef;
|
||||
border-radius: 1.2rem;
|
||||
padding: 1.2rem;
|
||||
box-shadow: 0 2px 14px #bbb4;
|
||||
}
|
||||
|
||||
/* Ficha */
|
||||
.tile {
|
||||
background: #fff;
|
||||
border-radius: 0.6em;
|
||||
box-shadow: 0 2px 8px #bbb;
|
||||
font-size: clamp(1.1em, 5vw, 2em);
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: background 0.15s;
|
||||
user-select: none;
|
||||
min-width: 0; /* Para que flex funcionen perfecto en grid */
|
||||
min-height: 0;
|
||||
aspect-ratio: 1 / 1;
|
||||
/* width y height no son necesarias, grid y aspect-ratio lo ajustan */
|
||||
}
|
||||
.tile.empty {
|
||||
background: #bdd4ea;
|
||||
cursor: default;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* Estado y botón */
|
||||
#status {
|
||||
font-size: clamp(1em, 2vw, 1.15em);
|
||||
min-height: 2em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
#restart-btn {
|
||||
background: #3498db;
|
||||
color: #fff;
|
||||
font-size: clamp(1em, 2vw, 1.15em);
|
||||
border: none;
|
||||
border-radius: 0.7em;
|
||||
padding: 0.5em 2em;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
margin-bottom: 1.4em;
|
||||
box-shadow: 0 2px 8px #3498db33;
|
||||
}
|
||||
#restart-btn:hover {
|
||||
background: #217dbb;
|
||||
}
|
||||
|
||||
/* ==== Pantallas pequeñas/móviles ==== */
|
||||
@media (max-width: 728px) {
|
||||
h1 {
|
||||
margin-top: 6vw;
|
||||
font-size: clamp(1.1em, 7vw, 2.1em);
|
||||
}
|
||||
#board {
|
||||
max-width: 96vw;
|
||||
padding: 2vw;
|
||||
gap: 3vw;
|
||||
border-radius: 6vw;
|
||||
margin-top: 6vw;
|
||||
margin-bottom: 6vw;
|
||||
}
|
||||
.tile {
|
||||
font-size: clamp(1em, 10vw, 2.6em);
|
||||
border-radius: 5vw;
|
||||
}
|
||||
#restart-btn {
|
||||
font-size: clamp(1em, 8vw, 1.5em);
|
||||
padding: 1em 13vw;
|
||||
border-radius: 5vw;
|
||||
margin-bottom: 5vw;
|
||||
}
|
||||
#status {
|
||||
font-size: clamp(1em, 7vw, 1.3em);
|
||||
margin-bottom: 4vw;
|
||||
}
|
||||
}
|
||||
|
||||
/* ==== Pantallas muy pequeñas ==== */
|
||||
@media (max-width: 350px) {
|
||||
#board {
|
||||
padding: 1vw;
|
||||
gap: 2vw;
|
||||
border-radius: 9vw;
|
||||
}
|
||||
.tile { font-size: clamp(0.9em, 15vw, 1.6em); }
|
||||
#restart-btn {
|
||||
padding: 0.7em 3vw;
|
||||
border-radius: 8vw;
|
||||
font-size: clamp(0.9em, 13vw, 1.1em);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user