|
42
|
Programación / Programación General / Mejorar esta búsqueda del camino menos costoso.
|
en: 30 Marzo 2025, 10:08 am
|
Flash pone carteles si un proceso es muy largo así que lo dividí en frames. En ese sentido no es que digo de mejorarlo, eso es complicado. Escena 1 actions for fotograma 1 // De las permutaciones a crear: Largo = 1; // Primeras opciones y costos: // Largo de la permutación, id: L1P1 = "A"; L1P1Costo = 4; L1P1Opciones = ["B", "C", "D", "E", "F", "G", "H"]; L1P2 = "B"; L1P2Costo = 4; L1P2Opciones = ["A", "C", "D", "E", "F", "G", "H"]; L1P3 = "C"; L1P3Costo = 4; L1P3Opciones = ["A", "B", "D", "E", "F", "G", "H"]; L1P4 = "D"; L1P4Costo = 4; L1P4Opciones = ["A", "B", "C", "E", "F", "G", "H"]; L1P5 = "E"; L1P5Costo = 2; L1P5Opciones = ["A", "B", "C", "D", "F", "G", "H"]; L1P6 = "F"; L1P6Costo = 2; L1P6Opciones = ["A", "B", "C", "D", "E", "G", "H"]; L1P7 = "G"; L1P7Costo = 2; L1P7Opciones = ["A", "B", "C", "D", "E", "F", "H"]; L1P8 = "H"; L1P8Costo = 2; L1P8Opciones = ["A", "B", "C", "D", "E", "F", "G"]; // Costes: CostoAB = 2; CostoBA = 2; CostoAC = 1; CostoCA = 1; CostoAD = 2; CostoDA = 2; CostoAE = 2; CostoEA = 2; CostoAF = 2; CostoFA = 2; CostoAG = 3; CostoGA = 3; CostoAH = 3; CostoHA = 3; // CostoBC = 2; CostoCB = 2; CostoBD = 1; CostoDB = 1; CostoBE = 2; CostoEB = 2; CostoBF = 2; CostoFB = 2; CostoBG = 3; CostoGB = 3; CostoBH = 3; CostoHB = 3; // CostoCD = 2; CostoDC = 2; CostoCE = 2; CostoEC = 2; CostoCF = 2; CostoFC = 2; CostoCG = 3; CostoGC = 3; CostoCH = 3; CostoHC = 3; // CostoDE = 3; CostoED = 3; CostoDF = 2; CostoFD = 2; CostoDG = 3; CostoGD = 3; CostoDH = 3; CostoHD = 3; // CostoEF = 1; CostoFE = 1; CostoEG = 1; CostoGE = 1; CostoEH = 2; CostoHE = 2; // CostoFG = 2; CostoGF = 2; CostoFH = 1; CostoHF = 1; // CostoGH = 1; CostoHG = 1; // Para saber cuántas permutaciones con el largo anterior hay... // que extender: PermutacionesDeOldL = 8; Mensaje = ""; actions for fotograma 2 // Se extenderá L?P1, L?P2, etc, esto evita repetir concatenaciones: L_OldLargo_P = "L"+Largo+"P"; // Incrementar largo de las permutaciones a crearse: Largo++; Mensaje = "Nuevo largo de permutaciones: "+Largo; // Parte de nombres de nuevas permutaciones, usado para evitar... // repetir concatenaciones: L_NewLargo_P = "L"+Largo+"P"; NroDePermutacionaExtender = 0; // Cuando se empiece a extender permutaciones más largas, // esto determina cuántas hay que extender (PermutacionesDeOldL): PermutacionesNuevas = 0; actions for fotograma 3 // Cambiar permutación a extender: NroDePermutacionaExtender++; NombreDePaExtender = L_OldLargo_P+NroDePermutacionaExtender; // Para evitar evals: EvaluedNombreDePaExtender = eval(NombreDePaExtender); // trace ("Se extenderá la permutación "+NombreDePaExtender+", que es "+EvaluedNombreDePaExtender); // Copia de variable, para evitar referencias: CaracteresDisponibles = eval(NombreDePaExtender+"Opciones"); // Para evitar restas: LastNroDeCaracter = CaracteresDisponibles.length-1; NroDeCaracteraAgregar = -1; // Copia para evitar referencias: Costo = eval(NombreDePaExtender+"Costo"); Mensaje = "Se extenderá la permutación "+NombreDePaExtender+", que es "+EvaluedNombreDePaExtender+" y cuesta "+Costo; // Último punto alcanzado: LastPunto = EvaluedNombreDePaExtender.charat(EvaluedNombreDePaExtender.length-1); // ¿NO SE PODRÍA USAR LastNroDeCaracter? // Para evitar repetir concatenaciones al averiguar costo a sumar: Costo_LastPunto = "Costo"+LastPunto; // ResumenParaCosto = "Costo"+(eval(NombreDePaExtender).charat(LastNroDeCaracter)); actions for fotograma 4 // Cambiar el caracter que se agrega: NroDeCaracteraAgregar++; // Crear permutación usando la a extender, // agregándole el caracter señalado: PermutacionesNuevas++; NombreDeNuevaP = L_NewLargo_P+PermutacionesNuevas; set (NombreDeNuevaP, eval(NombreDePaExtender)+CaracteresDisponibles[NroDeCaracteraAgregar]); // trace ("Nueva permutación: "+NombreDeNuevaP+": "+eval(NombreDeNuevaP)); // Crear su variable de Opciones // (slice para copiar el array, // splice para quitarle un elemento): // Copia el array: CopiaDelArray = CaracteresDisponibles.slice(); // A esa copia se le quita el caracter agregado en la permutación: CopiaDelArray.splice(NroDeCaracteraAgregar, 1); set (NombreDeNuevaP+"Opciones", CopiaDelArray); // trace ("Sus opciones son: "+NombreDeNuevaP+"Opciones: "+eval(NombreDeNuevaP+"Opciones")); set (NombreDeNuevaP+"Costo", Costo+(eval(Costo_LastPunto+(eval(NombreDeNuevaP).charat(eval(NombreDeNuevaP).length-1))))); actions for fotograma 5 if (NroDeCaracteraAgregar<LastNroDeCaracter) { // Se volverá a extender la permutación, cambiando el caracter: gotoAndPlay (4); } else if (NroDePermutacionaExtender<PermutacionesDeOldL) { // Se volverá a cambiar la permutación a extender: delete eval(NombreDePaExtender); delete eval(NombreDePaExtender+"Opciones"); delete eval(NombreDePaExtender+"Costo"); gotoAndPlay (3); } else if (Largo<4) { // Se volverá a incrementar el largo... // de las permutaciones a extender: delete eval(NombreDePaExtender); delete eval(NombreDePaExtender+"Opciones"); delete eval(NombreDePaExtender+"Costo"); PermutacionesDeOldL = PermutacionesNuevas; gotoAndPlay (2); } actions for fotograma 6 Mensaje = "Borrando variables innecesarias."; NroDePermutacionaBorrar = 0; do { NroDePermutacionaBorrar++; delete eval(L_NewLargo_P+NroDePermutacionaBorrar+"Opciones"); delete eval(L_NewLargo_P+NroDePermutacionaBorrar); } while (NroDePermutacionaBorrar<PermutacionesNuevas); actions for fotograma 7 delete eval(NombreDePaExtender); delete eval(NombreDePaExtender+"Opciones"); delete PermutacionesDeOldL; delete Largo; delete L_OldLargo_P; delete L_NewLargo_P; delete NroDePermutacionaExtender; delete PermutacionesNuevas; delete NombreDePaExtender; delete CaracteresDisponibles; delete LastNroDeCaracter; delete NroDeCaracteraAgregar; delete NombreDeNuevaP; delete CopiaDelArray; delete NroDePermutacionaBorrar; Mensaje = "Listo."; stop ();
Tanto borrado de variables al final es porque falta que muestre cual es el camino, tendría que comparar cada costo obtenido y quedarse con el menor ¿me conviene hacer eso al final? El caso que estoy analizando es probablemente simplón: Pasar por los 8 tornillos (o lo que sean) tocando la menor cantidad de escaleras posible: https://www.youtube.com/watch?v=ovi2Vr1Wza0El video ese no es mío y no se está intentando eso, es simplemente para que vean. Pero bueno ¿estoy borrando variables inexistentes? Y me faltaría que se borren estas: Variable _level0.CostoAB = 2 Variable _level0.CostoBA = 2 Variable _level0.CostoAC = 1 Variable _level0.CostoCA = 1 Variable _level0.CostoAD = 2 Variable _level0.CostoDA = 2 Variable _level0.CostoAE = 2 Variable _level0.CostoEA = 2 Variable _level0.CostoAF = 2 Variable _level0.CostoFA = 2 Variable _level0.CostoAG = 3 Variable _level0.CostoGA = 3 Variable _level0.CostoAH = 3 Variable _level0.CostoHA = 3 Variable _level0.CostoBC = 2 Variable _level0.CostoCB = 2 Variable _level0.CostoBD = 1 Variable _level0.CostoDB = 1 Variable _level0.CostoBE = 2 Variable _level0.CostoEB = 2 Variable _level0.CostoBF = 2 Variable _level0.CostoFB = 2 Variable _level0.CostoBG = 3 Variable _level0.CostoGB = 3 Variable _level0.CostoBH = 3 Variable _level0.CostoHB = 3 Variable _level0.CostoCD = 2 Variable _level0.CostoDC = 2 Variable _level0.CostoCE = 2 Variable _level0.CostoEC = 2 Variable _level0.CostoCF = 2 Variable _level0.CostoFC = 2 Variable _level0.CostoCG = 3 Variable _level0.CostoGC = 3 Variable _level0.CostoCH = 3 Variable _level0.CostoHC = 3 Variable _level0.CostoDE = 3 Variable _level0.CostoED = 3 Variable _level0.CostoDF = 2 Variable _level0.CostoFD = 2 Variable _level0.CostoDG = 3 Variable _level0.CostoGD = 3 Variable _level0.CostoDH = 3 Variable _level0.CostoHD = 3 Variable _level0.CostoEF = 1 Variable _level0.CostoFE = 1 Variable _level0.CostoEG = 1 Variable _level0.CostoGE = 1 Variable _level0.CostoEH = 2 Variable _level0.CostoHE = 2 Variable _level0.CostoFG = 2 Variable _level0.CostoGF = 2 Variable _level0.CostoFH = 1 Variable _level0.CostoHF = 1 Variable _level0.CostoGH = 1 Variable _level0.CostoHG = 1 Variable _level0.EvaluedNombreDePaExtender = "HGF" Variable _level0.Costo = 5 Variable _level0.LastPunto = "F" Variable _level0.Costo_LastPunto = "CostoF" Variable _level0.L3P336Costo = 5 O sea, si el programa tuviese más posibles caminos, serían más cantidad de "CostoLetra1Letra2". Además esta L3P336Costo, que supongo es la última de largo 3, si el programa llegara a formar caminos más largos (lo configuré hasta 4 por ahora para pruebas, pero se precisan 8), sería otra. No sé por qué no se borra. Otras supongo que son fáciles de borrar. ¿Qué más me recomiendan? No he olvidado esto: https://foro.elhacker.net/buscador-t522268.0.htmlpasa que en aquél entonces no me atraía tanto el tema. Leeré eso pronto.
|
|
|
43
|
Programación / Programación General / Mostrar dibujos variándolos desde izquierda arriba, empezando por una _|
|
en: 30 Marzo 2025, 03:40 am
|
No entiendo por qué me resulta tan complicado. Los dibujos empiezan teniendo 3*3 cuadraditos, siempre los números serán iguales entre sí. Como regla he puesto que, si son X*X, se muestren (X-1)*(X-1) dibujos en la pantalla, o sea que al inicio serían 2*2. Una muestra:  Lo gris son separadores. Hay 2*2 dibujos o cuadros, de 3*3 cuadraditos cada uno. Son blancos o negros. Hay 2^(3*3) dibujos posibles, creo, no importa si está mal el cálculo. Esa cantidad se quiere que se divida en 4, para que cada cuadro muestre la misma cantidad de dibujos. Los dibujos se pueden representar mediante un número, especialmente uno binario. Como en Flash el negro es 000000, decido que el 0 represente negro y 1 blanco. Quiero que se vayan mostrando dibujos en orden desde todo blanco, o sea, si los dibujos fuesen de 2*2 sería: 1er dibujo del 1er cuadro: 1111 2ndo dibujo de ese cuadro: 1110 3ero: 1101 el número va bajando, sin sobresaltos. También quiero que inicialmente los dibujos varíen desde arriba e izquierda, por lo que, supongo, me conviene numerar a los cuadraditos así: 8 7 6 5 4 3 2 1 0 Así que el dibujo correspondiente a 111111110 sería: 0 1 1 1 1 1 1 1 1 O sea ¡al revés! El número debe variar normal, pero debe aplicarse al revés, creo. Creo que ya había logrado eso. Entonces quise que en vez de mostrarse todos los dibujos, se empiece por este: 1 1 0 1 1 0 0 0 0 No viene al caso por qué. La cosa es que se mostrarán menos dibujos, la cantidad a dividir en cuadros es distinta. Hay que averiguar qué cantidad es. Hago esto: DibujoEnBinario = ""; NroDelCaracter = Cuadraditos; AnteriorCaracteraPintar = Cuadraditos-CuadraditosPorFila; // Esto genera la | do { NroDelCaracter--; if (NroDelCaracter != AnteriorCaracteraPintar) { DibujoEnBinario = DibujoEnBinario+1; } else { DibujoEnBinario = DibujoEnBinario+0; AnteriorCaracteraPintar = AnteriorCaracteraPintar-CuadraditosPorFila; } } while (NroDelCaracter > CuadraditosPorFila); // Esto la _ do { NroDelCaracter--; DibujoEnBinario = DibujoEnBinario+0; } while (NroDelCaracter > 0); trace("DibujoEnBinario (_|): "+DibujoEnBinario);
Me da: DibujoEnBinario (_|): 110110000 Está bien. Lo convierto a decimal, porque ese es el número de dibujo más grande que se mostrará, esa esa la cantidad que quiero repartir en los cuadros. DibujoaMostrar = 0; do { DibujoaMostrar = DibujoaMostrar+(Number(DibujoEnBinario.charat(NroDelCaracter))*Math.pow(2, DibujoEnBinario.length-1-NroDelCaracter)); NroDelCaracter++; } while (NroDelCaracter < Cuadraditos); DibujoaMostrar = Number(DibujoaMostrar);
Me da 432. Disminucion = Math.floor(DibujoaMostrar/Cuadros); // Se llama disminución porque se comenzará mostrando... // el dibujo que según el modo conque los numero, // es el último, y se irá disminuyendo.
No creo que el error esté ahí, tampoco. Pero como vieron en la imagen, el 1er cuadro (arriba izquierda, los cuadros están numerados normal) no muestra una _| sino una _ | ¿Qué estoy haciendo mal? // Generador de dibujos. // // Se insertarán cuadros numerados así: // 0 1 // 2 3 // En cada uno se insertarán cuadraditos numerados al revés (ver... // Por qué cuadraditos numerados inversamente.txt por detalles). // // Usada en InsertarCuadros sólo 1 vez // (ergo podría no ser una función, pero por ahora simplifica): function AjustarVariables () { Cuadros = CuadrosPorFila*CuadrosPorFila; MaxCuadro = Cuadros-1; Cuadraditos = CuadraditosPorFila*CuadraditosPorFila; MaxCuadradito = Cuadraditos-1; LargoDeCuadraditos = 384/(CuadraditosPorFila*CuadrosPorFila+CuadrosPorFila-1); LargoDeCuadros = CuadraditosPorFila*LargoDeCuadraditos; // Esto es para que el 1er dibujo sea una |_ porque es el... // 1ero que tiene algún cuadradito pintado en cada fila y... // columna (en realidad el 1ero es el que tiene despintado el punto de unión, pero hay poca diferencia) // esto es para evitar que se salteén montones de dibujos. // Se averigua su número representante: DibujoEnBinario = ""; NroDelCaracter = Cuadraditos; AnteriorCaracteraPintar = Cuadraditos-CuadraditosPorFila; // Esto genera la | do { NroDelCaracter--; if (NroDelCaracter != AnteriorCaracteraPintar) { DibujoEnBinario = DibujoEnBinario+1; } else { DibujoEnBinario = DibujoEnBinario+0; AnteriorCaracteraPintar = AnteriorCaracteraPintar-CuadraditosPorFila; } } while (NroDelCaracter > CuadraditosPorFila); // Esto la _ do { NroDelCaracter--; DibujoEnBinario = DibujoEnBinario+0; } while (NroDelCaracter > 0); trace("DibujoEnBinario (_|): "+DibujoEnBinario); // Convertirlo en decimal: DibujoaMostrar = 0; do { DibujoaMostrar = DibujoaMostrar+(Number(DibujoEnBinario.charat(NroDelCaracter))*Math.pow(2, DibujoEnBinario.length-1-NroDelCaracter)); NroDelCaracter++; } while (NroDelCaracter < Cuadraditos); DibujoaMostrar = Number(DibujoaMostrar); // Esa cantidad se dividirá según la cantidad de cuadros, // de modo que cada cuadro mostrará la misma cantidad de... // dibujos, pero distintos a los de otros cuadros: Disminucion = Math.floor(DibujoaMostrar/Cuadros); // Se llama disminución porque se comenzará mostrando... // el dibujo que según el modo conque los numero, // es el último, y se irá disminuyendo: // DibujoaMostrar = DibujoaMostrar-1; trace("DibujoaMostrar: "+DibujoaMostrar); } // Usada en InsertarCuadros una vez (totalmente innecesaria): function ConvertiraBinarioInverso (numero) { trace(numero); // Averiguar cómo es en binario: DibujoEnBinario = ""; while (numero>0) { DibujoEnBinario = DibujoEnBinario+numero%2; numero = Math.floor(numero/2); } // Agregar 0s a DibujoEnBinario si hacen falta: while (DibujoEnBinario.length<Cuadraditos) { DibujoEnBinario = DibujoEnBinario+0; } trace("DibujoEnBinario: "+DibujoEnBinario); } // Usada al inicio y cuando aumenta la cantidad de cuadraditos por fila: function InsertarCuadros () { AjustarVariables(); NroDelCuadroaColocar = 0; // Sus columnas y filas se cuentan desde 0 también: ColumnaDeCuadro = 0; FilaDeCuadro = 0; do { NombreDelCuadro = "Cuadro"+NroDelCuadroaColocar; attachMovie("sCuadro", NombreDelCuadro, NroDelCuadroaColocar); setProperty (NombreDelCuadro, _x, LargoDeCuadros*ColumnaDeCuadro+ColumnaDeCuadro*LargoDeCuadraditos); setProperty (NombreDelCuadro, _y, LargoDeCuadros*FilaDeCuadro+FilaDeCuadro*LargoDeCuadraditos); ColumnaDeCuadro++; if (ColumnaDeCuadro == CuadrosPorFila) { ColumnaDeCuadro = 0; FilaDeCuadro++; } // Se agregarán y distribuirán cuadraditos en el cuadro... // recién agregado, numerándolos del modo opuesto: NroDelCuadraditoaColocar = MaxCuadradito; // Sus columnas y filas se cuentan desde 0: ColumnaDeCuadradito = 0; FilaDeCuadradito = 0; // Se pintarán de modo que muestren el dibujo... // acorde a la división de dibujos; averiguarlo: ConvertiraBinarioInverso(DibujoaMostrar); ColumnaDeCuadradito = 0; FilaDeCuadradito = 0; do { eval(NombreDelCuadro).attachMovie("sCuadradito", "Cuadradito"+NroDelCuadraditoaColocar, NroDelCuadraditoaColocar); NombreDelCuadraditoSinNum = NombreDelCuadro+".Cuadradito"; NombreDelCuadradito = NombreDelCuadraditoSinNum+NroDelCuadraditoaColocar; setProperty (NombreDelCuadradito, _x, ColumnaDeCuadradito*LargoDeCuadraditos); setProperty (NombreDelCuadradito, _y, FilaDeCuadradito*LargoDeCuadraditos); setProperty (NombreDelCuadradito, _width, LargoDeCuadraditos); setProperty (NombreDelCuadradito, _height, LargoDeCuadraditos); ColorDelCuadradito = new Color(NombreDelCuadradito); // Los números tomados del binario son los opuestos al cuadradito, // ya que los cuadraditos están numerados al revés. // Tomando el 1er caracter del binario y borrándolo para que... // en la próxima repetición se use el siguiente, se logra eso: NroDeColor = Number(DibujoEnBinario.charat(0)); DibujoEnBinario = DibujoEnBinario.substring(1, DibujoEnBinario.length); if (NroDeColor == 0) { ColorDelCuadradito.setRGB(0); } else { ColorDelCuadradito.setRGB(0xFFFFFF); } // Esto es para modificar con más practicidad el color: set (NombreDelCuadro+".ColordeCuadradito"+NroDelCuadraditoaColocar, NroDeColor); ColumnaDeCuadradito++; if (ColumnaDeCuadradito == CuadraditosPorFila) { ColumnaDeCuadradito = 0; FilaDeCuadradito++; } NroDelCuadraditoaColocar--; } while (NroDelCuadraditoaColocar > -1); NroDelCuadroaColocar++; DibujoaMostrar = DibujoaMostrar-Disminucion; // trace("DibujoaMostrar: "+DibujoaMostrar); } while (NroDelCuadroaColocar < Cuadros); } // PorFila es también por columna: CuadrosPorFila = 2; // Debido a que en cierto chequeo se asume que... // si el cuadradito no está en la parte inferior ni... // superior entonces está en una fila intermedia, // conviene que CuadraditosPorFila comience siendo >2: CuadraditosPorFila = 3;
Probablemente obtengo el binario al revés y luego lo aplica al revés de eso, no sé, algunos cálculos me los dijo GPT ¿qué me conviene hacer?
|
|
|
44
|
Programación / Programación General / Re: ¿Con Macromedia Flash 5 se pueden hacer juegos para celular?
|
en: 29 Marzo 2025, 10:48 am
|
Es Macromedia, no Adobe, Adobe aún no lo había comprado.
No tengo móvil.
Lo veo complicado, este asunto es porque había pensado en ofrecer juegos para empresas (aunque probablemente aún no puedo hacer algo de calidad aceptable), pero tendría que ser para móvil porque hoy día PC no usa mucha gente creo. Pero tendría que probar lo que dijiste, aunque no sé qué le puedan meter al convertirlo en otro formato :/
Mejor podría ser aprender a usar un programa conque los pueda hacer.
|
|
|
45
|
Programación / Programación General / ¿Con Macromedia Flash 5 se pueden hacer juegos para celular?
|
en: 28 Marzo 2025, 03:39 am
|
No tengo idea sobre celulares. Si pueden abrir archivos exe o no. swf supongo que no. O tal vez con un programa... o muy popular. GPT: Correcto: **un celular no puede ejecutar archivos `.exe`** de forma nativa.
### 🧾 ¿Qué es un archivo `.exe`? - Un archivo `.exe` (de *"executable"*) es un **formato de programa ejecutable exclusivo de Windows**. - Está diseñado para funcionar en **sistemas operativos Windows** (como Windows 10, 11, etc.) y **no es compatible** con sistemas como Android o iOS.
---
### 📱 ¿Por qué no se puede ejecutar un `.exe` en un celular?
#### En Android: - Android **no usa Windows** ni su arquitectura. - Los archivos `.exe` están hechos para funcionar en **procesadores x86/x64**, mientras que la mayoría de los celulares usan **procesadores ARM**. - Android usa apps en formato **.apk**, que son completamente diferentes.
#### En iOS (iPhone/iPad): - iOS es aún más restrictivo. No permite ejecutar ningún archivo que no sea una app firmada y aprobada por Apple. - Mucho menos permite ejecutar `.exe`.
---
### 🛠️ ¿Existen formas de *intentar* ejecutar `.exe` en Android?
Sí, **pero con muchas limitaciones**:
1. **Emuladores de Windows para Android**, como: - **DOSBox**: puede ejecutar programas `.exe` tipo MS-DOS (muy antiguos). - **Wine for Android**: un intento de portar Wine (de Linux) a Android para ejecutar algunos `.exe`.
❗ *Estos métodos son experimentales y generalmente no funcionan bien, especialmente con juegos o programas complejos.*
2. **Uso remoto**: - Puedes **usar una app de escritorio remoto** (como Steam Link o Microsoft Remote Desktop) para **ejecutar el `.exe` en tu PC** y **verlo/controlarlo desde tu celular**.
---
### ✅ ¿Qué puedes hacer si quieres que tu juego funcione en celulares?
Si ya haces juegos en `.exe` (probablemente con Flash, Construct, Unity u otra herramienta), puedes:
- **Exportarlo a Android/iOS**, si tu motor de desarrollo lo permite. - Por ejemplo: - Unity permite exportar a Android e iOS. - Godot también. - HTML5 (con javascript) funciona directamente en el navegador del celular.
---
### 💡 En resumen:
> **No**, un celular **no puede ejecutar archivos `.exe` directamente**, porque son programas diseñados para Windows. Si quieres que tus juegos funcionen en móviles, necesitarás exportarlos en formatos compatibles como `.apk` (Android) o usar tecnologías web como HTML5.
|
|
|
46
|
Programación / Programación General / Mejorar botón que cambia colores.
|
en: 27 Marzo 2025, 04:02 am
|
 En la imagen pueden verse 10 textos que son valores de colores: 000000, FF0000, 00FF00, y el resto son todos 999999. Al lado de cada valor hay una columna de cuadraditos grises. La idea básicamente es que tengan un color y al cliquearlos su color se transfiera al valor que muestra su texto asociado. Cada columna de esas es una película con algo como esto: onClipEvent (load) { ColorAsociado = 0; ColorDelCentro0 = 0xCCCCCC; ColorDelCentro1 = 0x999999; ColorDelCentro2 = 0x666666; ColorDelCentro3 = 0x333333; }
en cada una los valores son distintos. ColorAsociado se refiere a qué valor cambiará. Lo demás se refiere a qué colores tendrán los centros de los cuadraditos. Cada cuadradito tiene: onClipEvent (load) { ColorDelCentro = _parent.ColorDelCentroX; }
donde X es 0, 1, etc, según el cuadradito que sea. Lo que hace es tomar de su película padre, el color que se le puso. Si los cuadraditos tuvieran nombre, quizá se podría haber puesto al inicio algo como: Cuadradito0.ColorDelCentro = 0xCCCCCC; Cuadradito1.ColorDelCentro = 0x999999; etc, tendría que probar. Todos los cuadraditos tienen esto:  En frame 1: ColorDelObjetoCentro = new Color(Centro); stop (); La parte del extremo (el borde, pero no le digo así porque tienen un borde con línea, que obvié) tiene transparencia. El centro, llamado Centro, se extiende hasta el frame 2 y tiene: onClipEvent (load) { _parent.ColorDelObjetoCentro.setRGB(_parent.ColorDelCentro); }
Con esto, cada vez que la película va al frame 1 o al 2, el centro del cuadradito se pone del color que se le estableció. El botón es un objeto invisible que ocupa todo el cuadradito y en el frame 1 tiene: on (rollOver) { gotoAndStop (2); }
Hace que, al señalarlo, la película vaya al frame 2. Frame 2:La parte extrema del cuadradito, ahora llamada Extremo, pero no sé si es necesario ponerle nombre, tiene: onClipEvent (load) { ColorDelExtremo = new Color(this); } onClipEvent (enterFrame) { Rojo = random(256); Verde = random(256); Azul = random(256); ColorDelExtremo.setRGB(Rojo*65536+Verde*256+Azul); }
Eso hace que cambie de color constantemente. Es un efecto visible para indicar que el botón está siendo señalado. El centro ya dije que se extendía desde el frame 1, así que sigue igual. El botón, que se extiende hasta el frame 3, tiene: on (rollOut) { gotoAndStop (1); } on (press) { // El extremo de este botón tendrá el color del centro, // y él cambiará a colores random: ExColorDelCentro = ColorDelObjetoCentro.getRGB(); gotoAndStop (3); } on (release, releaseOutside) { // El centro tendrá el color asociado (de unos cuadraditos): ColorDelCentro = _level0.PosiblesColores[_parent.ColorAsociado]; ColorDelObjetoCentro.setRGB(ColorDelCentro); // Si se saltearon colores (es cuando se asigna el 5to... // sin haber asignado el 4to, por ej), asignar los intermedios al azar: NroDePosibleColoraAsignar = _level0.PosiblesColores.length; while (_level0.PosiblesColores.length < _parent.ColorAsociado) { ColorElegido = random(16711681); _level0.PosiblesColores[NroDePosibleColoraAsignar] = ColorElegido; // A continuación se modificará la variable que muestra... // el color, que existe porque el contenido de un array... // no se puede mostrar directamente. Se le agregarán "0s"... // si tiene menos de lo debido: ColoraAsignar = ColorElegido.toString(16).toUpperCase(); while (ColoraAsignar.length < 6) { ColoraAsignar = "0"+ColoraAsignar; } set("_level0.ShowerDePosibleColor"+NroDePosibleColoraAsignar, ColoraAsignar); NroDePosibleColoraAsignar++; } // El color asociado de los posibles colores de los cuadraditos... // tendrá el color del extremo: _level0.PosiblesColores[_parent.ColorAsociado] = ColorDelExtremo.getRGB(); // A continuación se modificará la variable que muestra... // el color, que existe porque el contenido de un array... // no se puede mostrar directamente. Se le agregarán "0s"... // si tiene menos de lo debido: ColoraAsignar = ColorDelExtremo.getRGB().toString(16).toUpperCase(); while (ColoraAsignar.length < 6) { ColoraAsignar = "0"+ColoraAsignar; } set("_level0.ShowerDePosibleColor"+_parent.ColorAsociado, ColoraAsignar); _level0.InsertarCuadros(); gotoAndStop (1); }
Si el botón se deja de señalar, la película va al frame 1, donde la parte extrema del cuadradito ya no cambia de colores, queda como al inicio, un botón normal. Dije lo que hace cuando se cliquea, pero no entiendo cómo lo hice o cómo lo hago mejor, diré más en el frame 3. Es un efecto visible de que el botón está siendo presionado, en vez de hundirse. Lo que el botón hace cuando se suelta, lo hace luego de llegar al frame 3 porque fue ahí al cliquearse, así que lo vemos luego. Frame 3:ColorDelExtremo = new Color(Extremo); ColorDelExtremo.setRGB(ExColorDelCentro); Con esto el color del extremo del cuadradito queda como estaba su centro. Pensé que podría ponerlo en el botón en el código de cuando se cliquea, pero algo falla, no sé. La parte extrema del cuadradito, Extremo, ya no tiene su código de cambiar colores. El centro tiene: onClipEvent (load) { ColorDeEsto = new Color(this); } onClipEvent (enterFrame) { Rojo = random(256); Verde = random(256); Azul = random(256); ColorDeEsto.setRGB(Rojo*65536+Verde*256+Azul); }
Para que cambie de colores al azar, el efecto visible en vez de hundirse, que ya comenté. Y ahora se aplicaría lo del botón. // El centro tendrá el color asociado (de unos cuadraditos): ColorDelCentro = _level0.PosiblesColores[_parent.ColorAsociado]; ColorDelObjetoCentro.setRGB(ColorDelCentro);
En cuanto a cuadraditos es lo mismo que tomar el valor que tiene su texto asociado. Es como que los colores se intercambian, el color central es ahora como indica el texto pero el texto queda como era el color central. Es como si hubiera 5 opciones: 4 en los cuadraditos y la elegida en el texto, entonces al elegir otra se pasa al texto y la que estaba elegida pasa a las elegibles. // Si se saltearon colores (es cuando se asigna el 5to... // sin haber asignado el 4to, por ej), asignar los intermedios al azar: NroDePosibleColoraAsignar = _level0.PosiblesColores.length; while (_level0.PosiblesColores.length < _parent.ColorAsociado) { ColorElegido = random(16711681); _level0.PosiblesColores[NroDePosibleColoraAsignar] = ColorElegido; // A continuación se modificará la variable que muestra... // el color, que existe porque el contenido de un array... // no se puede mostrar directamente. Se le agregarán "0s"... // si tiene menos de lo debido: ColoraAsignar = ColorElegido.toString(16).toUpperCase(); while (ColoraAsignar.length < 6) { ColoraAsignar = "0"+ColoraAsignar; } set("_level0.ShowerDePosibleColor"+NroDePosibleColoraAsignar, ColoraAsignar); NroDePosibleColoraAsignar++; }
Eso se supone que está bien explicado y lo entiendo, no le veo problema tampoco. // El color asociado de los posibles colores de los cuadraditos... // tendrá el color del extremo: _level0.PosiblesColores[_parent.ColorAsociado] = ColorDelExtremo.getRGB(); // A continuación se modificará la variable que muestra... // el color, que existe porque el contenido de un array... // no se puede mostrar directamente. Se le agregarán "0s"... // si tiene menos de lo debido: ColoraAsignar = ColorDelExtremo.getRGB().toString(16).toUpperCase(); while (ColoraAsignar.length < 6) { ColoraAsignar = "0"+ColoraAsignar; } set("_level0.ShowerDePosibleColor"+_parent.ColorAsociado, ColoraAsignar);
Esto sería lo más importante, que el color cliqueado se transmita al valor que muestra el texto. La mención a cuadraditos es porque aparecerán en pantalla unos, que deben poder tener el color cliqueado. Con todo esto y otro código se logra. _level0.InsertarCuadros(); gotoAndStop (1);
Eso inserta dibujos con cuadraditos y el goto hace que el botón vuelva a quedar normal, mostrando en su centro qué color pondrá en el texto si se cliquea. Todo esto es que empecé a revisarlo y no lo entendía, y algunas cosas aún no las entiendo, si se pueden hacer mejor o no. Díganme cómo hacerlo mejor o explíquenme por qué no se puede.
|
|
|
47
|
Programación / Programación General / ¿Cómo mejoro mi juego Signos en linea?
|
en: 24 Marzo 2025, 23:59 pm
|
Sobre ponerle IA ya hice un tema, en ese sentido no pregunto en este. Tampoco sobre el modo conque chequea si hubo victoria. Lo que pregunto tiene que ver conque quiero agregarle cosas, por ejemplo: - Opción de que jueguen más de 2 jugadores. - Si es posible, opción de casilleros con otras formas, de modo que la cantidad de direcciones posibles sea distinta a 8. Por ahora sólo vi de 6: https://es.wikipedia.org/wiki/Teselado_hexagonal- Opción de que no se gane por hacer una línea de signos requeridos, sino por ser quien haya hecho más cuando el tablero esté lleno. - Opción de que se gane por tener la mayor cantidad de unidos, independientemente de cuan larga sea la línea. Aunque debo pensar si esto tendría gracia. - Opción de que se gane por haber formado la línea más larga posible (puede ocurrir antes de que el casillero se llene). - Opciones anti, como el antichess, o sea, que en vez de ganar por hacer una cosa u otra, eso lleve a perder. - Opción de que se gane no por hacer una línea, sino alguna figura. Por ejemplo una L. - Opción de que gane quien haga la figura más grande. - Opción de que en vez de ser signos se pongan letras y gane quien 1ero forme una palabra. - Que gane quien forme más palabras. - Las letras a poner van rotando, el jugador no elige. Por ejemplo si hay que formar "Win". - Al comienzo los jugadores se turnan en elegir una letra, luego empieza el juego poniéndolas según el orden conque las eligieron. - Lo mismo pero en cualquier orden. - Lo mismo pero puedes usar las letras de tu oponente. - Repetición de letras se permite. Y tal vez más... Algunas cosas no son excluyentes. Algunas cosas quizá sea mejor hacerlas en un programa aparte, pero ya que son juegos tan similares sería bueno un "todo en 1" ¿no? Además no sé cuales debería hacer aparte, tal vez el que se puede poner letras y el que es sobre formar figuras. Serían 3. ¿Ustedes harían 3 juegos o más o menos? Teniendo en cuenta todo eso, quisiera que mi código esté mejor preparado, porque intenté hacrlo eficiente pero en eso decidí hacerlo así nomás y por ahora está así. ¿Cómo lo mejorarían? Imagen para referencia:  Frame 1: CasillerosPorFila = 9; JuntosRequeridos = 3; MarcadorDeX = "Humano"; MarcadorDe0 = "IA"; Jugadores = "HumanoIA"; // Usado en el botón de quién marca con X: function CambiarMarcadorDeX () { if (MarcadorDeX == "Humano") { MarcadorDeX = "IA"; } else { MarcadorDeX = "Humano"; } Jugadores = MarcadorDeX+MarcadorDe0; HacerTablero(); } // Usado en el botón de quién marca con 0: function CambiarMarcadorDe0 () { if (MarcadorDe0 == "IA") { MarcadorDe0 = "Humano"; } else { MarcadorDe0 = "IA"; } Jugadores = MarcadorDeX+MarcadorDe0; HacerTablero(); } // Usado ahora y en general cuando se cambia la configuración de la partida: function HacerTablero () { // Esto se irá especificando en el próximo while: Situacion = []; PosiblesAcciones = []; // Los casilleros se cuentan desde 0: MaxCasillero = CasillerosPorFila*CasillerosPorFila-1; // Las columnas también. Esto es para no repetir restas por ahí: MaxColumna = CasillerosPorFila-1; LargoDeCasilleros = 384/CasillerosPorFila; NroDeCasilleroaColocar = -1; // Sus columnas y filas se cuentan desde 0, // sirven para posicionarlos más fácil: Columna = 0; Fila = 0; do { NroDeCasilleroaColocar++; // v es vacío: Situacion.push("v"); PosiblesAcciones.push(NroDeCasilleroaColocar); CasilleroaColocar = "Casillero"+NroDeCasilleroaColocar; // set ("SignoEn"+CasilleroaColocar, "v"); // sCasillero tiene código: attachMovie("sCasillero", CasilleroaColocar, NroDeCasilleroaColocar); setProperty (CasilleroaColocar, _x, LargoDeCasilleros*Columna); setProperty (CasilleroaColocar, _y, LargoDeCasilleros*Fila); setProperty (CasilleroaColocar, _width, LargoDeCasilleros); setProperty (CasilleroaColocar, _height, LargoDeCasilleros); Columna++; if (Columna == CasillerosPorFila) { Columna = 0; Fila++; } // Para que al presionar el botón se sepa qué modificar: set (CasilleroaColocar+".CasilleroAsociado", NroDeCasilleroaColocar); // trace("Colocado el "+NroDeCasilleroaColocar); } while (NroDeCasilleroaColocar < MaxCasillero); // Para que no muestre el mensaje de victoria: Win = "No"; // Esto es para evitar restas: LastNroDeAcccionPosible = PosiblesAcciones.length-1; trace ("LastNroDeAcccionPosible: "+LastNroDeAcccionPosible); SignoDeTurno = "X"; if (Jugadores == "HumanoIA") { gotoAndStop(2); } else if (Jugadores == "IAHumano") { TurnoDeIA(); if (Win == "No") { // OJO QUE SI HAY EMPATE NO DEBE IR AL F2, O NO ES NEC gotoAndStop(2); } } else if (Jugadores == "HumanoHumano") { gotoAndStop(2); } else { // IA VS IA: InutilizarBotones(); gotoAndStop(3); } } HacerTablero(); // Usada cuando el humano marca en un casillero: function HumanoHaMarcado () { // trace("PosiblesAcciones.length: "+PosiblesAcciones.length); // trace("Humano ha marcado"); // Inutilizar botón del casillero marcado: setProperty (eval("Casillero"+CasilleroMarcado+".Boton"), _visible, false); // Agregar signo: // SignosColocados++; eval("Casillero"+CasilleroMarcado).attachMovie("s"+SignoDeTurno, "Signo", 1); Situacion[CasilleroMarcado] = SignoDeTurno; // set ("SignoEnCasillero"+CasilleroMarcado, "X"); // ¿Gana? // Si esta función dice que no, usa otras: ChequearVertical(); if (Win == "Sí") { // Sí, inutilizar botones del tablero // (debería ser sólo los activos): InutilizarBotones(); // Mostrar mensaje de victoria: attachMovie("sGano"+SignoDeTurno, "Mensaje", NroDeCasilleroaColocar+1); UbicarMensaje(); } else if (PosiblesAcciones.length>=2) { // Sino, si aún hay >=2 acciones posibles // (la que usó aún no se quitó): // Quitar su acción de las posibles acciones: // Se busca en qué posición del array está: AccionRevisandose = -1; // Condición original: AccionRevisandose < LastNroDeAcccionPosible do { AccionRevisandose++; if (PosiblesAcciones[AccionRevisandose] == CasilleroMarcado) { // Se elimina la acción de la lista de posibles: PosiblesAcciones.splice(AccionRevisandose, 1); trace (PosiblesAcciones.join("")); break; } } while (true); LastNroDeAcccionPosible--; trace ("LastNroDeAcccionPosible disminuyó: "+LastNroDeAcccionPosible); // trace("PosiblesAcciones.length: "+PosiblesAcciones.length); CambiarSigno(); if (Jugadores == "HumanoIA" or Jugadores == "IAHumano") { TurnoDeIA(); } } else { // (sólo queda 1 acción en la lista, // pero es la que acaba de usar, // que debe borrarse, así que no quedan) trace ("Empate luego de que marcó el humano"); // trace("PosiblesAcciones.length: "+PosiblesAcciones.length); Empate(); } } // Usada en ChequeoHorizontal y requerida en otros chequeos: function ObtenerColumnayFilaDelMarcado () { ColumnaDelMarcado = CasilleroMarcado%CasillerosPorFila; // trace ("Su Columna según el cálculo es: "+ColumnaDelMarcado); FilaDelMarcado = Math.floor(CasilleroMarcado/CasillerosPorFila); // trace ("Su Fila: "+FilaDelMarcado); } // Usada cuando alguien gana o en HacerTablero si es IA VS IA: function InutilizarBotones () { BotonesInutilizados = -1; do { BotonesInutilizados++; setProperty ("Casillero"+BotonesInutilizados+".Boton", _visible, false); } while (BotonesInutilizados<MaxCasillero); } // Usada cuando hay que ubicar un mensaje, duh: function UbicarMensaje () { setProperty (Mensaje, _x, 192.4); setProperty (Mensaje, _y, 192); // gotoAndStop (3); } // En caso de empate: function Empate () { attachMovie("sEmpate", "Mensaje", NroDeCasilleroaColocar+1); UbicarMensaje(); // Para que en el modo IA VS IA, la IA no juegue más: Win = "Sí"; trace("Empate"); } function CambiarSigno () { if (SignoDeTurno == "X") { SignoDeTurno = 0; } else { SignoDeTurno = "X"; } } function TurnoDeIA () { // Elegir una acción al azar: NroDeAccionElegida = random(PosiblesAcciones.length); AccionElegida = PosiblesAcciones[NroDeAccionElegida]; trace ("IA ha marcado: "+AccionElegida); // Eliminar la que está en el nro elegido: PosiblesAcciones.splice(NroDeAccionElegida, 1); trace (PosiblesAcciones.join("")); LastNroDeAcccionPosible--; trace ("LastNroDeAcccionPosible disminuyó: "+LastNroDeAcccionPosible); eval("Casillero"+AccionElegida).attachMovie("s"+SignoDeTurno, "Signo", 0); Situacion[AccionElegida] = SignoDeTurno; // Inutilizar el botón de ahí: setProperty (eval("Casillero"+AccionElegida+".Boton"), _visible, false); // Ver si IA ganó: CasilleroMarcado = AccionElegida; // trace ("JuntosRequeridos: "+JuntosRequeridos); ChequearVertical(); // trace("PosiblesAcciones.length: "+PosiblesAcciones.length); if (Win == "Sí") { // Sí, inutilizar botones del tablero // (debería ser sólo los activos): InutilizarBotones(); // Mostrar mensaje de victoria: attachMovie("sGano"+SignoDeTurno, "Mensaje", NroDeCasilleroaColocar+1); UbicarMensaje (); } else if (PosiblesAcciones.length == 0) { trace ("Empate luego de que marcó la IA"); // trace("PosiblesAcciones.length: "+PosiblesAcciones.length); Empate(); } else { CambiarSigno(); } }
ChequeoHorizontal lo que hace es fijarse si hay victoria. Si hay, hace que Win sea "Sí". Sino, llama a otros chequeos que hacen cosas parecidas. Pueden ver el código en mi otro tema reciente, pero como dije no es la cuestión aquí. Frame 2: stop(); Nada relevante aquí, simplemente ocurre el juego, el jugador hace clic en los casilleros. Los casilleros tienen un botón con esto: on (release) { _level0.CasilleroMarcado = _parent.CasilleroAsociado; _level0.HumanoHaMarcado(); } Frame 3: Aquí funciona el modo IA VS IA, un objeto tiene: onClipEvent (enterFrame) { trace("SignoDeTurno: "+_level0.SignoDeTurno); _level0.TurnoDeIA(); trace("Win: "+_level0.Win); if (_level0.Win == "No") { trace("SignoDeTurno: "+_level0.SignoDeTurno); _level0.TurnoDeIA(); trace("Win: "+_level0.Win); } trace("Win: "+_level0.Win); // No va un else, esto es que si la IA ganó en su 1er turno o... // en su 2ndo, frana: if (_level0.Win == "Sí") { trace("Va al frame 2"); _root.gotoAndStop (2); } }
No me gusta mucho usar distintos frames pero parece la forma más eficiente de evitar ifs, evals, etc, no sé...
|
|
|
48
|
Programación / Programación General / ¿Cómo hacer un programa que aprenda a jugar expertamente Signos en línea?
|
en: 24 Marzo 2025, 07:12 am
|
Aquí pueden ver a la máquina jugando al azar: https://youtu.be/NtGWCFXvfk8En vez de 4 en línea puede ser 3, 5, etc. Lo que tengo no es suficiente y no lo apliqué: // Signos en línea en tablero de Lado*Lado: // Este programa tiene básicamente 2 etapas, // que se pueden resumir así: // 1: // Desde la situación inicial probar las acciones, // guardando las situaciones nuevas, // y probando acciones en ellas también. // Guardar las situación-acción que causan una victoria, // y las que causan un empate. Es el RE de esa situación, // resultado esperado (porque en otros casos es el que... // se espera o supone si el rival juega bien). // 2: ACTUALIZAR ESTA // En las situaciones no resueltas, probar las acciones. // Si las consecuencias tienen RE, anotar cuantas de ellas... // son victoria de X, 0 o empate y anotar la acción que... // cause la RE más favorable, considerando secundariamente... // las cantidades. // JuntosRequeridos = 2; CasillerosPorFila = 2; // Contando desde 0: MaxColumna = CasillerosPorFila-1; // Los casilleros están numerados así: // 0 1 2 // 3 4 5 // 6 7 8 Casilleros = CasillerosPorFila*CasillerosPorFila; MaxCasillero = Casilleros-1; // Uso arrays porque es más fácil así modificar partes... // de los valores de variables (los casilleros): // Situación a experimentar nro 1, signo en los casilleros // (a este array se le agregarán valores): SaE1 = []; ValoraAgregar = -1; do { ValoraAgregar++; // v significa vacío SaE1.push("v"); // trace("ValoraAgregar es "+ValoraAgregar); } while (ValoraAgregar < MaxCasillero); delete (ValoraAgregar); // Situaciones a experimentar (cuántas son): SaE = 1; NroDeSExperimentandose = 0; NoEvaluedSaE = "SaE1"; SaEEvaluedyJoined = "S"+(eval(NoEvaluedSaE).join("")); // Usada para fácilmente saber de qué signo es turno: set (SaEEvaluedyJoined+"Turno", "X"); // Con LastAPosible, usada para evitar probar... // acciones innecesarias y saber si sólo queda 1: set (SaEEvaluedyJoined+"FirstAPosible", 0); set (SaEEvaluedyJoined+"LastAPosible", MaxCasillero); // Usada a continuación y en varios casos: function PrepararExperimentosEnOtraS () { // trace("Ejecutando PrepararExperimentosEnOtraS"); NroDeSExperimentandose++; trace("Se inician experimentos en otra situación, la anotada nro "+NroDeSExperimentandose); // Usada para evitar concatenar repetidamente: NoEvaluedSaE = "SaE"+NroDeSExperimentandose; SituacionBase = eval(NoEvaluedSaE); SaEEvaluedyJoined = "S"+(SituacionBase.join("")); Turno = eval(SaEEvaluedyJoined+"Turno"); FirstActionPosible = eval(SaEEvaluedyJoined+"FirstAPosible"); LastActionPosible = eval(SaEEvaluedyJoined+"LastAPosible"); Action = FirstActionPosible; } PrepararExperimentosEnOtraS(); // Usada en frame 2 repetidamente: function BuscarBuenasSituacionesEt1 () { // Plantear situación porque puede modificarse pero... // podría requerirse su estado original luego: Situacion = SituacionBase.slice(); // trace("La situación experimentándose es "+Situacion); EvaluarAplicabilidadEt1(); } // Usada luego de que cambia la SaE y/o la acción: function EvaluarAplicabilidadEt1 () { // trace("Ejecutando EvaluarAplicabilidadEt1"); if (Situacion[Action] == "v") { // trace("La acción "+Action+" es realizable."); AplicarAccionEt1(); } else { // trace("La acción "+Action+" no es realizable."); BuscarAccionEt1(); } } // Usada luego de EvaluarAplicabilidadEt1, // si una acción es realizable: function AplicarAccionEt1 () { // trace("Ejecutando AplicarAccionEt1"); Situacion[Action] = Turno; // trace("Se realizó la acción "+Action+"; ahora la situación es "+Situacion); // ¿Ganó? // Si no se detecta victoria vertical, // revisa de otros modos (ver las funciones Chequear): ChequearVertical(); if (Win == "Sí") { // Sí, crear datos sobre eso: // trace("Ganó, ahora se sabe que en la situación "+SituacionBase+" se gana usando la acción "+Action); set (SaEEvaluedyJoined+"BestAction", Action); set (SaEEvaluedyJoined+"RE", Turno); // Se borra la situación de la lista a experimentar, // pues ya se halló la mejor acción en ella: BorrarSaE(); BuscarOtraSituacionEt1(); } else if (FirstActionPosible == LastActionPosible) { // sino si es empate (no hay más acciones posibles): // Parecido, crear datos sobre eso: // trace("Empató, ahora se sabe que en la situación "+SituacionBase+" se empata usando la acción "+Action); // (y es la mejor acción porque no hay otra) set (SaEEvaluedyJoined+"BestAction", Action); set (SaEEvaluedyJoined+"RE", "Empate"); // Se borra la situación de la lista a experimentar, // pues ya se halló la mejor acción en ella: BorrarSaE(); BuscarOtraSituacionEt1(); } else { EvaluarConocimientoSobreSEt1(); // ¿Queda alguna acción sin probar... // en la situación? BuscarAccionEt1(); } } // Usada luego de AplicarAccionEt1, // si causa victoria o empate: function BorrarSaE () { // La última SaE ponerla en la actual: // trace("ATENCIÓN: "+NoEvaluedSaE+", que es "+SaEEvaluedyJoined); set (NoEvaluedSaE, eval("SaE"+SaE).slice()); // trace("...ahora es: "+eval(NoEvaluedSaE)); // Borrar la última: delete (eval("SaE"+SaE)); // Indicar que hay una menos: SaE--; // También se borran datos prácticos que ya no se usarán: // trace("SaEEvaluedyJoined: "+SaEEvaluedyJoined); // trace("SaEEvaluedyJoined+Turno: "+eval(SaEEvaluedyJoined+"Turno")); delete (eval(SaEEvaluedyJoined+"Turno")); // trace("SaEEvaluedyJoined+Turno: "+eval(SaEEvaluedyJoined+"Turno")); delete (eval(SaEEvaluedyJoined+"FirstAPosible")); delete (eval(SaEEvaluedyJoined+"LastAPosible")); // Indicar que vuelva a invertigarse la del número actual, // pues ahora es otra: NroDeSExperimentandose--; } // Usada luego de EvaluarAplicabilidadEt1, // cuando una acción no es realizable: function BuscarAccionEt1 () { // trace("Ejecutando BuscarAccionEt1"); if (Action < LastActionPosible) { // Si queda alguna acción sin probar... // en la situación, probarla: Action++; // Se ejecutará BuscarBuenasSituaciones. } else { // trace("No hay más acciones realizables."); BuscarOtraSituacionEt1(); } } // Usada luego de que hay victoria, empate o si no hay más acciones posibles: function BuscarOtraSituacionEt1 () { // trace("Ejecutando BuscarOtraSituacionEt1"); if (SaE > NroDeSExperimentandose) { PrepararExperimentosEnOtraS(); } else { trace( "No hay más situaciones a experimentar; inicia la etapa 2."); // IniciarEtapa2(); gotoAndStop(4); } } // Usada en AplicarAccionEt1 cuando no hay victoria ni empate: function EvaluarConocimientoSobreSEt1 () { // trace("Ejecutando EvaluarConocimientoSobreSEt1"); SituacionJoined = Situacion.join(""); NombreDeSituacion = "S"+SituacionJoined; ResumenDeBest = NombreDeSituacion+"BestAction"; // ¿Se ha llegado antes a la situación? if (eval(ResumenDeBest) == undefined) { // No, anotar que debe investigarse: SaE++; // Copiar array (porque no se puede normalmente): set ("SaE"+SaE, Situacion.slice()); // trace("Esa situación no está anotada; se anota como nro "+SaE); set(ResumenDeBest, "Desconocida"); if (Turno == "X") { set (NombreDeSituacion+"Turno", "0"); } else { set (NombreDeSituacion+"Turno", "X"); } // Averiguar cual es su 1er acción posible: AccionRevisandose = -1; do { AccionRevisandose++; if (Situacion[AccionRevisandose] == "v") { set (NombreDeSituacion+"FirstAPosible", AccionRevisandose); break; } } while (true); // Averiguar cual es su última acción posible: AccionRevisandose = Casilleros; do { AccionRevisandose--; if (Situacion[AccionRevisandose] == "v") { set (NombreDeSituacion+"LastAPosible", AccionRevisandose); break; } } while (true); } } function ObtenerColumnayFilaDelMarcado () { FilaDelMarcado = Math.floor(Action/CasillerosPorFila); ColumnaDelMarcado = Action%CasillerosPorFila; } function ChequearVertical () { // trace ("Ejecutando ChequearVertical"); // // SOLO FUNCIONA SI CasillerosPorFila >= JuntosRequeridos. // // Se revisará la vertical. Desde el casillero más arriba... // que pueda estar incluído en la línea, // hasta el casillero marcado. Si se haya alguno que no... // tenga la marca requerida, se repite el proceso mirando... // desde uno más abajo del fallado, y mirando ahora hasta... // más abajo, según corresponda: Desde = Action-CasillerosPorFila*(JuntosRequeridos-1); // Mientras el casillero no exista: while (Desde<0) { // trace ("Desde es "+Desde+", se aumentará"); // Indicar que se empiece a mirar desde más abajo: Desde = Desde+CasillerosPorFila; } do { Hasta = Desde+CasillerosPorFila*(JuntosRequeridos-1); if (Hasta>MaxCasillero) { // Para ganar se necesitaría más casilleros hacia... // abajo de los que hay, terminar análisis: // trace ("No hay suficientes cuadraditos abajo"); break; } Puntero = Desde; // trace ("Comenzando chequeo desde "+Desde+" hasta "+Hasta); // Puede cambiar: Win = "Sí"; do { // trace ("Chequando el casillero "+Puntero); if (Situacion[Action] != Situacion[Puntero]) { Win = "No"; Desde = Puntero+CasillerosPorFila; break; } Puntero = Puntero+CasillerosPorFila; } while (Puntero<=Hasta); } while (Desde<=Action && Win == "No"); if (Win == "No") { ChequearHorizontal(); } } function ChequearHorizontal () { // trace ("Ejecutando ChequearHorizontal"); // Es similar al chequeo vertical, pero aquí no sirve... // sumar o restar a un puntero que marque el casillero... // porque puede existir ese casillero pero no estar en... // un costado. En vez de eso, se obtiene su columna y... // fila, se modifica la columna si es posible, // y se calcula cual es el casillero a mirar: ObtenerColumnayFilaDelMarcado(); DesdeColumna = ColumnaDelMarcado-JuntosRequeridos+1; // Para que no mire cuadraditos inexistentes en la izq: if (DesdeColumna<0) { DesdeColumna = 0; } do { HastaColumna = DesdeColumna+JuntosRequeridos-1; if (HastaColumna>MaxColumna) { // Para ganar se necesitaría más casilleros hacia... // la derecha de los que hay, terminar análisis: // trace ("No hay suficientes cuadraditos a la derecha"); break; } Puntero = DesdeColumna; // trace ("Comenzando chequeo desde "+DesdeColumna+" hasta "+HastaColumna); // Puede cambiar: Win = "Sí"; do { CasilleroaMirar = FilaDelMarcado*CasillerosPorFila+Puntero; // trace ("Chequando el casillero "+CasilleroaMirar); if (Situacion[Action] != Situacion[CasilleroaMirar]) { Win = "No"; DesdeColumna = Puntero+1; break; } Puntero++; } while (Puntero<=HastaColumna); } while (DesdeColumna<=ColumnaDelMarcado && Win == "No"); if (Win == "No") { ChequearDesdeUpIzq(); } } // La diagonal así \ function ChequearDesdeUpIzq () { // trace ("Ejecutando ChequearDesdeUpIzq"); DesdeColumna = ColumnaDelMarcado-JuntosRequeridos+1; // trace("DesdeColumna: "+DesdeColumna); DesdeFila = FilaDelMarcado-JuntosRequeridos+1; // trace("DesdeFila: "+DesdeFila); // Para que no mire cuadraditos inexistentes: if (DesdeColumna<DesdeFila) { Sumar = DesdeColumna; } else { Sumar = DesdeFila; } // trace("Sumar: "+Sumar); if (Sumar<0) { // trace("Sumando."); DesdeColumna = DesdeColumna-Sumar; // trace("DesdeColumna: "+DesdeColumna); DesdeFila = DesdeFila-Sumar; // trace("DesdeFila: "+DesdeFila); } do { HastaColumna = DesdeColumna+JuntosRequeridos-1; if (HastaColumna>MaxColumna) { // Para ganar se necesitaría más casilleros hacia... // la derecha de los que hay, terminar análisis: // trace ("No hay suficientes cuadraditos a la derecha"); break; } HastaFila = DesdeFila+JuntosRequeridos-1; // Sirve usar MaxColumna en vez de crear MaxFila... // porque como el tablero es cuadrado serían iguales: if (HastaFila>MaxColumna) { // Para ganar se necesitaría más casilleros hacia... // abajo de los que hay, terminar análisis: // trace ("No hay suficientes cuadraditos abajo"); break; } PunteroDeColumna = DesdeColumna; PunteroDeFila = DesdeFila; // trace ("Comenzando chequeo desde columna "+DesdeColumna+" y fila "+DesdeFila); // trace ("hasta columna "+HastaColumna+" y fila "+HastaFila); // Puede cambiar: Win = "Sí"; do { CasilleroaMirar = PunteroDeFila*CasillerosPorFila+PunteroDeColumna; // trace ("Chequando el casillero "+CasilleroaMirar); if (Situacion[Action] != Situacion[CasilleroaMirar]) { Win = "No"; DesdeColumna = PunteroDeColumna+1; DesdeFila = PunteroDeFila+1; break; } PunteroDeColumna++; PunteroDeFila++; } while (PunteroDeColumna<=HastaColumna); } while (DesdeColumna<=ColumnaDelMarcado && Win == "No"); if (Win == "No") { ChequearDesdeDownIzq(); } } // La diagonal así / function ChequearDesdeDownIzq () { // trace ("Ejecutando ChequearDesdeDownIzq"); DesdeColumna = ColumnaDelMarcado-JuntosRequeridos+1; // trace("DesdeColumna: "+DesdeColumna); DesdeFila = FilaDelMarcado+JuntosRequeridos-1; // trace("DesdeFila: "+DesdeFila); // Para que no mire cuadraditos inexistentes: ColumnasInexistentes = 0; if (DesdeColumna<0) { ColumnasInexistentes = DesdeColumna*-1; } FilasInexistentes = 0; // Está bien usar MaxColumna porque MaxFila sería igual: if (DesdeFila>MaxColumna) { FilasInexistentes = DesdeFila-MaxColumna; } if (ColumnasInexistentes>=FilasInexistentes) { Ajuste = ColumnasInexistentes; } else { Ajuste = FilasInexistentes; } // trace("Ajuste: "+Ajuste); if (Ajuste>0) { // trace("Ajustando."); DesdeColumna = DesdeColumna+Ajuste; // trace("DesdeColumna: "+DesdeColumna); DesdeFila = DesdeFila-Ajuste; // trace("DesdeFila: "+DesdeFila); } do { HastaColumna = DesdeColumna+JuntosRequeridos-1; if (HastaColumna>MaxColumna) { // Para ganar se necesitaría más casilleros hacia... // la derecha de los que hay, terminar análisis: // trace ("No hay suficientes cuadraditos a la derecha"); break; } HastaFila = DesdeFila-JuntosRequeridos+1; if (HastaFila<0) { // Para ganar se necesitaría más casilleros hacia... // arriba de los que hay, terminar análisis: // trace ("No hay suficientes cuadraditos arriba"); break; } PunteroDeColumna = DesdeColumna; PunteroDeFila = DesdeFila; // trace ("Comenzando chequeo desde columna "+DesdeColumna+" y fila "+DesdeFila); // trace ("hasta columna "+HastaColumna+" y fila "+HastaFila); // Puede cambiar: Win = "Sí"; do { CasilleroaMirar = PunteroDeFila*CasillerosPorFila+PunteroDeColumna; // trace ("Chequando el casillero "+CasilleroaMirar); if (Situacion[Action] != Situacion[CasilleroaMirar]) { Win = "No"; DesdeColumna = PunteroDeColumna+1; DesdeFila = PunteroDeFila-1; break; } PunteroDeColumna++; PunteroDeFila--; } while (PunteroDeColumna<=HastaColumna); } while (DesdeColumna<=ColumnaDelMarcado && Win == "No"); // trace("Win: "+Win); }
Resumen:  Mi idea con eso es hallar las mejores acciones en cada posible situación de un tablero de cierto tamaño cuando se requieren cierta cantidad de signos en línea, es decir, si por ejemplo en el "aprendedor" se configura que el tablero tiene 6 casilleros de largo y se requieren 5 signos en línea, el programa aprendería a jugar así, no en 5 casilleros de largo, ni 7, etc, ni con 6 signos requeridos, etc. Así que en ese sentido no voy por buen camino, ya que no puedo correr el programa poniendo cada pares posibles de valores. Y aunque pudiera programar que los varíe, los resultados son de este estilo: SvX0vBestAction = 0 es decir el nombre de la variable indica la situación, lo que sucederá es que serán un montón de variables con nombres cada vez más largos, es mejor algo más deductivo, unas reglas generales, siempre y cuando den buenos resultados. La etapa 2 creo que debería tener en cuenta probabilidades, es decir, que cuando por ejemplo el resultado esperado es un empate, busque llegar a situaciones en que la mayoría de opciones del rival lo lleven a una derrota. Las probabilidades se basarían en la cantidad de opciones y las que salvan al rival, o a uno mismo (si el resultado esperado es derrota, aunque en este juego una IA no debería llegar a eso), no en cuan evidentes para un humano son las opciones mejores, porque eso parece subjetivo y complicado, ni lo intento. Aún no tengo del todo claro cómo hacer la etapa 2. Y he estado cambiando cosas de la 1. En eso empecé a creer que en la etapa 1 debería guardar las posibilidades o en la 2nda no podría saber las probabilidades, o sería complicado. Creo que debería poner 3 etapas... 1- Se pueban acciones en las posibles situaciones, se van anotando las situaciones, y se anota "la mejor acción" y resultado cuando en la situación sólo hay 1 acción posible. 2- En las situaciones que quedaron sin resolver, se prueban acciones... No sé bien... en ese punto una acción puede: - Llevar a una situación resuelta, que luego será un empate o derrota. - Llevar a una situación no resuelta. - Llevar a una victoria. Supongamos que está en: 0XX XX0 0AB Turno del 0. Si pone en A, lleva a una situación resuelta, sólo queda una posible jugaba, B, y es empate. Si pone en B, también es resuelta, pero es derrota. Entonces deben crearse unas variables digamos así: S0XXXX00vvWinX = 1 S0XXXX00vvEmpate = 1 marcando que en esa situación hay 1 posibilidad de que gane X y otra de que haya empate. La idea es que en la etapa 3, cuando haya que elegir cual es la mejor acción en una situación anterior a esta, cuando se llegue a esta se vea que X tiene 1/2 de probabilidad de ganar, aunque el resultado esperado sea empate, logrando entonces que el programa deduzca que para X es una situación más conveniente a llegar que otras, por ejemplo: 0CX XX0 0AB Turno de X. Si 0 juega bien, será empate, pero X poniendo en C o A tiene probabilidades de ganar, poniendo en B no. Se trata de guardar posibilidades y luego guardar las acciones que lleven a situaciones en que haya más probabilidades de ganar. Otra posibilidad es que lleve a una victoria, ejemplo: 0Xv 0Xv vvv Turno del X. Lo que le conviene a X es evidente, pero... 0 debe tener en cuenta la posibilidad de que no haga eso. En tableros más grandes, puede que se deba elegir entre 2 situaciones inconvenientes, quizá en una X tiene 2 formas de ganar y en la otra sólo 1, por lo tanto debe grabarse la 2nda. Para eso debe haber datos sobre qué puede suceder, y por eso aunque la mejor acción aquí sea evidente, la situación no se puede resolver mientras no se tengan datos de las próximas, para saber exactamente qué tan probable es que gane X en esta (parece 1/5 pero es más complejo), para que previamente 0 pueda saber si esta situación es peor que otra alternativa, como expliqué. Todo esto es como muy rebuscado, creo que sólo tiene sentido en tableros grandes. Normalmente la IA no llegaría a situaciones en que pueda perder. A ver un caso más realista: vvvv vXvv vvvv vvvv Turno de 0, se requieren 3 para ganar. Parece que no importa lo que haga, perderá, pero la idea es que tenga las mayores probabilidades posibles de ganar o al menos empatar. En fin, parece que entonces es cuestión de ir hacia atrás, en orden, es decir, resolver 1ero las situaciones en que sólo 1 acción es posible, luego las que sólo tienen 2, etc. Aunque en algunas sea obvio cómo ganar, no se pueden considerar resueltas antes de tiempo. Así que sería: Etapa 1: Las acciones pueden llevar a situaciones nuevas, no resueltas, empates o victorias. Etapa 2: Las acciones pueden llevar a situaciones no resueltas, resueltas o victorias. Etapa 3: Las acciones pueden llevar a situaciones no resueltas o resueltas. Considero importantes las diferencias para evitar ifs en vano... Una posible mejora del programa sería, en vez de partir de un tablero vacío e ir grabando situaciones a las que se llegue, generar las posibles situaciones finales, resolverlas, generar las situaciones previas, resolverlas, y así. O en vez de tener 1 lista de situaciones, tener una por cada cantidad de signos puestos, o sea: Una lista de situaciones en que sólo 1 acción es posible. Otra en que sólo 2 acciones son posibles. Etc. Son mejoras alternativas. Sirven para evitar que el programa analice repetidamente situaciones que sabemos que aún no podrá resolver. ¿Ustedes cómo lo harían? Un programa que aprenda a jugar expertamente Signos en línea.
|
|
|
49
|
Foros Generales / Foro Libre / Re: En honor a quienes caminaron antes que nosotros (en el foro)
|
en: 20 Marzo 2025, 06:47 am
|
Al unico que que veo aún aquí es a brujo que me llego a meter a un wargame que se hizo acá en el foro para entrenar gente ¿Me puedes explicar mejor dónde o cómo lo viste? Hace casi 2 meses que espero me responda un asunto y tampoco lo he visto postear en el foro. ¿O tu comentario es un sarcasmo/bait? En otro tema preguntas qué pasó con el foro. Yo participo desde hace unos 10 7 años creo, no lo noto tan distinto. Antes no sé, pero no es poco común que un foro pierda actividad, las causas no las sé, en mi caso que me borraron comentarios sin explicación. Ahora postié porque es un caso especial ya que dijiste que viste al admin, pf, espero que sea cierto. ¿Y tú por qué te fuiste? Quejarse es fácil pero por haberte ído eres, probablemente, parte del culpable de que el foro haya perdido actividad o calidad según tu criterio.
|
|
|
50
|
Foros Generales / Sugerencias y dudas sobre el Foro / Hace como 1 mes envié un mensaje al administrador y no lo respondió.
|
en: 24 Febrero 2025, 21:21 pm
|
Ni siquiera ha posteado en algún tema, o no lo he visto. Hace poco he tenido días difíciles así que no estoy de ánimo para luchar por un foro más justo, si es que al admin le interesa, o para entender qué pasa con algún moderador o algunos, que me borra/n mensajes injustamente y sin explicar, pero, dejo este comentario, que quizá sea borrado también, meh, pero algún usuario lo verá: Si quieren decirle algo al admin, mejor por email, quizá, es un consejo. Yo es que paso de hablar por email con un hacker. Mi idea era que él me explique o solucione el problema y luego seguir participando en el foro. Pero al parecer está muy ocupado, complicado, o no le interesa lo suficiente mi asunto o lo que pasa en su foro. O a lo mejor es una fachada y en realidad es de algún moderador. No quiero hacer aportes a un foro que es injusto conmigo. https://www.youtube.com/watch?v=htOqsFL14YU
|
|
|
|
|
|
|