Laberinto — detectar que es imposible (nivel 3)
Mismo algoritmo de exploración exhaustiva que el otro ejemplo de nivel 3, pero cargado contra un laberinto deliberadamente SIN SOLUCIÓN (la salida está completamente sellada). El algoritmo explora todo lo alcanzable y concluye "imposible" con CERTEZA — no es una heurística que se rinde, es una búsqueda exhaustiva real que prueba que no hay camino.
Abrir en el editor →Algoritmo de ejemplo, listo para ejecutar paso a paso en el navegador. Sin instalar nada.
Diagrama de flujo
Pseudocódigo
// Mismo algoritmo que el otro ejemplo de nivel 3, pero cargado contra un laberinto deliberadamente SIN SOLUCIÓN (la salida está completamente sellada). Demuestra la otra mitad del ejercicio: el algoritmo explora todo lo alcanzable y concluye "imposible" con certeza, en vez de trabarse o dar una respuesta incorrecta.
Algoritmo main
Activar("Laberinto")
CargarEscenario("trampa")
fila <- 1
columna <- 1
n <- 1
visFila(1) <- fila
visColumna(1) <- columna
profundidad <- 0
encontrado <- 0
imposible <- 0
Mientras NO encontrado Y NO imposible
Llegue()
Si response_call
encontrado <- 1
SiNo
BuscarDireccion(fila, columna, visFila, visColumna, n, direccionElegida, hayDireccion)
Si hayDireccion
MOVER(direccionElegida, 1)
Delta(direccionElegida, fila, columna, fila, columna)
n <- n+1
visFila(n) <- fila
visColumna(n) <- columna
profundidad <- profundidad+1
pilaDir(profundidad) <- direccionElegida
SiNo
Si profundidad==0
imposible <- 1
SiNo
direccionTomada <- pilaDir(profundidad)
profundidad <- profundidad-1
Opuesta(direccionTomada, direccionVolver)
MOVER(direccionVolver, 1)
Delta(direccionVolver, fila, columna, fila, columna)
FinSi
FinSi
FinSi
FinMientras
Si encontrado
Escribir "Encontré la salida — exploré ", n, " posiciones."
SiNo
Escribir "Es IMPOSIBLE llegar a la salida — exploré todo lo alcanzable (", n, " posiciones) sin encontrarla."
FinSi
FinAlgoritmo
Funcion BuscarDireccion(filaAct, columnaAct, visFila, visColumna, n, direccionElegida, hayDireccion)
orden(1) <- "ARRIBA"
orden(2) <- "DERECHA"
orden(3) <- "ABAJO"
orden(4) <- "IZQUIERDA"
hayDireccion <- 0
Para i <- 1 Hasta 4
Si NO hayDireccion
d <- orden(i)
HayObstaculo(d)
Si NO response_call
Delta(d, filaAct, columnaAct, filaC, columnaC)
EstaVisitado(filaC, columnaC, visFila, visColumna, n, visitado)
Si NO visitado
direccionElegida <- d
hayDireccion <- 1
FinSi
FinSi
FinSi
FinPara
FinFuncion
Funcion Delta(direccion, filaAct, columnaAct, filaC, columnaC)
Segun direccion
Caso ARRIBA:
filaC <- filaAct-1
columnaC <- columnaAct
Caso ABAJO:
filaC <- filaAct+1
columnaC <- columnaAct
Caso IZQUIERDA:
filaC <- filaAct
columnaC <- columnaAct-1
Caso DERECHA:
filaC <- filaAct
columnaC <- columnaAct+1
De Otro Modo:
FinSegun
FinFuncion
Funcion EstaVisitado(filaC, columnaC, visFila, visColumna, n, resultado)
resultado <- 0
Para i <- 1 Hasta n
Si NO resultado
Si visFila(i)==filaC Y visColumna(i)==columnaC
resultado <- 1
FinSi
FinSi
FinPara
FinFuncion
Funcion Opuesta(direccion, resultado)
Segun direccion
Caso ARRIBA:
resultado <- "ABAJO"
Caso ABAJO:
resultado <- "ARRIBA"
Caso IZQUIERDA:
resultado <- "DERECHA"
Caso DERECHA:
resultado <- "IZQUIERDA"
De Otro Modo:
FinSegun
FinFuncion
El mismo algoritmo en Java
package org.desarrollo;
import java.util.ArrayList;
import java.util.Scanner;
/**
* Mismo algoritmo que el otro ejemplo de nivel 3, pero cargado contra un laberinto deliberadamente SIN SOLUCIÓN (la salida está completamente sellada). Demuestra la otra mitad del ejercicio: el algoritmo explora todo lo alcanzable y concluye "imposible" con certeza, en vez de trabarse o dar una respuesta incorrecta.
*/
public class FreeDFDMain {
/**
* Punto de entrada del programa generado por freeDFDWeb.
*
* @param args no utilizado — freeDFDWeb no pasa argumentos de línea de comandos.
*/
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
double[] fila = {0.0}; // Arreglo de 1 elemento: simula paso por referencia (Java no permite mutar un double pasado a otro método) — se usa como "fila[0]" en el resto del método
double[] columna = {0.0}; // Arreglo de 1 elemento: simula paso por referencia (Java no permite mutar un double pasado a otro método) — se usa como "columna[0]" en el resto del método
double n = 0.0;
ArrayList<Double> visFila = new ArrayList<>();
ArrayList<Double> visColumna = new ArrayList<>();
double profundidad = 0.0;
double encontrado = 0.0;
double imposible = 0.0;
double response_call = 0.0;
double[] direccionElegida = {0.0}; // Arreglo de 1 elemento: simula paso por referencia (Java no permite mutar un double pasado a otro método) — se usa como "direccionElegida[0]" en el resto del método
double[] hayDireccion = {0.0}; // Arreglo de 1 elemento: simula paso por referencia (Java no permite mutar un double pasado a otro método) — se usa como "hayDireccion[0]" en el resto del método
ArrayList<Double> pilaDir = new ArrayList<>();
double direccionTomada = 0.0;
double[] direccionVolver = {0.0}; // Arreglo de 1 elemento: simula paso por referencia (Java no permite mutar un double pasado a otro método) — se usa como "direccionVolver[0]" en el resto del método
System.out.println("Activar(" + "Laberinto" + ")"); // Componente interactivo no disponible en el código exportado
System.out.println("CargarEscenario(" + "trampa" + ")"); // Componente interactivo no disponible en el código exportado
fila[0] = 1;
columna[0] = 1;
n = 1;
vecSet(visFila, (int)(1), fila[0]);
vecSet(visColumna, (int)(1), columna[0]);
profundidad = 0;
encontrado = 0;
imposible = 0;
while ((((!((encontrado) != 0)) && (!((imposible) != 0))))) {
System.out.println("Llegue(" + "" + ")"); // Componente interactivo no disponible en el código exportado
if (((response_call) != 0)) {
encontrado = 1;
} else {
BuscarDireccion(fila[0], columna[0], visFila, visColumna, n, direccionElegida, hayDireccion);
if (((hayDireccion[0]) != 0)) {
System.out.println("MOVER(" + fmt(direccionElegida[0]) + ", " + fmt(1) + ")"); // Componente interactivo no disponible en el código exportado
Delta(direccionElegida[0], fila[0], columna[0], fila, columna);
n = (n + 1);
vecSet(visFila, (int)(n), fila[0]);
vecSet(visColumna, (int)(n), columna[0]);
profundidad = (profundidad + 1);
vecSet(pilaDir, (int)(profundidad), direccionElegida[0]);
} else {
if (((profundidad == 0))) {
imposible = 1;
} else {
direccionTomada = vecGet(pilaDir, (int)(profundidad));
profundidad = (profundidad - 1);
Opuesta(direccionTomada, direccionVolver);
System.out.println("MOVER(" + fmt(direccionVolver[0]) + ", " + fmt(1) + ")"); // Componente interactivo no disponible en el código exportado
Delta(direccionVolver[0], fila[0], columna[0], fila, columna);
}
}
}
}
if (((encontrado) != 0)) {
System.out.println("Encontré la salida — exploré " + fmt(n) + " posiciones.");
} else {
System.out.println("Es IMPOSIBLE llegar a la salida — exploré todo lo alcanzable (" + fmt(n) + " posiciones) sin encontrarla.");
}
}
/**
* Subprograma generado por freeDFDWeb, sin descripción en el diagrama original.
*
* @param filaAct double
* @param columnaAct double
* @param visFila double
* @param visColumna double
* @param n double
* @param direccionElegida double[] — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
* @param hayDireccion double[] — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
*/
static void BuscarDireccion(double filaAct, double columnaAct, double visFila, double visColumna, double n, double[] direccionElegida, double[] hayDireccion) {
ArrayList<Double> orden = new ArrayList<>();
double i = 0.0;
double d = 0.0;
double response_call = 0.0;
double[] filaC = {0.0}; // Arreglo de 1 elemento: simula paso por referencia (Java no permite mutar un double pasado a otro método) — se usa como "filaC[0]" en el resto del método
double[] columnaC = {0.0}; // Arreglo de 1 elemento: simula paso por referencia (Java no permite mutar un double pasado a otro método) — se usa como "columnaC[0]" en el resto del método
double[] visitado = {0.0}; // Arreglo de 1 elemento: simula paso por referencia (Java no permite mutar un double pasado a otro método) — se usa como "visitado[0]" en el resto del método
vecSet(orden, (int)(1), "ARRIBA");
vecSet(orden, (int)(2), "DERECHA");
vecSet(orden, (int)(3), "ABAJO");
vecSet(orden, (int)(4), "IZQUIERDA");
hayDireccion[0] = 0;
double _forStart1 = 1;
double _forEnd1 = 4;
double _forStep1 = 1;
if (_forStep1 == 0) { throw new RuntimeException("El incremento de \"para i\" no puede ser 0"); }
for (i = _forStart1; _forStep1 > 0 ? i <= _forEnd1 : i >= _forEnd1; i += _forStep1) {
if ((!((hayDireccion[0]) != 0))) {
d = vecGet(orden, (int)(i));
System.out.println("HayObstaculo(" + fmt(d) + ")"); // Componente interactivo no disponible en el código exportado
if ((!((response_call) != 0))) {
Delta(d, filaAct, columnaAct, filaC, columnaC);
EstaVisitado(filaC[0], columnaC[0], visFila, visColumna, n, visitado);
if ((!((visitado[0]) != 0))) {
direccionElegida[0] = d;
hayDireccion[0] = 1;
}
}
}
}
}
/**
* Subprograma generado por freeDFDWeb, sin descripción en el diagrama original.
*
* @param direccion double
* @param filaAct double
* @param columnaAct double
* @param filaC double[] — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
* @param columnaC double[] — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
*/
static void Delta(double direccion, double filaAct, double columnaAct, double[] filaC, double[] columnaC) {
double _switch2 = direccion;
if (_switch2 == 0.0) {
filaC[0] = (filaAct - 1);
columnaC[0] = columnaAct;
} else if (_switch2 == 0.0) {
filaC[0] = (filaAct + 1);
columnaC[0] = columnaAct;
} else if (_switch2 == 0.0) {
filaC[0] = filaAct;
columnaC[0] = (columnaAct - 1);
} else if (_switch2 == 0.0) {
filaC[0] = filaAct;
columnaC[0] = (columnaAct + 1);
} else {
}
}
/**
* Subprograma generado por freeDFDWeb, sin descripción en el diagrama original.
*
* @param filaC double
* @param columnaC double
* @param visFila ArrayList<Double>
* @param visColumna ArrayList<Double>
* @param n double
* @param resultado double[] — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
*/
static void EstaVisitado(double filaC, double columnaC, ArrayList<Double> visFila, ArrayList<Double> visColumna, double n, double[] resultado) {
double i = 0.0;
resultado[0] = 0;
double _forStart3 = 1;
double _forEnd3 = n;
double _forStep3 = 1;
if (_forStep3 == 0) { throw new RuntimeException("El incremento de \"para i\" no puede ser 0"); }
for (i = _forStart3; _forStep3 > 0 ? i <= _forEnd3 : i >= _forEnd3; i += _forStep3) {
if ((!((resultado[0]) != 0))) {
if (((((vecGet(visFila, (int)(i)) == filaC)) && ((vecGet(visColumna, (int)(i)) == columnaC))))) {
resultado[0] = 1;
}
}
}
}
/**
* Subprograma generado por freeDFDWeb, sin descripción en el diagrama original.
*
* @param direccion double
* @param resultado String[] — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
*/
static void Opuesta(double direccion, String[] resultado) {
double _switch4 = direccion;
if (_switch4 == 0.0) {
resultado[0] = "ABAJO";
} else if (_switch4 == 0.0) {
resultado[0] = "ARRIBA";
} else if (_switch4 == 0.0) {
resultado[0] = "DERECHA";
} else if (_switch4 == 0.0) {
resultado[0] = "IZQUIERDA";
} else {
}
}
static boolean readBoolean(Scanner scanner) {
String t = scanner.nextLine().trim().toLowerCase();
if (t.equals("verdadero") || t.equals("true") || t.equals("1")) return true;
if (t.equals("falso") || t.equals("false") || t.equals("0")) return false;
throw new RuntimeException("Se esperaba Verdadero o Falso, se recibio: " + t);
}
static double readDouble(Scanner scanner) {
return Double.parseDouble(scanner.nextLine().trim());
}
static ArrayList<Double> readVector(Scanner scanner) {
ArrayList<Double> result = new ArrayList<>();
for (String token : scanner.nextLine().split(",")) {
String t = token.trim();
if (!t.isEmpty()) result.add(Double.parseDouble(t));
}
return result;
}
/** Formatea un double sin ".0" final cuando es entero — replica cómo freeDFDWeb (JS) imprime números, ej. factorial(5) debe mostrar "120", no "120.0". */
static String fmt(double d) {
if (!Double.isInfinite(d) && !Double.isNaN(d) && d == Math.floor(d) && Math.abs(d) < 1e15) {
return String.valueOf((long) d);
}
return String.valueOf(d);
}
/** `String.valueOf(true)` da "true" — el pseudolenguaje escribe e imprime "Verdadero"/"Falso". */
static String boolStr(boolean b) {
return b ? "Verdadero" : "Falso";
}
/** `ToChar(n)` de Flowgorithm: código de carácter → carácter. `Character.toChars` cubre también los puntos fuera del BMP (emoji), que no caben en un `char`. */
static String toChar(double code) {
int c = (int) code;
if (c < 0 || c > 0x10FFFF) {
throw new RuntimeException("ToChar(" + c + "): codigo de caracter fuera de rango");
}
return new String(Character.toChars(c));
}
/** `ToFixed(r, i)` de Flowgorithm: TRUNCA a `i` decimales, no redondea. `Locale.ROOT` para que el separador sea el punto siempre, igual que el resto del generador. */
static String toFixed(double value, double digits) {
int d = (int) digits;
double factor = Math.pow(10, d);
double truncated = (double)(long)(value * factor) / factor;
return String.format(java.util.Locale.ROOT, "%." + d + "f", truncated);
}
static double vecGet(ArrayList<Double> v, int index) {
int i = index - 1;
if (i < 0 || i >= v.size() || v.get(i) == null) {
throw new RuntimeException("La posición " + index + " del vector no tiene un valor asignado todavía");
}
return v.get(i);
}
static void vecSet(ArrayList<Double> v, int index, double value) {
int i = index - 1;
while (v.size() <= i) v.add(null);
v.set(i, value);
}
static double div(double a, double b) {
if (b == 0) throw new ArithmeticException("División por cero");
return a / b;
}
static double mod(double a, double b) {
if (b == 0) throw new ArithmeticException("Módulo por cero");
return a % b;
}
static void sleep(double seconds) {
try { Thread.sleep((long) (seconds * 1000)); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
}
}
El mismo algoritmo en Python
#!/usr/bin/env python3
"""Mismo algoritmo que el otro ejemplo de nivel 3, pero cargado contra un laberinto deliberadamente SIN SOLUCIÓN (la salida está completamente sellada). Demuestra la otra mitad del ejercicio: el algoritmo explora todo lo alcanzable y concluye "imposible" con certeza, en vez de trabarse o dar una respuesta incorrecta."""
import math
import random
import sys
import time
import datetime
class DfdRuntimeError(Exception):
pass
def read_boolean():
t = input().strip().lower()
if t in ('verdadero', 'true', '1'):
return True
if t in ('falso', 'false', '0'):
return False
raise DfdRuntimeError('Se esperaba Verdadero o Falso, se recibio: ' + t)
def read_double():
return float(input().strip())
def read_vector():
return [float(t.strip()) for t in input().split(',') if t.strip() != '']
def fmt(d):
"""Formatea sin ".0" final cuando es entero — replica cómo freeDFDWeb (JS) imprime números."""
if math.isinf(d):
return 'Infinity' if d > 0 else '-Infinity'
if math.isnan(d):
return 'NaN'
if d == math.floor(d) and abs(d) < 1e15:
return str(int(d))
return str(d)
def bool_str(b):
"""`str(True)` da "True" (mayúscula) — el pseudolenguaje escribe e imprime "Verdadero"/"Falso"."""
return 'Verdadero' if b else 'Falso'
def sgn(x):
"""`Sgn(n)` de Flowgorithm. Devuelve x tal cual en el cero para conservar el signo del -0.0, igual que `Math.sign` de JS."""
if math.isnan(x):
return x
if x > 0:
return 1.0
if x < 0:
return -1.0
return x
def to_fixed(value, digits):
"""`ToFixed(r, i)` de Flowgorithm: TRUNCA a i decimales, no redondea."""
d = int(digits)
factor = 10 ** d
truncated = math.trunc(value * factor) / factor
return f'{truncated:.{d}f}'
def vec_get(v, index):
i = index - 1
if i < 0 or i >= len(v) or v[i] is None:
raise DfdRuntimeError(f'La posición {index} del vector no tiene un valor asignado todavía')
return v[i]
def vec_set(v, index, value):
i = index - 1
while len(v) <= i:
v.append(None)
v[i] = value
def div(a, b):
if b == 0:
raise DfdRuntimeError('División por cero')
return a / b
def mod(a, b):
if b == 0:
raise DfdRuntimeError('Módulo por cero')
# `math.fmod`, NUNCA el `%` nativo de Python — el signo del resultado de
# `%` en Python sigue al DIVISOR (-7 % 3 == 2), mientras que JS (y el
# intérprete real) usan resto con signo del DIVIDENDO (-7 % 3 == -1),
# que es exactamente lo que `math.fmod` reproduce.
return math.fmod(a, b)
def redon(x):
"""Redondeo tipo `Math.round` de JS (.5 siempre hacia +Infinity) — NUNCA `round()` nativo de Python (redondeo bancario: round(2.5) == 2)."""
return math.floor(x + 0.5)
def BuscarDireccion(filaAct, columnaAct, visFila, visColumna, n, direccionElegida, hayDireccion):
"""
Subprograma generado por freeDFDWeb, sin descripción en el diagrama original.
Args:
filaAct: float
columnaAct: float
visFila: float
visColumna: float
n: float
direccionElegida: float — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
hayDireccion: float — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
"""
orden = []
filaC = [0.0] # Lista de 1 elemento: simula paso por referencia (Python no permite mutar un float pasado a otra función) — se usa como "filaC[0]" en el resto de la función
columnaC = [0.0] # Lista de 1 elemento: simula paso por referencia (Python no permite mutar un float pasado a otra función) — se usa como "columnaC[0]" en el resto de la función
visitado = [0.0] # Lista de 1 elemento: simula paso por referencia (Python no permite mutar un float pasado a otra función) — se usa como "visitado[0]" en el resto de la función
vec_set(orden, int(1), "ARRIBA")
vec_set(orden, int(2), "DERECHA")
vec_set(orden, int(3), "ABAJO")
vec_set(orden, int(4), "IZQUIERDA")
hayDireccion[0] = 0
_for_start_1 = 1
_for_end_1 = 4
_for_step_1 = 1
if _for_step_1 == 0:
raise DfdRuntimeError('El incremento de "para i" no puede ser 0')
i = _for_start_1
while (i <= _for_end_1) if _for_step_1 > 0 else (i >= _for_end_1):
if (not (hayDireccion[0] != 0)):
d = vec_get(orden, int(i))
print("HayObstaculo(" + fmt(d) + ")") # Componente interactivo no disponible en el código exportado
if (not (response_call != 0)):
Delta(d, filaAct, columnaAct, filaC, columnaC)
EstaVisitado(filaC[0], columnaC[0], visFila, visColumna, n, visitado)
if (not (visitado[0] != 0)):
direccionElegida[0] = d
hayDireccion[0] = 1
i += _for_step_1
def Delta(direccion, filaAct, columnaAct, filaC, columnaC):
"""
Subprograma generado por freeDFDWeb, sin descripción en el diagrama original.
Args:
direccion: float
filaAct: float
columnaAct: float
filaC: float — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
columnaC: float — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
"""
_switch_2 = direccion
if _switch_2 == 0:
filaC[0] = (filaAct - 1)
columnaC[0] = columnaAct
elif _switch_2 == 0:
filaC[0] = (filaAct + 1)
columnaC[0] = columnaAct
elif _switch_2 == 0:
filaC[0] = filaAct
columnaC[0] = (columnaAct - 1)
elif _switch_2 == 0:
filaC[0] = filaAct
columnaC[0] = (columnaAct + 1)
else:
pass
def EstaVisitado(filaC, columnaC, visFila, visColumna, n, resultado):
"""
Subprograma generado por freeDFDWeb, sin descripción en el diagrama original.
Args:
filaC: float
columnaC: float
visFila: list[float]
visColumna: list[float]
n: float
resultado: float — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
"""
resultado[0] = 0
_for_start_3 = 1
_for_end_3 = n
_for_step_3 = 1
if _for_step_3 == 0:
raise DfdRuntimeError('El incremento de "para i" no puede ser 0')
i = _for_start_3
while (i <= _for_end_3) if _for_step_3 > 0 else (i >= _for_end_3):
if (not (resultado[0] != 0)):
if ((vec_get(visFila, int(i)) == filaC) and (vec_get(visColumna, int(i)) == columnaC)):
resultado[0] = 1
i += _for_step_3
def Opuesta(direccion, resultado):
"""
Subprograma generado por freeDFDWeb, sin descripción en el diagrama original.
Args:
direccion: float
resultado: str — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
"""
_switch_4 = direccion
if _switch_4 == 0:
resultado[0] = "ABAJO"
elif _switch_4 == 0:
resultado[0] = "ARRIBA"
elif _switch_4 == 0:
resultado[0] = "DERECHA"
elif _switch_4 == 0:
resultado[0] = "IZQUIERDA"
else:
pass
def main():
fila = [0.0] # Lista de 1 elemento: simula paso por referencia (Python no permite mutar un float pasado a otra función) — se usa como "fila[0]" en el resto de la función
columna = [0.0] # Lista de 1 elemento: simula paso por referencia (Python no permite mutar un float pasado a otra función) — se usa como "columna[0]" en el resto de la función
visFila = []
visColumna = []
direccionElegida = [0.0] # Lista de 1 elemento: simula paso por referencia (Python no permite mutar un float pasado a otra función) — se usa como "direccionElegida[0]" en el resto de la función
hayDireccion = [0.0] # Lista de 1 elemento: simula paso por referencia (Python no permite mutar un float pasado a otra función) — se usa como "hayDireccion[0]" en el resto de la función
pilaDir = []
direccionVolver = [0.0] # Lista de 1 elemento: simula paso por referencia (Python no permite mutar un float pasado a otra función) — se usa como "direccionVolver[0]" en el resto de la función
print("Activar(" + "Laberinto" + ")") # Componente interactivo no disponible en el código exportado
print("CargarEscenario(" + "trampa" + ")") # Componente interactivo no disponible en el código exportado
fila[0] = 1
columna[0] = 1
n = 1
vec_set(visFila, int(1), fila[0])
vec_set(visColumna, int(1), columna[0])
profundidad = 0
encontrado = 0
imposible = 0
while ((not (encontrado != 0)) and (not (imposible != 0))):
print("Llegue(" + "" + ")") # Componente interactivo no disponible en el código exportado
if (response_call != 0):
encontrado = 1
else:
BuscarDireccion(fila[0], columna[0], visFila, visColumna, n, direccionElegida, hayDireccion)
if (hayDireccion[0] != 0):
print("MOVER(" + fmt(direccionElegida[0]) + ", " + fmt(1) + ")") # Componente interactivo no disponible en el código exportado
Delta(direccionElegida[0], fila[0], columna[0], fila, columna)
n = (n + 1)
vec_set(visFila, int(n), fila[0])
vec_set(visColumna, int(n), columna[0])
profundidad = (profundidad + 1)
vec_set(pilaDir, int(profundidad), direccionElegida[0])
else:
if (profundidad == 0):
imposible = 1
else:
direccionTomada = vec_get(pilaDir, int(profundidad))
profundidad = (profundidad - 1)
Opuesta(direccionTomada, direccionVolver)
print("MOVER(" + fmt(direccionVolver[0]) + ", " + fmt(1) + ")") # Componente interactivo no disponible en el código exportado
Delta(direccionVolver[0], fila[0], columna[0], fila, columna)
if (encontrado != 0):
print("Encontré la salida — exploré " + fmt(n) + " posiciones.")
else:
print("Es IMPOSIBLE llegar a la salida — exploré todo lo alcanzable (" + fmt(n) + " posiciones) sin encontrarla.")
if __name__ == '__main__':
main()
El mismo algoritmo en C#
using System;
using System.Collections.Generic;
using System.Globalization;
/// <summary>Excepción propia para errores de ejecución del programa generado (división por cero, índice de vector sin asignar, etc.) — mismo criterio que el `RuntimeError` real de freeDFDWeb.</summary>
class DfdRuntimeException : Exception {
public DfdRuntimeException(string message) : base(message) { }
}
/// <summary>
/// Mismo algoritmo que el otro ejemplo de nivel 3, pero cargado contra un laberinto deliberadamente SIN SOLUCIÓN (la salida está completamente sellada). Demuestra la otra mitad del ejercicio: el algoritmo explora todo lo alcanzable y concluye "imposible" con certeza, en vez de trabarse o dar una respuesta incorrecta.
/// </summary>
class Program {
/// <summary>
/// Punto de entrada del programa generado por freeDFDWeb.
/// </summary>
/// <param name="args">no utilizado — freeDFDWeb no pasa argumentos de línea de comandos.</param>
static void Main(string[] args) {
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
double fila = 0.0;
double columna = 0.0;
double n = 0.0;
List<double?> visFila = new List<double?>();
List<double?> visColumna = new List<double?>();
double profundidad = 0.0;
double encontrado = 0.0;
double imposible = 0.0;
double response_call = 0.0;
double direccionElegida = 0.0;
double hayDireccion = 0.0;
List<double?> pilaDir = new List<double?>();
double direccionTomada = 0.0;
double direccionVolver = 0.0;
Console.WriteLine("Activar(" + "Laberinto" + ")"); // Componente interactivo no disponible en el código exportado
Console.WriteLine("CargarEscenario(" + "trampa" + ")"); // Componente interactivo no disponible en el código exportado
fila = 1;
columna = 1;
n = 1;
VecSet(visFila, (int)(1), fila);
VecSet(visColumna, (int)(1), columna);
profundidad = 0;
encontrado = 0;
imposible = 0;
while ((!((encontrado) != 0) && !((imposible) != 0))) {
Console.WriteLine("Llegue(" + "" + ")"); // Componente interactivo no disponible en el código exportado
if (((response_call) != 0)) {
encontrado = 1;
} else {
BuscarDireccion(fila, columna, visFila, visColumna, n, ref direccionElegida, ref hayDireccion);
if (((hayDireccion) != 0)) {
Console.WriteLine("MOVER(" + Fmt(direccionElegida) + ", " + Fmt(1) + ")"); // Componente interactivo no disponible en el código exportado
Delta(direccionElegida, fila, columna, ref fila, ref columna);
n = (n + 1);
VecSet(visFila, (int)(n), fila);
VecSet(visColumna, (int)(n), columna);
profundidad = (profundidad + 1);
VecSet(pilaDir, (int)(profundidad), direccionElegida);
} else {
if ((profundidad == 0)) {
imposible = 1;
} else {
direccionTomada = VecGet(pilaDir, (int)(profundidad));
profundidad = (profundidad - 1);
Opuesta(direccionTomada, ref direccionVolver);
Console.WriteLine("MOVER(" + Fmt(direccionVolver) + ", " + Fmt(1) + ")"); // Componente interactivo no disponible en el código exportado
Delta(direccionVolver, fila, columna, ref fila, ref columna);
}
}
}
}
if (((encontrado) != 0)) {
Console.WriteLine("Encontré la salida — exploré " + Fmt(n) + " posiciones.");
} else {
Console.WriteLine("Es IMPOSIBLE llegar a la salida — exploré todo lo alcanzable (" + Fmt(n) + " posiciones) sin encontrarla.");
}
}
/// <summary>
/// Subprograma generado por freeDFDWeb, sin descripción en el diagrama original.
/// </summary>
/// <param name="filaAct">double</param>
/// <param name="columnaAct">double</param>
/// <param name="visFila">double</param>
/// <param name="visColumna">double</param>
/// <param name="n">double</param>
/// <param name="direccionElegida">double — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)</param>
/// <param name="hayDireccion">double — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)</param>
static void BuscarDireccion(double filaAct, double columnaAct, double visFila, double visColumna, double n, ref double direccionElegida, ref double hayDireccion) {
List<double?> orden = new List<double?>();
double i = 0.0;
double d = 0.0;
double response_call = 0.0;
double filaC = 0.0;
double columnaC = 0.0;
double visitado = 0.0;
VecSet(orden, (int)(1), "ARRIBA");
VecSet(orden, (int)(2), "DERECHA");
VecSet(orden, (int)(3), "ABAJO");
VecSet(orden, (int)(4), "IZQUIERDA");
hayDireccion = 0;
double _forStart1 = 1;
double _forEnd1 = 4;
double _forStep1 = 1;
if (_forStep1 == 0) { throw new DfdRuntimeException("El incremento de \"para i\" no puede ser 0"); }
for (i = _forStart1; _forStep1 > 0 ? i <= _forEnd1 : i >= _forEnd1; i += _forStep1) {
if (!((hayDireccion) != 0)) {
d = VecGet(orden, (int)(i));
Console.WriteLine("HayObstaculo(" + Fmt(d) + ")"); // Componente interactivo no disponible en el código exportado
if (!((response_call) != 0)) {
Delta(d, filaAct, columnaAct, ref filaC, ref columnaC);
EstaVisitado(filaC, columnaC, visFila, visColumna, n, ref visitado);
if (!((visitado) != 0)) {
direccionElegida = d;
hayDireccion = 1;
}
}
}
}
}
/// <summary>
/// Subprograma generado por freeDFDWeb, sin descripción en el diagrama original.
/// </summary>
/// <param name="direccion">double</param>
/// <param name="filaAct">double</param>
/// <param name="columnaAct">double</param>
/// <param name="filaC">double — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)</param>
/// <param name="columnaC">double — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)</param>
static void Delta(double direccion, double filaAct, double columnaAct, ref double filaC, ref double columnaC) {
double _switch2 = direccion;
if (_switch2 == 0.0) {
filaC = (filaAct - 1);
columnaC = columnaAct;
} else if (_switch2 == 0.0) {
filaC = (filaAct + 1);
columnaC = columnaAct;
} else if (_switch2 == 0.0) {
filaC = filaAct;
columnaC = (columnaAct - 1);
} else if (_switch2 == 0.0) {
filaC = filaAct;
columnaC = (columnaAct + 1);
} else {
}
}
/// <summary>
/// Subprograma generado por freeDFDWeb, sin descripción en el diagrama original.
/// </summary>
/// <param name="filaC">double</param>
/// <param name="columnaC">double</param>
/// <param name="visFila">List<double?></param>
/// <param name="visColumna">List<double?></param>
/// <param name="n">double</param>
/// <param name="resultado">double — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)</param>
static void EstaVisitado(double filaC, double columnaC, List<double?> visFila, List<double?> visColumna, double n, ref double resultado) {
double i = 0.0;
resultado = 0;
double _forStart3 = 1;
double _forEnd3 = n;
double _forStep3 = 1;
if (_forStep3 == 0) { throw new DfdRuntimeException("El incremento de \"para i\" no puede ser 0"); }
for (i = _forStart3; _forStep3 > 0 ? i <= _forEnd3 : i >= _forEnd3; i += _forStep3) {
if (!((resultado) != 0)) {
if (((VecGet(visFila, (int)(i)) == filaC) && (VecGet(visColumna, (int)(i)) == columnaC))) {
resultado = 1;
}
}
}
}
/// <summary>
/// Subprograma generado por freeDFDWeb, sin descripción en el diagrama original.
/// </summary>
/// <param name="direccion">double</param>
/// <param name="resultado">string — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)</param>
static void Opuesta(double direccion, ref string resultado) {
double _switch4 = direccion;
if (_switch4 == 0.0) {
resultado = "ABAJO";
} else if (_switch4 == 0.0) {
resultado = "ARRIBA";
} else if (_switch4 == 0.0) {
resultado = "DERECHA";
} else if (_switch4 == 0.0) {
resultado = "IZQUIERDA";
} else {
}
}
static readonly Random Rnd = new Random();
static bool ReadBoolean() {
string t = (Console.ReadLine() ?? "").Trim().ToLowerInvariant();
if (t == "verdadero" || t == "true" || t == "1") return true;
if (t == "falso" || t == "false" || t == "0") return false;
throw new Exception("Se esperaba Verdadero o Falso, se recibio: " + t);
}
static double ReadDouble() {
return double.Parse(Console.ReadLine().Trim(), CultureInfo.InvariantCulture);
}
static List<double?> ReadVector() {
List<double?> result = new List<double?>();
foreach (string token in Console.ReadLine().Split(',')) {
string t = token.Trim();
if (t.Length > 0) result.Add(double.Parse(t, CultureInfo.InvariantCulture));
}
return result;
}
/// <summary>Formatea un double sin ".0" final cuando es entero — replica cómo freeDFDWeb (JS) imprime números.</summary>
static string Fmt(double d) {
if (double.IsPositiveInfinity(d)) return "Infinity";
if (double.IsNegativeInfinity(d)) return "-Infinity";
if (double.IsNaN(d)) return "NaN";
if (d == Math.Floor(d) && Math.Abs(d) < 1e15) {
return ((long)d).ToString(CultureInfo.InvariantCulture);
}
return d.ToString(CultureInfo.InvariantCulture);
}
/// <summary>`true.ToString()` da "True" (mayúscula) — el pseudolenguaje escribe e imprime "Verdadero"/"Falso".</summary>
static string BoolStr(bool b) {
return b ? "Verdadero" : "Falso";
}
/// <summary>`Sgn(n)` de Flowgorithm. Helper y no `Math.Sign`: ese LANZA sobre NaN, mientras el intérprete devuelve NaN. Devuelve x en el cero para conservar el -0.0.</summary>
static double Sgn(double x) {
if (double.IsNaN(x)) return x;
if (x > 0) return 1.0;
if (x < 0) return -1.0;
return x;
}
/// <summary>`ToFixed(r, i)` de Flowgorithm: TRUNCA a i decimales, no redondea. `InvariantCulture` para que el separador sea el punto, igual que `Fmt`.</summary>
static string ToFixed(double value, double digits) {
int d = (int) digits;
double factor = Math.Pow(10, d);
double truncated = Math.Truncate(value * factor) / factor;
return truncated.ToString("F" + d, CultureInfo.InvariantCulture);
}
static double VecGet(List<double?> v, int index) {
int i = index - 1;
if (i < 0 || i >= v.Count || !v[i].HasValue) {
throw new DfdRuntimeException("La posición " + index + " del vector no tiene un valor asignado todavía");
}
return v[i].Value;
}
static void VecSet(List<double?> v, int index, double value) {
int i = index - 1;
while (v.Count <= i) v.Add(null);
v[i] = value;
}
static double Div(double a, double b) {
if (b == 0) throw new DfdRuntimeException("División por cero");
return a / b;
}
static double Mod(double a, double b) {
if (b == 0) throw new DfdRuntimeException("Módulo por cero");
// El operador `%` nativo de C# para `double` SÍ coincide con el
// signo de JS (confirmado real: -7 % 3 == -1 en ambos) — a
// diferencia de Python, no hace falta ningún wrapper de signo.
return a % b;
}
/// <summary>Redondeo tipo `Math.round` de JS (.5 siempre hacia +Infinity) — NUNCA `Math.Round()` directo (bancario en .NET: Math.Round(2.5) == 2).</summary>
static double Redon(double x) {
return Math.Floor(x + 0.5);
}
}
El mismo algoritmo en C++
#include <iostream>
#include <string>
#include <vector>
#include <optional>
#include <cmath>
#include <sstream>
#include <iomanip>
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <chrono>
#include <thread>
#include <charconv>
#include <stdexcept>
/**
* Mismo algoritmo que el otro ejemplo de nivel 3, pero cargado contra un laberinto deliberadamente SIN SOLUCIÓN (la salida está completamente sellada). Demuestra la otra mitad del ejercicio: el algoritmo explora todo lo alcanzable y concluye "imposible" con certeza, en vez de trabarse o dar una respuesta incorrecta.
*/
const double PI = 3.14159265358979323846;
class DfdRuntimeError : public std::runtime_error {
public:
explicit DfdRuntimeError(const std::string& message) : std::runtime_error(message) {}
};
std::string readLine() {
std::string line;
if (!std::getline(std::cin, line)) return "";
if (!line.empty() && line.back() == '\r') line.pop_back();
return line;
}
/** `std::stod` (usado por `toNumberOrThrow`) NO tira con texto no numérico de forma consistente en todos los casos (ignora sufijos raros) pero SÍ tira `std::invalid_argument` con texto totalmente no numérico — verificado real. Envuelto para relanzar como `DfdRuntimeError`, mismo tipo de excepción que el resto del programa generado. */
double toNumberOrThrow(const std::string& value) {
try {
return std::stod(value);
} catch (const std::exception&) {
throw DfdRuntimeError("Se esperaba un número, se encontró \"" + value + "\"");
}
}
bool readBoolean() {
std::string t = readLine();
for (auto& c : t) c = (char)std::tolower((unsigned char)c);
if (t == "verdadero" || t == "true" || t == "1") return true;
if (t == "falso" || t == "false" || t == "0") return false;
throw std::runtime_error("Se esperaba Verdadero o Falso, se recibio: " + t);
}
double readDouble() {
return toNumberOrThrow(readLine());
}
std::vector<std::optional<double>> readVector() {
std::vector<std::optional<double>> result;
std::stringstream ss(readLine());
std::string token;
while (std::getline(ss, token, ',')) {
size_t start = token.find_first_not_of(" \t");
size_t end = token.find_last_not_of(" \t");
if (start == std::string::npos) continue;
result.push_back(toNumberOrThrow(token.substr(start, end - start + 1)));
}
return result;
}
/** Formatea sin ".0" final cuando es entero, con representación de ida y vuelta exacta para decimales (`std::to_chars`, C++17) — replica cómo freeDFDWeb (JS) imprime números. Diverge de JS solo en notación científica de magnitudes extremas (ver comentario de cabecera del archivo), gap aceptado. */
std::string fmt(double d) {
if (std::isinf(d)) return d > 0 ? "Infinity" : "-Infinity";
if (std::isnan(d)) return "NaN";
char buf[64];
if (d == std::floor(d) && std::abs(d) < 1e15) {
auto res = std::to_chars(buf, buf + sizeof(buf), (long long)d);
return std::string(buf, res.ptr);
}
auto res = std::to_chars(buf, buf + sizeof(buf), d);
return std::string(buf, res.ptr);
}
/** `std::cout << bool` imprime "1"/"0" — el pseudolenguaje escribe e imprime "Verdadero"/"Falso". */
std::string boolStr(bool b) {
return b ? "Verdadero" : "Falso";
}
/** `Sgn(n)` de Flowgorithm. Devuelve x en el cero para conservar el signo del -0.0, igual que `Math.sign` de JS. */
double sgn(double x) {
if (std::isnan(x)) return x;
if (x > 0) return 1.0;
if (x < 0) return -1.0;
return x;
}
/** `ToChar(n)`: punto de código → carácter. C++ es el único destino sin conversión nativa, así que codifica UTF-8 a mano — `std::string` acá son bytes, no puntos de código. */
std::string toCharStr(double code) {
long long c = (long long) code;
if (c < 0 || c > 0x10FFFF) {
throw DfdRuntimeError("ToChar(" + std::to_string(c) + "): codigo de caracter fuera de rango");
}
std::string out;
if (c < 0x80) {
out += (char)c;
} else if (c < 0x800) {
out += (char)(0xC0 | (c >> 6));
out += (char)(0x80 | (c & 0x3F));
} else if (c < 0x10000) {
out += (char)(0xE0 | (c >> 12));
out += (char)(0x80 | ((c >> 6) & 0x3F));
out += (char)(0x80 | (c & 0x3F));
} else {
out += (char)(0xF0 | (c >> 18));
out += (char)(0x80 | ((c >> 12) & 0x3F));
out += (char)(0x80 | ((c >> 6) & 0x3F));
out += (char)(0x80 | (c & 0x3F));
}
return out;
}
/** `ToCode(c)`: inversa de `toCharStr` — decodifica el PRIMER punto de código UTF-8, no el primer byte (si no, una "ñ" daría 195). */
double toCode(const std::string& s) {
if (s.empty()) {
throw DfdRuntimeError("ToCode espera un texto de un caracter");
}
unsigned char b0 = (unsigned char)s[0];
if (b0 < 0x80) return (double)b0;
int extra = (b0 >= 0xF0) ? 3 : (b0 >= 0xE0) ? 2 : 1;
long long cp = b0 & (0x3F >> extra);
for (int i = 1; i <= extra; i++) {
if ((size_t)i >= s.size()) {
throw DfdRuntimeError("ToCode: texto UTF-8 mal formado");
}
cp = (cp << 6) | ((unsigned char)s[i] & 0x3F);
}
return (double)cp;
}
/** `ToFixed(r, i)` de Flowgorithm: TRUNCA a i decimales, no redondea. */
std::string toFixed(double value, double digits) {
int d = (int) digits;
double factor = std::pow(10.0, d);
double truncated = std::trunc(value * factor) / factor;
std::ostringstream out;
out << std::fixed << std::setprecision(d) << truncated;
return out.str();
}
std::string toUpperStr(const std::string& s) {
std::string result = s;
std::transform(result.begin(), result.end(), result.begin(), [](unsigned char c) { return std::toupper(c); });
return result;
}
std::string toLowerStr(const std::string& s) {
std::string result = s;
std::transform(result.begin(), result.end(), result.begin(), [](unsigned char c) { return std::tolower(c); });
return result;
}
double vecGet(std::vector<std::optional<double>>& v, int index) {
int i = index - 1;
if (i < 0 || (size_t)i >= v.size() || !v[i].has_value()) {
throw DfdRuntimeError("La posición " + std::to_string(index) + " del vector no tiene un valor asignado todavía");
}
return *v[i];
}
void vecSet(std::vector<std::optional<double>>& v, int index, double value) {
int i = index - 1;
if ((size_t)(i + 1) > v.size()) v.resize(i + 1);
v[i] = value;
}
/**
* `dividir` y no `div`, que sería el nombre obvio: `div` YA EXISTE en la
* biblioteca estándar de C (`<cstdlib>`, devuelve un `div_t`) y está
* declarada aunque no se incluya ese encabezado. Con dos literales
* enteros, `div(7, 2)` resuelve a la versión de C —coincidencia exacta—
* y el programa generado NO COMPILA:
*
* error: cannot convert 'div_t' to 'double'
*
* O sea: CUALQUIER programa con una división fallaba al exportar a C++.
* Encontrado el 30-oct-2026 compilando de verdad lo exportado
* (`scripts/equivalencia/comparar.mjs`); ninguna prueba lo veía porque
* ninguna compilaba C++.
*/
double dividir(double a, double b) {
if (b == 0) throw DfdRuntimeError("División por cero");
return a / b;
}
double mod(double a, double b) {
if (b == 0) throw DfdRuntimeError("Módulo por cero");
// `%` NO COMPILA sobre `double` en C++ — `std::fmod` es la única forma.
// Su signo SÍ coincide con JS (confirmado real), a diferencia de
// Python, que necesitaba un wrapper de signo además del de cero.
return std::fmod(a, b);
}
/** Redondeo tipo `Math.round` de JS (.5 siempre hacia +Infinity) — NUNCA `std::round()` directo (redondea siempre alejándose de cero: round(-2.5) == -3, distinto de Math.round(-2.5) == -2). */
double redon(double x) {
return std::floor(x + 0.5);
}
// ---------------------------------------------------------------------------
// Programa
// ---------------------------------------------------------------------------
/**
* Subprograma generado por freeDFDWeb, sin descripción en el diagrama original.
* @param filaAct double
* @param columnaAct double
* @param visFila double
* @param visColumna double
* @param n double
* @param direccionElegida double — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
* @param hayDireccion double — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
*/
void BuscarDireccion(double filaAct, double columnaAct, double visFila, double visColumna, double n, double& direccionElegida, double& hayDireccion) {
std::vector<std::optional<double>> orden;
double i = 0.0;
double d = 0.0;
double response_call = 0.0;
double filaC = 0.0;
double columnaC = 0.0;
double visitado = 0.0;
vecSet(orden, (int)(1), std::string("ARRIBA"));
vecSet(orden, (int)(2), std::string("DERECHA"));
vecSet(orden, (int)(3), std::string("ABAJO"));
vecSet(orden, (int)(4), std::string("IZQUIERDA"));
hayDireccion = 0;
double _forStart1 = 1;
double _forEnd1 = 4;
double _forStep1 = 1;
if (_forStep1 == 0) { throw DfdRuntimeError("El incremento de \"para i\" no puede ser 0"); }
for (i = _forStart1; _forStep1 > 0 ? i <= _forEnd1 : i >= _forEnd1; i += _forStep1) {
if (!((hayDireccion) != 0)) {
d = vecGet(orden, (int)(i));
std::cout << (std::string("HayObstaculo(") + fmt(d) + ")") << "\n"; // Componente interactivo no disponible en el código exportado
if (!((response_call) != 0)) {
Delta(d, filaAct, columnaAct, filaC, columnaC);
EstaVisitado(filaC, columnaC, visFila, visColumna, n, visitado);
if (!((visitado) != 0)) {
direccionElegida = d;
hayDireccion = 1;
}
}
}
}
}
/**
* Subprograma generado por freeDFDWeb, sin descripción en el diagrama original.
* @param direccion double
* @param filaAct double
* @param columnaAct double
* @param filaC double — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
* @param columnaC double — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
*/
void Delta(double direccion, double filaAct, double columnaAct, double& filaC, double& columnaC) {
double _switch2 = direccion;
if (_switch2 == 0.0) {
filaC = (filaAct - 1);
columnaC = columnaAct;
} else if (_switch2 == 0.0) {
filaC = (filaAct + 1);
columnaC = columnaAct;
} else if (_switch2 == 0.0) {
filaC = filaAct;
columnaC = (columnaAct - 1);
} else if (_switch2 == 0.0) {
filaC = filaAct;
columnaC = (columnaAct + 1);
} else {
}
}
/**
* Subprograma generado por freeDFDWeb, sin descripción en el diagrama original.
* @param filaC double
* @param columnaC double
* @param visFila std::vector<std::optional<double>>
* @param visColumna std::vector<std::optional<double>>
* @param n double
* @param resultado double — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
*/
void EstaVisitado(double filaC, double columnaC, std::vector<std::optional<double>> visFila, std::vector<std::optional<double>> visColumna, double n, double& resultado) {
double i = 0.0;
resultado = 0;
double _forStart3 = 1;
double _forEnd3 = n;
double _forStep3 = 1;
if (_forStep3 == 0) { throw DfdRuntimeError("El incremento de \"para i\" no puede ser 0"); }
for (i = _forStart3; _forStep3 > 0 ? i <= _forEnd3 : i >= _forEnd3; i += _forStep3) {
if (!((resultado) != 0)) {
if (((vecGet(visFila, (int)(i)) == filaC) && (vecGet(visColumna, (int)(i)) == columnaC))) {
resultado = 1;
}
}
}
}
/**
* Subprograma generado por freeDFDWeb, sin descripción en el diagrama original.
* @param direccion double
* @param resultado std::string — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
*/
void Opuesta(double direccion, std::string& resultado) {
double _switch4 = direccion;
if (_switch4 == 0.0) {
resultado = std::string("ABAJO");
} else if (_switch4 == 0.0) {
resultado = std::string("ARRIBA");
} else if (_switch4 == 0.0) {
resultado = std::string("DERECHA");
} else if (_switch4 == 0.0) {
resultado = std::string("IZQUIERDA");
} else {
}
}
/**
* Punto de entrada del programa generado por freeDFDWeb.
*/
int main() {
double fila = 0.0;
double columna = 0.0;
double n = 0.0;
std::vector<std::optional<double>> visFila;
std::vector<std::optional<double>> visColumna;
double profundidad = 0.0;
double encontrado = 0.0;
double imposible = 0.0;
double response_call = 0.0;
double direccionElegida = 0.0;
double hayDireccion = 0.0;
std::vector<std::optional<double>> pilaDir;
double direccionTomada = 0.0;
double direccionVolver = 0.0;
std::cout << (std::string("Activar(") + std::string("Laberinto") + ")") << "\n"; // Componente interactivo no disponible en el código exportado
std::cout << (std::string("CargarEscenario(") + std::string("trampa") + ")") << "\n"; // Componente interactivo no disponible en el código exportado
fila = 1;
columna = 1;
n = 1;
vecSet(visFila, (int)(1), fila);
vecSet(visColumna, (int)(1), columna);
profundidad = 0;
encontrado = 0;
imposible = 0;
while ((!((encontrado) != 0) && !((imposible) != 0))) {
std::cout << (std::string("Llegue(") + std::string("") + ")") << "\n"; // Componente interactivo no disponible en el código exportado
if (((response_call) != 0)) {
encontrado = 1;
} else {
BuscarDireccion(fila, columna, visFila, visColumna, n, direccionElegida, hayDireccion);
if (((hayDireccion) != 0)) {
std::cout << (std::string("MOVER(") + fmt(direccionElegida) + ", " + fmt(1) + ")") << "\n"; // Componente interactivo no disponible en el código exportado
Delta(direccionElegida, fila, columna, fila, columna);
n = (n + 1);
vecSet(visFila, (int)(n), fila);
vecSet(visColumna, (int)(n), columna);
profundidad = (profundidad + 1);
vecSet(pilaDir, (int)(profundidad), direccionElegida);
} else {
if ((profundidad == 0)) {
imposible = 1;
} else {
direccionTomada = vecGet(pilaDir, (int)(profundidad));
profundidad = (profundidad - 1);
Opuesta(direccionTomada, direccionVolver);
std::cout << (std::string("MOVER(") + fmt(direccionVolver) + ", " + fmt(1) + ")") << "\n"; // Componente interactivo no disponible en el código exportado
Delta(direccionVolver, fila, columna, fila, columna);
}
}
}
}
if (((encontrado) != 0)) {
std::cout << std::string("Encontré la salida — exploré ") + fmt(n) + std::string(" posiciones.") << "\n";
} else {
std::cout << std::string("Es IMPOSIBLE llegar a la salida — exploré todo lo alcanzable (") + fmt(n) + std::string(" posiciones) sin encontrarla.") << "\n";
}
return 0;
}
El mismo algoritmo en TypeScript
import * as fs from 'fs';
/**
* Mismo algoritmo que el otro ejemplo de nivel 3, pero cargado contra un laberinto deliberadamente SIN SOLUCIÓN (la salida está completamente sellada). Demuestra la otra mitad del ejercicio: el algoritmo explora todo lo alcanzable y concluye "imposible" con certeza, en vez de trabarse o dar una respuesta incorrecta.
*/
class DfdRuntimeError extends Error {}
const inputLines: string[] = fs.readFileSync(0, 'utf-8').split('\n');
let inputIndex = 0;
/** Toda la entrada se lee de una sola vez al arrancar (ver cabecera del archivo) — cada llamada consume la siguiente línea ya bufferizada. */
function readLine(): string {
return (inputLines[inputIndex++] ?? '').replace(/\r$/, '');
}
function readBoolean(): boolean {
const t = readLine().trim().toLowerCase();
if (t === 'verdadero' || t === 'true' || t === '1') return true;
if (t === 'falso' || t === 'false' || t === '0') return false;
throw new Error('Se esperaba Verdadero o Falso, se recibio: ' + t);
}
function readDouble(): number {
return toNumberOrThrow(readLine().trim());
}
function readVector(): (number | undefined)[] {
return readLine()
.split(',')
.map((t) => t.trim())
.filter((t) => t.length > 0)
.map((t) => toNumberOrThrow(t));
}
/** `Number(x)` nativo no tira error con texto no numérico (da `NaN`) — a diferencia del intérprete real (`toNumber`), que sí tira. Único punto donde este generador necesita reproducir ese comportamiento a mano. */
function toNumberOrThrow(value: string | number): number {
const n = Number(value);
if (Number.isNaN(n)) {
throw new DfdRuntimeError(`Se esperaba un número, se encontró "${value}"`);
}
return n;
}
/** `String(true)` da "true" — el pseudolenguaje escribe e imprime "Verdadero"/"Falso". */
function boolStr(b: boolean): string {
return b ? 'Verdadero' : 'Falso';
}
/** `ToFixed(r, i)` de Flowgorithm: TRUNCA a i decimales, no redondea — por eso no basta el `.toFixed()` nativo, que redondea. */
function toFixed(value: number, digits: number): string {
const d = Math.trunc(digits);
const factor = Math.pow(10, d);
return (Math.trunc(value * factor) / factor).toFixed(d);
}
function vecGet(v: (number | undefined)[], index: number): number {
const i = Math.trunc(index) - 1;
const value = v[i];
if (i < 0 || value === undefined) {
throw new DfdRuntimeError(`La posición ${index} del vector no tiene un valor asignado todavía`);
}
return value;
}
function vecSet(v: (number | undefined)[], index: number, value: number): void {
v[Math.trunc(index) - 1] = value;
}
function div(a: number, b: number): number {
if (b === 0) throw new DfdRuntimeError('División por cero');
return a / b;
}
function mod(a: number, b: number): number {
if (b === 0) throw new DfdRuntimeError('Módulo por cero');
// El `%` nativo de JS/TS coincide exacto con el del intérprete real
// (mismo motor) — a diferencia de Python, no hace falta ningún wrapper
// de signo, solo el chequeo de división por cero.
return a % b;
}
/**
* Generado por freeDFDWeb, sin descripción en el diagrama original.
* @param filaAct number
* @param columnaAct number
* @param visFila number
* @param visColumna number
* @param n number
* @param direccionElegida number[] — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
* @param hayDireccion number[] — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
*/
function BuscarDireccion(filaAct: number, columnaAct: number, visFila: number, visColumna: number, n: number, direccionElegida: number[], hayDireccion: number[]): void {
let orden: (number | undefined)[] = [];
let i: number = 0;
let d: number = 0;
let response_call: number = 0;
let filaC: number[] = [0]; // Arreglo de 1 elemento: simula paso por referencia (JS/TS no tiene parámetros por referencia para primitivos) — se usa como "filaC[0]" en el resto de la función
let columnaC: number[] = [0]; // Arreglo de 1 elemento: simula paso por referencia (JS/TS no tiene parámetros por referencia para primitivos) — se usa como "columnaC[0]" en el resto de la función
let visitado: number[] = [0]; // Arreglo de 1 elemento: simula paso por referencia (JS/TS no tiene parámetros por referencia para primitivos) — se usa como "visitado[0]" en el resto de la función
vecSet(orden, 1, "ARRIBA");
vecSet(orden, 2, "DERECHA");
vecSet(orden, 3, "ABAJO");
vecSet(orden, 4, "IZQUIERDA");
hayDireccion[0] = 0;
const _forStart1 = 1;
const _forEnd1 = 4;
const _forStep1 = 1;
if (_forStep1 === 0) { throw new DfdRuntimeError("El incremento de \"para i\" no puede ser 0"); }
for (i = _forStart1; _forStep1 > 0 ? i <= _forEnd1 : i >= _forEnd1; i += _forStep1) {
if (!((hayDireccion[0]) !== 0)) {
d = vecGet(orden, i);
console.log("HayObstaculo(" + String(d) + ")"); // Componente interactivo no disponible en el código exportado
if (!((response_call) !== 0)) {
Delta(d, filaAct, columnaAct, filaC, columnaC);
EstaVisitado(filaC[0], columnaC[0], visFila, visColumna, n, visitado);
if (!((visitado[0]) !== 0)) {
direccionElegida[0] = d;
hayDireccion[0] = 1;
}
}
}
}
}
/**
* Generado por freeDFDWeb, sin descripción en el diagrama original.
* @param direccion number
* @param filaAct number
* @param columnaAct number
* @param filaC number[] — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
* @param columnaC number[] — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
*/
function Delta(direccion: number, filaAct: number, columnaAct: number, filaC: number[], columnaC: number[]): void {
const _switch2: number = direccion;
if (_switch2 === 0) {
filaC[0] = (filaAct - 1);
columnaC[0] = columnaAct;
} else if (_switch2 === 0) {
filaC[0] = (filaAct + 1);
columnaC[0] = columnaAct;
} else if (_switch2 === 0) {
filaC[0] = filaAct;
columnaC[0] = (columnaAct - 1);
} else if (_switch2 === 0) {
filaC[0] = filaAct;
columnaC[0] = (columnaAct + 1);
} else {
}
}
/**
* Generado por freeDFDWeb, sin descripción en el diagrama original.
* @param filaC number
* @param columnaC number
* @param visFila (number | undefined)[]
* @param visColumna (number | undefined)[]
* @param n number
* @param resultado number[] — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
*/
function EstaVisitado(filaC: number, columnaC: number, visFila: (number | undefined)[], visColumna: (number | undefined)[], n: number, resultado: number[]): void {
let i: number = 0;
resultado[0] = 0;
const _forStart3 = 1;
const _forEnd3 = n;
const _forStep3 = 1;
if (_forStep3 === 0) { throw new DfdRuntimeError("El incremento de \"para i\" no puede ser 0"); }
for (i = _forStart3; _forStep3 > 0 ? i <= _forEnd3 : i >= _forEnd3; i += _forStep3) {
if (!((resultado[0]) !== 0)) {
if (((vecGet(visFila, i) === filaC) && (vecGet(visColumna, i) === columnaC))) {
resultado[0] = 1;
}
}
}
}
/**
* Generado por freeDFDWeb, sin descripción en el diagrama original.
* @param direccion number
* @param resultado string[] — por referencia (el subprograma lo reasigna; el valor final es visible para quien llama)
*/
function Opuesta(direccion: number, resultado: string[]): void {
const _switch4: number = direccion;
if (_switch4 === 0) {
resultado[0] = "ABAJO";
} else if (_switch4 === 0) {
resultado[0] = "ARRIBA";
} else if (_switch4 === 0) {
resultado[0] = "DERECHA";
} else if (_switch4 === 0) {
resultado[0] = "IZQUIERDA";
} else {
}
}
/**
* Punto de entrada del programa generado por freeDFDWeb.
*/
function main(): void {
let fila: number[] = [0]; // Arreglo de 1 elemento: simula paso por referencia (JS/TS no tiene parámetros por referencia para primitivos) — se usa como "fila[0]" en el resto de la función
let columna: number[] = [0]; // Arreglo de 1 elemento: simula paso por referencia (JS/TS no tiene parámetros por referencia para primitivos) — se usa como "columna[0]" en el resto de la función
let n: number = 0;
let visFila: (number | undefined)[] = [];
let visColumna: (number | undefined)[] = [];
let profundidad: number = 0;
let encontrado: number = 0;
let imposible: number = 0;
let response_call: number = 0;
let direccionElegida: number[] = [0]; // Arreglo de 1 elemento: simula paso por referencia (JS/TS no tiene parámetros por referencia para primitivos) — se usa como "direccionElegida[0]" en el resto de la función
let hayDireccion: number[] = [0]; // Arreglo de 1 elemento: simula paso por referencia (JS/TS no tiene parámetros por referencia para primitivos) — se usa como "hayDireccion[0]" en el resto de la función
let pilaDir: (number | undefined)[] = [];
let direccionTomada: number = 0;
let direccionVolver: number[] = [0]; // Arreglo de 1 elemento: simula paso por referencia (JS/TS no tiene parámetros por referencia para primitivos) — se usa como "direccionVolver[0]" en el resto de la función
console.log("Activar(" + "Laberinto" + ")"); // Componente interactivo no disponible en el código exportado
console.log("CargarEscenario(" + "trampa" + ")"); // Componente interactivo no disponible en el código exportado
fila[0] = 1;
columna[0] = 1;
n = 1;
vecSet(visFila, 1, fila[0]);
vecSet(visColumna, 1, columna[0]);
profundidad = 0;
encontrado = 0;
imposible = 0;
while ((!((encontrado) !== 0) && !((imposible) !== 0))) {
console.log("Llegue(" + "" + ")"); // Componente interactivo no disponible en el código exportado
if (((response_call) !== 0)) {
encontrado = 1;
} else {
BuscarDireccion(fila[0], columna[0], visFila, visColumna, n, direccionElegida, hayDireccion);
if (((hayDireccion[0]) !== 0)) {
console.log("MOVER(" + String(direccionElegida[0]) + ", " + String(1) + ")"); // Componente interactivo no disponible en el código exportado
Delta(direccionElegida[0], fila[0], columna[0], fila, columna);
n = (n + 1);
vecSet(visFila, n, fila[0]);
vecSet(visColumna, n, columna[0]);
profundidad = (profundidad + 1);
vecSet(pilaDir, profundidad, direccionElegida[0]);
} else {
if ((profundidad === 0)) {
imposible = 1;
} else {
direccionTomada = vecGet(pilaDir, profundidad);
profundidad = (profundidad - 1);
Opuesta(direccionTomada, direccionVolver);
console.log("MOVER(" + String(direccionVolver[0]) + ", " + String(1) + ")"); // Componente interactivo no disponible en el código exportado
Delta(direccionVolver[0], fila[0], columna[0], fila, columna);
}
}
}
}
if (((encontrado) !== 0)) {
console.log("Encontré la salida — exploré " + String(n) + " posiciones.");
} else {
console.log("Es IMPOSIBLE llegar a la salida — exploré todo lo alcanzable (" + String(n) + " posiciones) sin encontrarla.");
}
}
main();
Generado por freeDFDWeb desde el diagrama de arriba. Es el mismo archivo que descarga el botón Exportar del editor.
Abre y guarda en los formatos que ya usas
Importa y exporta PSeInt (.psc) y Flowgorithm (.fprg), y abre archivos .dfd del DFD clásico. Todo en el navegador, sin instalar nada: sirve en Windows, Mac, Linux, Chromebook y celular.