Conversió de l'original en TCL a bonico en HTML (Co-Authored-By: Copilot)
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
backups
|
||||||
@@ -0,0 +1,974 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="es">
|
||||||
|
<head>
|
||||||
|
<!--
|
||||||
|
Conversió de tiny_solver.tcl a HTML+JS amb Copilot
|
||||||
|
30/05/2026
|
||||||
|
-->
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Solver TCL-like + UI Mejorada</title>
|
||||||
|
<style>
|
||||||
|
body { margin:0; padding:0; background:#111; color:#eee; font-family:monospace; }
|
||||||
|
#left { flex:1; overflow:auto; padding:10px; border-right:2px solid #333; }
|
||||||
|
#right { flex:1; overflow:hidden; }
|
||||||
|
#map { font-size:16px; line-height:16px; }
|
||||||
|
.row { height:16px; }
|
||||||
|
.tile { display:inline-block; width:16px; height:16px; text-align:center; }
|
||||||
|
|
||||||
|
.t-empty { background:#222; }
|
||||||
|
.t-wall { background:#888; }
|
||||||
|
.t-hole { background:#004; }
|
||||||
|
.t-water { background:#006; }
|
||||||
|
.t-sand { background:#663; }
|
||||||
|
.t-ball { background:#0a0; }
|
||||||
|
.t-rock { background:#a50; }
|
||||||
|
.t-door { background:#550; }
|
||||||
|
.t-switch{ background:#770; }
|
||||||
|
.t-special{ background:#a0a; }
|
||||||
|
|
||||||
|
button { margin:3px; padding:5px 10px; }
|
||||||
|
.hl {
|
||||||
|
color: yellow;
|
||||||
|
font-weight: bold;
|
||||||
|
text-shadow: 0 0 5px #ff0;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div style="display:flex; height:100vh; width:100vw; overflow:hidden;">
|
||||||
|
|
||||||
|
<!-- ========================= -->
|
||||||
|
<!-- COLUMNA IZQUIERDA -->
|
||||||
|
<!-- ========================= -->
|
||||||
|
<div id="left">
|
||||||
|
|
||||||
|
<!-- ========================= -->
|
||||||
|
<!-- PRIMERA FILA: NIVELES -->
|
||||||
|
<!-- ========================= -->
|
||||||
|
<div>
|
||||||
|
<button onclick="prevLevel()">⬅ Nivel anterior</button>
|
||||||
|
|
||||||
|
<label for="levelSelect">Nivel:</label>
|
||||||
|
<select id="levelSelect"></select>
|
||||||
|
|
||||||
|
<button onclick="nextLevel()">Siguiente nivel ➡</button>
|
||||||
|
|
||||||
|
<button onclick="loadAndSolve()">Cargar y resolver</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ========================= -->
|
||||||
|
<!-- SEGUNDA FILA: ANIMACIÓN -->
|
||||||
|
<!-- ========================= -->
|
||||||
|
<div style="margin-top:10px;">
|
||||||
|
<button onclick="play()">▶</button>
|
||||||
|
<button onclick="pause()">⏸</button>
|
||||||
|
<button onclick="stepBackward()">⟵</button>
|
||||||
|
<button onclick="stepForward()">⟶</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ========================= -->
|
||||||
|
<!-- MOVIMIENTOS Y PASO -->
|
||||||
|
<!-- ========================= -->
|
||||||
|
<div style="margin-top:10px;">
|
||||||
|
<div>Movimientos: <span id="moves"></span></div>
|
||||||
|
<div>Paso: <span id="stepInfo"></span></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ========================= -->
|
||||||
|
<!-- MAPA -->
|
||||||
|
<!-- ========================= -->
|
||||||
|
<div id="map" style="margin-top:10px;"></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ========================= -->
|
||||||
|
<!-- COLUMNA DERECHA -->
|
||||||
|
<!-- ========================= -->
|
||||||
|
<div id="right">
|
||||||
|
<iframe
|
||||||
|
src="https://www.lexaloffle.com/bbs/?pid=79680"
|
||||||
|
style="border:none; width:100%; height:100%; background:#000;">
|
||||||
|
</iframe>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/* ============================================================
|
||||||
|
=============== AQUÍ VA TODO EL SOLVER B1 =================
|
||||||
|
============================================================ */
|
||||||
|
|
||||||
|
/* ------------------ MAPAS (los 32 niveles) ------------------ */
|
||||||
|
const levels = {
|
||||||
|
"hole01": [
|
||||||
|
"------",
|
||||||
|
"- -",
|
||||||
|
"- -- -",
|
||||||
|
"- -- -",
|
||||||
|
"- -- -",
|
||||||
|
"- -- -",
|
||||||
|
"-B--H-",
|
||||||
|
"------"
|
||||||
|
],
|
||||||
|
"hole02": [
|
||||||
|
" ----- ",
|
||||||
|
"--- --",
|
||||||
|
"-H -",
|
||||||
|
"--- -",
|
||||||
|
" -- --",
|
||||||
|
" -B-- ",
|
||||||
|
" --- "
|
||||||
|
],
|
||||||
|
"hole03": [
|
||||||
|
" ---- ",
|
||||||
|
"-- ----",
|
||||||
|
"- -",
|
||||||
|
"- B -",
|
||||||
|
"- H -",
|
||||||
|
"- -",
|
||||||
|
"-- --",
|
||||||
|
" ------ "
|
||||||
|
],
|
||||||
|
"hole04": [
|
||||||
|
"---- ",
|
||||||
|
"-- ------",
|
||||||
|
"- -",
|
||||||
|
"- ---- -",
|
||||||
|
"- - -",
|
||||||
|
"-- -H - -",
|
||||||
|
" - - - -",
|
||||||
|
" - ---- -",
|
||||||
|
" - B-",
|
||||||
|
" --------"
|
||||||
|
],
|
||||||
|
"hole05": [
|
||||||
|
"------",
|
||||||
|
"-B--H-",
|
||||||
|
"- H-",
|
||||||
|
"- -- -",
|
||||||
|
"- -- -",
|
||||||
|
"- -",
|
||||||
|
"-B -",
|
||||||
|
"------"
|
||||||
|
],
|
||||||
|
"hole06": [
|
||||||
|
"..----",
|
||||||
|
".- H-",
|
||||||
|
"- H-",
|
||||||
|
"- ---",
|
||||||
|
"- -",
|
||||||
|
"--- -",
|
||||||
|
"- -",
|
||||||
|
"- ---",
|
||||||
|
"- -",
|
||||||
|
"-B B-",
|
||||||
|
"------"
|
||||||
|
],
|
||||||
|
"hole07": [
|
||||||
|
"-----..",
|
||||||
|
"-H ---",
|
||||||
|
"--- H-",
|
||||||
|
"..- ---",
|
||||||
|
"..- -..",
|
||||||
|
"..- -..",
|
||||||
|
"..- -..",
|
||||||
|
".-- -..",
|
||||||
|
".-BB-..",
|
||||||
|
".----.."
|
||||||
|
],
|
||||||
|
"hole08": [
|
||||||
|
"--------",
|
||||||
|
"-BH B-",
|
||||||
|
"- H-",
|
||||||
|
"- -",
|
||||||
|
"- -",
|
||||||
|
"-H -",
|
||||||
|
"-B HB-",
|
||||||
|
"--------"
|
||||||
|
],
|
||||||
|
"hole09": [
|
||||||
|
"-----.",
|
||||||
|
"- H-.",
|
||||||
|
"- H-.",
|
||||||
|
"- H-.",
|
||||||
|
"- ---.",
|
||||||
|
"- --..",
|
||||||
|
"- -..",
|
||||||
|
"- -.",
|
||||||
|
"-BBB -",
|
||||||
|
"------"
|
||||||
|
],
|
||||||
|
"hole10": [
|
||||||
|
"..---...",
|
||||||
|
"..-B-...",
|
||||||
|
"---B----",
|
||||||
|
"-H-B--W-",
|
||||||
|
"- - -- -",
|
||||||
|
"- - H- -",
|
||||||
|
"- - -- -",
|
||||||
|
"- -",
|
||||||
|
"------ -",
|
||||||
|
"-H -",
|
||||||
|
"--------"
|
||||||
|
],
|
||||||
|
"hole11": [
|
||||||
|
".---....",
|
||||||
|
".-H-....",
|
||||||
|
".- -----",
|
||||||
|
"--B -",
|
||||||
|
"-H -",
|
||||||
|
"-- B-",
|
||||||
|
".- ---",
|
||||||
|
".- BH-.",
|
||||||
|
".------."
|
||||||
|
],
|
||||||
|
"hole12": [
|
||||||
|
"..----..",
|
||||||
|
"..-H -..",
|
||||||
|
"--- ---",
|
||||||
|
"-B -",
|
||||||
|
"-B S -",
|
||||||
|
"--- ---",
|
||||||
|
"..-H -..",
|
||||||
|
"..----.."
|
||||||
|
],
|
||||||
|
"hole13": [
|
||||||
|
"----..----",
|
||||||
|
"-H-----H--",
|
||||||
|
"-H BBBB H-",
|
||||||
|
"-- WWWW --",
|
||||||
|
".- WWWW -.",
|
||||||
|
".- WWWW -.",
|
||||||
|
"-- WWWW --",
|
||||||
|
"-H BBBB H-",
|
||||||
|
"-H-----H--",
|
||||||
|
"----..----"
|
||||||
|
],
|
||||||
|
"hole14": [
|
||||||
|
"------..",
|
||||||
|
"-H --.",
|
||||||
|
"- --",
|
||||||
|
"- WBBW-",
|
||||||
|
"- WWBBW-",
|
||||||
|
"- WWWWW-",
|
||||||
|
"-HWW----",
|
||||||
|
"-HW--...",
|
||||||
|
"----...."
|
||||||
|
],
|
||||||
|
"hole15": [
|
||||||
|
"..------..",
|
||||||
|
"---H ---",
|
||||||
|
"-H-- -H-",
|
||||||
|
"-H-S -",
|
||||||
|
"- - S -",
|
||||||
|
"- S -",
|
||||||
|
"- S -",
|
||||||
|
"--- ---",
|
||||||
|
"..-BBBB-..",
|
||||||
|
"..------.."
|
||||||
|
],
|
||||||
|
"hole16": [
|
||||||
|
"---- ----",
|
||||||
|
"- H- -BW-",
|
||||||
|
"-WB- -H -",
|
||||||
|
"---- ----",
|
||||||
|
" ",
|
||||||
|
"---- ----",
|
||||||
|
"- W- -H -",
|
||||||
|
"-BH- -WB-",
|
||||||
|
"---- ----"
|
||||||
|
],
|
||||||
|
"hole17": [
|
||||||
|
"--------- ",
|
||||||
|
"- - ",
|
||||||
|
"- - ",
|
||||||
|
"- WBBW - ",
|
||||||
|
"- WWWW --",
|
||||||
|
"- WWWW H-",
|
||||||
|
"- --",
|
||||||
|
"- -- ",
|
||||||
|
"-H------ ",
|
||||||
|
"--- "
|
||||||
|
],
|
||||||
|
"hole18": [
|
||||||
|
" --- ",
|
||||||
|
" ---H-- ",
|
||||||
|
" ----B - ",
|
||||||
|
"-- - ",
|
||||||
|
"-H S -- ",
|
||||||
|
"-- S B- ",
|
||||||
|
" -B S --",
|
||||||
|
" -- S H-",
|
||||||
|
" - --",
|
||||||
|
" - B---- ",
|
||||||
|
" --H--- ",
|
||||||
|
" --- "
|
||||||
|
],
|
||||||
|
"hole19": [
|
||||||
|
"--------",
|
||||||
|
"-H H-",
|
||||||
|
"-H H-",
|
||||||
|
"-- BB --",
|
||||||
|
" -B B- ",
|
||||||
|
" -B B- ",
|
||||||
|
"-- BB --",
|
||||||
|
"-H H-",
|
||||||
|
"-H H-",
|
||||||
|
"--------"
|
||||||
|
],
|
||||||
|
"hole20": [
|
||||||
|
"------- ",
|
||||||
|
"- WSW - ",
|
||||||
|
"- S S--------",
|
||||||
|
"-S S B--WSBWH-",
|
||||||
|
"- W --S SW -",
|
||||||
|
"-HWSSW-- SWWS-",
|
||||||
|
"--------S SW -",
|
||||||
|
" -WS -",
|
||||||
|
" -------"
|
||||||
|
],
|
||||||
|
"hole21": [
|
||||||
|
"--------",
|
||||||
|
"- H-",
|
||||||
|
"-- -- --",
|
||||||
|
" - -- - ",
|
||||||
|
" -R R- ",
|
||||||
|
" - -- - ",
|
||||||
|
" -B-- - ",
|
||||||
|
"--------"
|
||||||
|
],
|
||||||
|
"hole22": [
|
||||||
|
"-----------",
|
||||||
|
"-HR R B-",
|
||||||
|
"-- - - - --",
|
||||||
|
"-- - - - --",
|
||||||
|
"-B R RH-",
|
||||||
|
"-----------"
|
||||||
|
],
|
||||||
|
"hole23": [
|
||||||
|
"---- ---",
|
||||||
|
"- ---- -",
|
||||||
|
"- R -",
|
||||||
|
"-- ---- -",
|
||||||
|
" - - -R-",
|
||||||
|
" -R- - -",
|
||||||
|
" - ---- -",
|
||||||
|
" -HR-B -",
|
||||||
|
"------- -",
|
||||||
|
" ---"
|
||||||
|
],
|
||||||
|
"hole24": [
|
||||||
|
"..---..",
|
||||||
|
"---H---",
|
||||||
|
"- -",
|
||||||
|
"- RRR -",
|
||||||
|
"--RBR--",
|
||||||
|
"- RRR -",
|
||||||
|
"- -",
|
||||||
|
"--- ---",
|
||||||
|
" --- "
|
||||||
|
],
|
||||||
|
"hole25": [
|
||||||
|
"---------",
|
||||||
|
"- RRBRW-",
|
||||||
|
"- -------",
|
||||||
|
"- -------",
|
||||||
|
"- HW-",
|
||||||
|
"---------"
|
||||||
|
],
|
||||||
|
"hole26": [
|
||||||
|
"----------",
|
||||||
|
"-H--BR--0-",
|
||||||
|
"-1-- -- -",
|
||||||
|
"- -",
|
||||||
|
"----------"
|
||||||
|
],
|
||||||
|
"hole27": [
|
||||||
|
"-------.",
|
||||||
|
"-H1 -.",
|
||||||
|
"---- --.",
|
||||||
|
"-0-- ---",
|
||||||
|
"- RB-0-",
|
||||||
|
"---BR -",
|
||||||
|
"..- ----",
|
||||||
|
".-- ----",
|
||||||
|
".- 1H-",
|
||||||
|
".-------"
|
||||||
|
],
|
||||||
|
"hole28": [
|
||||||
|
" --- ",
|
||||||
|
" -0------- ",
|
||||||
|
" -R- - - - ",
|
||||||
|
"------ - - ---",
|
||||||
|
"-H1H1 1H-",
|
||||||
|
"------1-1-1---",
|
||||||
|
" - - - - ",
|
||||||
|
" -B-B-B- ",
|
||||||
|
" ------- "
|
||||||
|
],
|
||||||
|
"hole29": [
|
||||||
|
"...----...",
|
||||||
|
"...-HH-...",
|
||||||
|
"----11----",
|
||||||
|
"-B S 0-",
|
||||||
|
"-B S 0-",
|
||||||
|
"--- ---",
|
||||||
|
"--- ---",
|
||||||
|
"-W S B-",
|
||||||
|
"-W S B-",
|
||||||
|
"---- ----",
|
||||||
|
"...-HH-...",
|
||||||
|
"...----..."
|
||||||
|
],
|
||||||
|
"hole30": [
|
||||||
|
"-------.",
|
||||||
|
"-H S W-.",
|
||||||
|
"--- ---.",
|
||||||
|
"-W S H-.",
|
||||||
|
"---1----",
|
||||||
|
".-0 R-",
|
||||||
|
".--- ---",
|
||||||
|
"..-R -",
|
||||||
|
"..--- --",
|
||||||
|
"...-BB-.",
|
||||||
|
"...----."
|
||||||
|
],
|
||||||
|
"hole31": [
|
||||||
|
"-----------...",
|
||||||
|
"-RRRR-BBBB-...",
|
||||||
|
"- ----- -...",
|
||||||
|
"- - ----",
|
||||||
|
"--- - ---HH-",
|
||||||
|
"-0000- 1HH-",
|
||||||
|
"--------------"
|
||||||
|
],
|
||||||
|
"hole32": [
|
||||||
|
" --- ",
|
||||||
|
"------W- ",
|
||||||
|
"-BRBBBB- ",
|
||||||
|
"------ - ",
|
||||||
|
" - ---",
|
||||||
|
" --- -H-",
|
||||||
|
" -H- - -",
|
||||||
|
" - - H-",
|
||||||
|
" -H ---",
|
||||||
|
" -- -- ",
|
||||||
|
" -H- ",
|
||||||
|
" --- "
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------ VARIABLES GLOBALES ------------------ */
|
||||||
|
let MAP_WIDTH = 0;
|
||||||
|
let MAP_HEIGHT = 0;
|
||||||
|
let STATES_SEEN = new Set();
|
||||||
|
|
||||||
|
let currentLevelName = "hole01";
|
||||||
|
let currentMap = levels[currentLevelName];
|
||||||
|
let solutionMoves = "";
|
||||||
|
let solutionStates = [];
|
||||||
|
let currentStep = 0;
|
||||||
|
let animTimer = null;
|
||||||
|
|
||||||
|
/* ------------------ CARGAR SELECTOR ------------------ */
|
||||||
|
(function initSelector() {
|
||||||
|
const sel = document.getElementById("levelSelect");
|
||||||
|
Object.keys(levels).forEach(name => {
|
||||||
|
const opt = document.createElement("option");
|
||||||
|
opt.value = name;
|
||||||
|
opt.textContent = name;
|
||||||
|
sel.appendChild(opt);
|
||||||
|
});
|
||||||
|
sel.value = currentLevelName;
|
||||||
|
drawRawMap(currentMap);
|
||||||
|
})();
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
=============== FUNCIONES DEL SOLVER TCL ==================
|
||||||
|
============================================================ */
|
||||||
|
|
||||||
|
// ================== CRC32 ==================
|
||||||
|
function crc32(str) {
|
||||||
|
let table = window.crcTable || (window.crcTable = (function() {
|
||||||
|
let c, table = [];
|
||||||
|
for (let n = 0; n < 256; n++) {
|
||||||
|
c = n;
|
||||||
|
for (let k = 0; k < 8; k++) {
|
||||||
|
c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
|
||||||
|
}
|
||||||
|
table[n] = c;
|
||||||
|
}
|
||||||
|
return table;
|
||||||
|
})());
|
||||||
|
let crc = 0 ^ (-1);
|
||||||
|
for (let i = 0; i < str.length; i++) {
|
||||||
|
crc = (crc >>> 8) ^ table[(crc ^ str.charCodeAt(i)) & 0xFF];
|
||||||
|
}
|
||||||
|
return (crc ^ (-1)) >>> 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================== CONVERSIÓN MAPA (convertMap) ==================
|
||||||
|
function convertMap(map) {
|
||||||
|
let state = {};
|
||||||
|
for (let j = 0; j < map.length; j++) {
|
||||||
|
for (let i = 0; i < map[j].length; i++) {
|
||||||
|
state[`${i},${j}`] = map[j][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [{ moves: "", map: state }];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================== popState ==================
|
||||||
|
function popState(states) {
|
||||||
|
const st = states[0];
|
||||||
|
states.splice(0,1);
|
||||||
|
return [st.moves, st.map];
|
||||||
|
}
|
||||||
|
// ================== UTILIDADES DE TILES (clon TCL) ==================
|
||||||
|
function objectInTile(tile) {
|
||||||
|
switch(tile) {
|
||||||
|
case " ": case "H": case "W": case "S":
|
||||||
|
case "0": case "1": case "2":
|
||||||
|
return "";
|
||||||
|
case "B": case "C": case "I": case "T":
|
||||||
|
case "U": case "3": case "5":
|
||||||
|
return "B";
|
||||||
|
case "D": case "J": case "R": case "4": case "6":
|
||||||
|
return "R";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function leaveTile(from_tile) {
|
||||||
|
switch(from_tile) {
|
||||||
|
case "B":
|
||||||
|
case "R": return " ";
|
||||||
|
case "C":
|
||||||
|
case "D": return "I";
|
||||||
|
case "U": return "S";
|
||||||
|
case "J": return "H";
|
||||||
|
case "3":
|
||||||
|
case "4": return "0";
|
||||||
|
case "5":
|
||||||
|
case "6": return "2";
|
||||||
|
}
|
||||||
|
return from_tile;
|
||||||
|
}
|
||||||
|
|
||||||
|
function enterTile(from_tile, to_tile) {
|
||||||
|
let object = objectInTile(from_tile);
|
||||||
|
if (object === "B") {
|
||||||
|
switch(to_tile) {
|
||||||
|
case " ": return "B";
|
||||||
|
case "H": return "I";
|
||||||
|
case "I": return "C";
|
||||||
|
case "W": return "W";
|
||||||
|
case "S": return "T";
|
||||||
|
case "0": return "3";
|
||||||
|
case "2": return "5";
|
||||||
|
}
|
||||||
|
} else if (object === "R") {
|
||||||
|
switch(to_tile) {
|
||||||
|
case " ": return "R";
|
||||||
|
case "H": return "J";
|
||||||
|
case "I": return "D";
|
||||||
|
case "W": return "W";
|
||||||
|
case "0": return "4";
|
||||||
|
case "2": return "6";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return to_tile;
|
||||||
|
}
|
||||||
|
|
||||||
|
function movableTile(tile) {
|
||||||
|
return (tile==="B" || tile==="C" || tile==="U" || tile==="R" ||
|
||||||
|
tile==="D" || tile==="J" || tile==="3" || tile==="4" ||
|
||||||
|
tile==="5" || tile==="6");
|
||||||
|
}
|
||||||
|
|
||||||
|
function isWall(tile) {
|
||||||
|
return (tile==="-" || tile==="B" || tile==="R" || tile==="3" ||
|
||||||
|
tile==="4" || tile==="1" || tile==="5" || tile==="6" ||
|
||||||
|
tile==="U" || tile==="T" || tile==="J" || tile==="D" ||
|
||||||
|
tile==="C");
|
||||||
|
}
|
||||||
|
// ================== changeState (clon TCL) ==================
|
||||||
|
function changeState(move, state) {
|
||||||
|
let dmove, j0, j1, dj, i0, i1, di;
|
||||||
|
if (move === "U") {
|
||||||
|
dmove = [0,-1];
|
||||||
|
j0 = 0; j1 = MAP_HEIGHT; dj = 1;
|
||||||
|
i0 = 0; i1 = MAP_WIDTH; di = 1;
|
||||||
|
} else if (move === "D") {
|
||||||
|
dmove = [0,1];
|
||||||
|
j0 = MAP_HEIGHT-1; j1 = -1; dj = -1;
|
||||||
|
i0 = 0; i1 = MAP_WIDTH; di = 1;
|
||||||
|
} else if (move === "L") {
|
||||||
|
dmove = [-1,0];
|
||||||
|
j0 = 0; j1 = MAP_HEIGHT; dj = 1;
|
||||||
|
i0 = 0; i1 = MAP_WIDTH; di = 1;
|
||||||
|
} else if (move === "R") {
|
||||||
|
dmove = [1,0];
|
||||||
|
j0 = 0; j1 = MAP_HEIGHT; dj = 1;
|
||||||
|
i0 = MAP_WIDTH-1; i1 = -1; di = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const premoves = state[0];
|
||||||
|
const mapObj = {...state[1]};
|
||||||
|
let arrmap = mapObj;
|
||||||
|
|
||||||
|
// T -> U
|
||||||
|
for (const pos in arrmap) {
|
||||||
|
if (arrmap[pos] === "T") arrmap[pos] = "U";
|
||||||
|
}
|
||||||
|
|
||||||
|
let nmoves = 1;
|
||||||
|
let total_moves = 0;
|
||||||
|
let iter = 0;
|
||||||
|
|
||||||
|
while (nmoves > 0 && iter < 9) {
|
||||||
|
nmoves = 0;
|
||||||
|
let j = j0;
|
||||||
|
while (j !== j1) {
|
||||||
|
let i = i0;
|
||||||
|
while (i !== i1) {
|
||||||
|
const x = i, y = j;
|
||||||
|
const key = `${x},${y}`;
|
||||||
|
let tile = arrmap[key] ?? " ";
|
||||||
|
if (movableTile(tile)) {
|
||||||
|
const test_x = x + dmove[0];
|
||||||
|
const test_y = y + dmove[1];
|
||||||
|
const tkey = `${test_x},${test_y}`;
|
||||||
|
let destTile = arrmap[tkey] ?? " ";
|
||||||
|
if (isWall(destTile)) {
|
||||||
|
if (tile === "U") arrmap[key] = "T";
|
||||||
|
} else {
|
||||||
|
arrmap[key] = leaveTile(tile);
|
||||||
|
arrmap[tkey] = enterTile(tile, destTile);
|
||||||
|
nmoves++;
|
||||||
|
|
||||||
|
// switches
|
||||||
|
let switches = 0;
|
||||||
|
for (const p in arrmap) {
|
||||||
|
if (arrmap[p] === "0") switches++;
|
||||||
|
}
|
||||||
|
if (switches === 0) {
|
||||||
|
for (const p in arrmap) {
|
||||||
|
if (arrmap[p] === "1") arrmap[p] = "2";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (const p in arrmap) {
|
||||||
|
if (arrmap[p] === "2") arrmap[p] = "1";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i += di;
|
||||||
|
}
|
||||||
|
j += dj;
|
||||||
|
}
|
||||||
|
total_moves += nmoves;
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (total_moves === 0) {
|
||||||
|
return [];
|
||||||
|
} else {
|
||||||
|
const result = [`${premoves}${move}`, arrmap];
|
||||||
|
const isNew = addLeaf(result);
|
||||||
|
if (!isNew) return [];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================== addLeaf (crc32 de filas) ==================
|
||||||
|
function addLeaf(state) {
|
||||||
|
const map = state[1];
|
||||||
|
let rows = [];
|
||||||
|
for (let j = 0; j < MAP_HEIGHT; j++) {
|
||||||
|
let row = "";
|
||||||
|
for (let i = 0; i < MAP_WIDTH; i++) {
|
||||||
|
row += (map[`${i},${j}`] ?? " ");
|
||||||
|
}
|
||||||
|
rows.push(row);
|
||||||
|
}
|
||||||
|
const hash = crc32(rows.join("|"));
|
||||||
|
const before = STATES_SEEN.size;
|
||||||
|
STATES_SEEN.add(hash);
|
||||||
|
return STATES_SEEN.size !== before; // true si es nuevo
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================== checkHoles ==================
|
||||||
|
function checkHoles(state) {
|
||||||
|
const map = state[1];
|
||||||
|
for (const k in map) {
|
||||||
|
const tile = map[k];
|
||||||
|
if (tile === "H" || tile === "J") return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================== solveMap (clon TCL) ==================
|
||||||
|
function solveMap(map) {
|
||||||
|
let states = convertMap(map);
|
||||||
|
let nmoves = 0;
|
||||||
|
let found = 0;
|
||||||
|
let newstates = [];
|
||||||
|
let solution = "NOT FOUND";
|
||||||
|
const MAX_PAR = 21;
|
||||||
|
MAP_WIDTH = map[0].length;
|
||||||
|
MAP_HEIGHT = map.length;
|
||||||
|
const moves = ["U","D","L","R"];
|
||||||
|
STATES_SEEN = new Set();
|
||||||
|
|
||||||
|
while (found === 0 && nmoves < MAX_PAR && states.length > 0) {
|
||||||
|
const state = popState(states);
|
||||||
|
addLeaf(state);
|
||||||
|
for (const move of moves) {
|
||||||
|
const newstate = changeState(move, state);
|
||||||
|
if (newstate.length !== 0) {
|
||||||
|
newstates.push({ moves: newstate[0], map: newstate[1] });
|
||||||
|
nmoves = newstate[0].length;
|
||||||
|
if (checkHoles(newstate) === 0) {
|
||||||
|
found = 1;
|
||||||
|
solution = newstate[0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found === 0 && states.length === 0) {
|
||||||
|
states = newstates;
|
||||||
|
newstates = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return solution;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================== solveMap2 (replay para estados) ==================
|
||||||
|
function solveMap2(map, movesStr) {
|
||||||
|
let states = convertMap(map);
|
||||||
|
MAP_WIDTH = map[0].length;
|
||||||
|
MAP_HEIGHT = map.length;
|
||||||
|
STATES_SEEN = new Set();
|
||||||
|
let current = popState(states); // [moves,map]
|
||||||
|
let resultStates = [current[1]];
|
||||||
|
|
||||||
|
for (const mv of movesStr.split("")) {
|
||||||
|
const newstate = changeState(mv, current);
|
||||||
|
if (newstate.length === 0) break;
|
||||||
|
resultStates.push(newstate[1]);
|
||||||
|
current = newstate;
|
||||||
|
}
|
||||||
|
return resultStates;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================== DIBUJADO COLORES ==================
|
||||||
|
function tileClass(ch) {
|
||||||
|
if (ch === "-" || ch === ".") return "t-wall";
|
||||||
|
if (ch === " " ) return "t-empty";
|
||||||
|
if (ch === "H" || ch === "I" || ch === "C" || ch === "J" || ch === "D") return "t-hole";
|
||||||
|
if (ch === "W") return "t-water";
|
||||||
|
if (ch === "S" || ch === "T" || ch === "U") return "t-sand";
|
||||||
|
if (ch === "B" || ch === "3" || ch === "5") return "t-ball";
|
||||||
|
if (ch === "R" || ch === "4" || ch === "6") return "t-rock";
|
||||||
|
if (ch === "0" || ch === "1" || ch === "2") return "t-door";
|
||||||
|
return "t-special";
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawStateColored(mapState) {
|
||||||
|
const mapDiv = document.getElementById("map");
|
||||||
|
mapDiv.innerHTML = "";
|
||||||
|
let coords = Object.keys(mapState).map(k => k.split(",").map(Number));
|
||||||
|
let maxY = Math.max(...coords.map(c => c[1]));
|
||||||
|
let maxX = Math.max(...coords.map(c => c[0]));
|
||||||
|
|
||||||
|
for (let y = 0; y <= maxY; y++) {
|
||||||
|
const rowDiv = document.createElement("div");
|
||||||
|
rowDiv.className = "row";
|
||||||
|
for (let x = 0; x <= maxX; x++) {
|
||||||
|
const ch = mapState[`${x},${y}`] ?? " ";
|
||||||
|
const span = document.createElement("span");
|
||||||
|
span.className = "tile " + tileClass(ch);
|
||||||
|
span.textContent = ch === " " ? " " : ch;
|
||||||
|
rowDiv.appendChild(span);
|
||||||
|
}
|
||||||
|
mapDiv.appendChild(rowDiv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawRawMap(map) {
|
||||||
|
let state = {};
|
||||||
|
for (let j = 0; j < map.length; j++) {
|
||||||
|
for (let i = 0; i < map[j].length; i++) {
|
||||||
|
state[`${i},${j}`] = map[j][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drawStateColored(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
function stepTo(idx) {
|
||||||
|
if (!solutionStates.length) return;
|
||||||
|
|
||||||
|
idx = Math.max(0, Math.min(idx, solutionStates.length - 1));
|
||||||
|
currentStep = idx;
|
||||||
|
|
||||||
|
drawStateColored(solutionStates[currentStep]);
|
||||||
|
|
||||||
|
// Resaltar movimiento correspondiente
|
||||||
|
renderMovesWithHighlight(currentStep);
|
||||||
|
|
||||||
|
document.getElementById("stepInfo").textContent =
|
||||||
|
`${currentStep} / ${solutionStates.length - 1}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function stepForward() { stepTo(currentStep + 1); }
|
||||||
|
function stepBackward() { stepTo(currentStep - 1); }
|
||||||
|
|
||||||
|
function play() {
|
||||||
|
if (!solutionStates.length) return;
|
||||||
|
if (animTimer) return;
|
||||||
|
animTimer = setInterval(() => {
|
||||||
|
if (currentStep >= solutionStates.length-1) {
|
||||||
|
pause();
|
||||||
|
} else {
|
||||||
|
stepForward();
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
function pause() {
|
||||||
|
if (animTimer) {
|
||||||
|
clearInterval(animTimer);
|
||||||
|
animTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
=============== NUEVAS FUNCIONES PEDIDAS ==================
|
||||||
|
============================================================ */
|
||||||
|
|
||||||
|
/* ----------- Convertir UDLR → flechas ----------- */
|
||||||
|
function movesToArrows(m) {
|
||||||
|
return m
|
||||||
|
.replace(/U/g, "↑")
|
||||||
|
.replace(/D/g, "↓")
|
||||||
|
.replace(/L/g, "←")
|
||||||
|
.replace(/R/g, "→");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------- Cargar y resolver ----------- */
|
||||||
|
function loadAndSolve() {
|
||||||
|
pause();
|
||||||
|
currentLevelName = document.getElementById("levelSelect").value;
|
||||||
|
currentMap = levels[currentLevelName];
|
||||||
|
|
||||||
|
const sol = solveMap(currentMap);
|
||||||
|
solutionMoves = sol;
|
||||||
|
renderMovesWithHighlight(0);
|
||||||
|
|
||||||
|
if (sol === "NOT FOUND" || sol === "") {
|
||||||
|
solutionStates = [];
|
||||||
|
document.getElementById("stepInfo").textContent = "Sin solución";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
solutionStates = solveMap2(currentMap, sol);
|
||||||
|
currentStep = 0;
|
||||||
|
document.getElementById("stepInfo").textContent =
|
||||||
|
`0 / ${solutionStates.length - 1}`;
|
||||||
|
drawStateColored(solutionStates[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------- Nivel anterior / siguiente ----------- */
|
||||||
|
function prevLevel() {
|
||||||
|
const keys = Object.keys(levels);
|
||||||
|
let idx = keys.indexOf(currentLevelName);
|
||||||
|
if (idx > 0) {
|
||||||
|
idx--;
|
||||||
|
document.getElementById("levelSelect").value = keys[idx];
|
||||||
|
loadAndSolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function nextLevel() {
|
||||||
|
const keys = Object.keys(levels);
|
||||||
|
let idx = keys.indexOf(currentLevelName);
|
||||||
|
if (idx < keys.length - 1) {
|
||||||
|
idx++;
|
||||||
|
document.getElementById("levelSelect").value = keys[idx];
|
||||||
|
loadAndSolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function renderMovesWithHighlight(step) {
|
||||||
|
if (!solutionMoves) {
|
||||||
|
document.getElementById("moves").innerHTML = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let html = "";
|
||||||
|
for (let i = 0; i < solutionMoves.length; i++) {
|
||||||
|
let ch = solutionMoves[i];
|
||||||
|
let arrow =
|
||||||
|
ch === "U" ? "↑" :
|
||||||
|
ch === "D" ? "↓" :
|
||||||
|
ch === "L" ? "←" :
|
||||||
|
ch === "R" ? "→" : ch;
|
||||||
|
|
||||||
|
if (i === step) {
|
||||||
|
html += `<span class="hl">${arrow}</span>`;
|
||||||
|
} else {
|
||||||
|
html += arrow;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < solutionMoves.length - 1) html += " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById("moves").innerHTML = html;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
=============== CONTROL POR TECLADO ========================
|
||||||
|
============================================================ */
|
||||||
|
|
||||||
|
document.addEventListener("keydown", function(e) {
|
||||||
|
console.log("KEYDOWN")
|
||||||
|
if (!solutionMoves || !solutionMoves.length) return;
|
||||||
|
if (!solutionStates.length) return;
|
||||||
|
|
||||||
|
// Mapa de teclas → movimientos
|
||||||
|
const keyToMove = {
|
||||||
|
"ArrowUp": "U",
|
||||||
|
"ArrowDown": "D",
|
||||||
|
"ArrowLeft": "L",
|
||||||
|
"ArrowRight": "R"
|
||||||
|
};
|
||||||
|
|
||||||
|
const mv = keyToMove[e.key];
|
||||||
|
if (!mv) return; // ignorar otras teclas
|
||||||
|
|
||||||
|
// Si ya estamos en el último paso, no avanzar
|
||||||
|
if (currentStep >= solutionMoves.length) return;
|
||||||
|
|
||||||
|
// Comprobar si la tecla coincide con el siguiente movimiento real
|
||||||
|
const expected = solutionMoves[currentStep];
|
||||||
|
|
||||||
|
if (mv === expected) {
|
||||||
|
// Avanzar un paso
|
||||||
|
stepTo(currentStep + 1);
|
||||||
|
} else {
|
||||||
|
// Si quieres, puedes mostrar un pequeño aviso visual
|
||||||
|
// pero por defecto simplemente ignoramos la tecla
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user