|
41
|
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
|
|
|
42
|
Programación / Programación General / Captar victoria en juego estilo 3 en línea. 2 contiguos solamente.
|
en: 20 Enero 2025, 19:40 pm
|
La cantidad de casilleros por fila y columna es configurable.
La cantidad de contiguos para ganar, también.
Pero por ahora quiero resolver el caso de 2 contiguos simplemente.
La situación se guarda en un array, es decir lo que tiene cada casillero, por ejemplo esta: vv0 vXv vvv Es: v, v, 0, v, X, v, v, v, v donde v es vacío
Mi idea es que, cuando un casillero se marque, se mire arriba, luego arriba-derecha, y así sucesivamente como las agujas de un reloj.
El reto es averiguar qué casillero en el array es el de arriba, y demás. Y si es que existe, sino capaz que mira alguno que no debe, no sé.
Si por ejemplo el casillero marcado es el nro 0, el de arriba no existe, el de arriba-derecha tampoco, el de la derecha es su +1... Pero si se marca el nro 2, el de su derecha no es el +1, sino que no existe.
Quizá la mejor forma de resolver esto es creando variables estilo: Casillero0_0 = "v" Casillero1_0 = "v" Casillero2_0 = "0"
Pero entre más grande sea el tablero, más variables así habría y son una copia de las otras así que no parece buena idea.
Debe haber una forma de calcular en qué posición del array está el casillero contiguo que se quiere mirar ¿cómo?
|
|
|
43
|
Programación / Programación General / Indicar que una acción no debe usarse.
|
en: 20 Enero 2025, 04:16 am
|
Intento hacer una IA que aprenda a poner una X en un tablero y luego otra en la derecha o izquierda. El problema que intento resolver en cuanto a eso, es que puede poner una X donde ya hay, debo evitarlo. Sé que debo poner algo como: if (Situacion[Action] == "v") { // Es realizable, realizarla... sino // No, ver si hay otra...
Pero no sé bien qué pasa, es como que si hago eso tendría que poner código igual en distintos lados (aunque a ese código lo convierta en una función, siento que es innecesario que se repita), innecesariamente. Aún no tengo el código completo. Díganme cómo pondrían uds ese if, dónde, o cómo harían. // 2 en línea horizontal, en tablero de 2x2, sólo X: // // Uso arrays porque es más fácil así modificar los nombres... // de variables: // // Los casilleros están numerados así: // 0 1 // 2 3 // Situación inicial (v es casillero vacío): SituacionBase = ["v", "v", "v", "v"]; // Ponerla en la lista de situaciones a experimentar: SaE1 = SituacionBase.slice(); // Situaciones a experimentar (cuántas son): SaE = 1; NroDeSExperimentandose = 1; NombreDeSE = "S"+(SaE1.join("")); // Acción a realizarse (casillero a marcar): Action = 0; function BuscarAccionesGanadoras () { PlantearSyActuar(); // ¿Ganó? // Para averiguarlo, calcular fila (contando desde 0): Fila = Math.floor(Action/2); // trace(" Fila: "+Fila); if (Situacion[Fila*2] == Situacion[Fila*2+1]) { // trace("Situacion[Fila*2] == Situacion[Fila*2+1]: "+Situacion[Fila*2]+" == "+Situacion[Fila*2+1]); // Sí, crear datos sobre eso: // En la situación base conviene la acción realizada: set (NombreDeSE+"BestAction", Action); // En esa situación se requiere 1 acción para ganar: set (NombreDeSE+"DistanciaaGanar", 1); trace("Ganó, ahora se sabe que en la situación "+SituacionBase+" se gana usando la acción "+Action); // ¿Aún hay situaciones a experimentar? if (SaE > NroDeSExperimentandose) { IniciarExperimentosEnOtraS(); } else { // Comenzar la etapa 2. IniciarEtapa2(); } } else { EvaluarConocimientoSobreSyEtc(); } } function PlantearSyActuar () { // 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); // Aplicación de la acción: Situacion[Action] = "X"; trace(" Se realizó la acción "+Action+"; ahora la situación es "+Situacion); } function IniciarExperimentosEnOtraS () { NroDeSExperimentandose++; SituacionBase = eval("SaE"+NroDeSExperimentandose); // trace("SituacionBase: "+SituacionBase); // Reset de la acción a probar: Action = 0; trace("Se inician experimentos en otra situación"); } function IniciarEtapa2 () { DistanciaaGanarAceptada = 1; trace("Se experimentaron todas las situaciones; se reexperimentarán buscando resultados menos óptimos"); trace("Son "+SaE+" situaciones; se acepta que la distancia a la victoria sea "+DistanciaaGanarAceptada); gotoAndStop (3); } function EvaluarConocimientoSobreSyEtc () { SituacionHechaTexto = Situacion.join(""); NombreDeSituacion = "S"+SituacionHechaTexto; Resumen = NombreDeSituacion+"BestAction"; if (eval(Resumen) == undefined) { // No, anotar que debe investigarse: SaE++; set ("SaE"+SaE, Situacion.slice()); trace("Esa situación no está anotada; se anota como nro "+SaE); // Esto para saber que está anotada: set (Resumen, "Desconocida"); } // ¿Queda alguna acción sin probar? if (Action < 3) { // Sí, probar otra: Action++; } else if (SaE > NroDeSExperimentandose) { // Sino si aún hay situaciones a experimentar: trace("No hay más acciones posibles en la situación"); IniciarExperimentosEnOtraS(); } else { // Comenzar la etapa 2. IniciarEtapa2(); } }
Ah, BuscarAccionesGanadoras se repite hasta que empiece la etapa 2.
|
|
|
44
|
Programación / Programación General / ¿Qué lío he hecho con mi generador de tableros estilo 3 en línea?
|
en: 19 Enero 2025, 23:57 pm
|
Así funcionaba: function HacerTablero () { MaxCasillero = CasillerosPorFila*CasillerosPorFila; LargoDeCasilleros = 384/CasillerosPorFila; CasillerosColocados = 0; // Sus columnas y filas se cuentan desde 0, // sirven para posicionarlos más fácil: Columna = 0; Fila = 0; do { CasillerosColocados++; CasilleroaColocar = "Casillero"+CasillerosColocados; // v es vacío. set ("SignoEn"+CasilleroaColocar, "v"); // sCasillero tiene código. attachMovie("sCasillero", CasilleroaColocar, CasillerosColocados); setProperty (CasilleroaColocar, _x, LargoDeCasilleros*Columna); setProperty (CasilleroaColocar, _y, LargoDeCasilleros*Fila); setProperty (CasilleroaColocar, _width, LargoDeCasilleros); setProperty (CasilleroaColocar, _height, LargoDeCasilleros); Columna = Columna+1; if (Columna == CasillerosPorFila) { Columna = 0; Fila = Fila+1; } // Para que al presionar el botón se sepa qué modificar: set (CasilleroaColocar+".CasilleroAsociado", CasillerosColocados); } while (CasillerosColocados<MaxCasillero); }
Intenté poner que se cuenten desde 0 en vez desde 1 (o sea, que en vez de Casillero1, Casillero2, etc, sean Casillero0, Casillero1, etc) y ahora anda mal, pone uno menos y además lo borra mal (eso es otro tema): function HacerTablero () { // Esto se irá especificando en el while: Situacion = []; PosiblesAcciones = []; // Los casilleros se cuentan desde 0: MaxCasillero = CasillerosPorFila*CasillerosPorFila-1; LargoDeCasilleros = 384/CasillerosPorFila; NroDeCasillerosaColocar = -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 = Columna+1; if (Columna == CasillerosPorFila) { Columna = 0; Fila = Fila+1; } // Para que al presionar el botón se sepa qué modificar: set (CasilleroaColocar+".CasilleroAsociado", NroDeCasilleroaColocar); trace("Colocado el "+NroDeCasilleroaColocar); } while (NroDeCasilleroaColocar<MaxCasillero); }
Si el tablero es de 3*3, se deben colocar 9, pero el máximo será 8 porque se cuentan desde 0. Y puse que el 1er colocado sea el 0. Pero el trace no lo indica, el 1er trace es del 1: Colocado el 1 Colocado el 2 ... Colocado el 8 ¿Qué pasa? Edit: Creo que era una s de más, sorry >___< NroDeCasillerosaColocar = -1; debe ser: NroDeCasilleroaColocar = -1;
|
|
|
45
|
Programación / Programación General / Busco testers para mi generador de dibujos, hallar errores, paso el editable también.
|
en: 15 Enero 2025, 16:18 pm
|
El siguiente link tiene un exe, un fla que es el archivo editable, y un swf que es como un exe menos peligroso pero sólo sirve si tienen Flash Player. Actualización de acuerdo al momento en que el post fue editado: 25-01-15, 16:18 https://drive.google.com/file/d/17Mn04J7GUnn4CGaqjnE70UeGHISAVqbN/view?usp=sharingNota: Al cliquear un dibujo, muta. Errores conocidos que intentaré arreglar más adelante: 1: La flecha de abajo que apunta a la izquierda, cuando se usa en la 1er pantalla quiero que lleve a las opciones de la última, pero aún no existe, así que está mal, no la usen en la 1er pantalla, saca las opciones y el programa se vuelve inusable. 2: Los botones de colores en la 2nda pantalla (flecha de abajo que apunta a la derecha) no deberían estar ahí. No los usen porque aún no llegué a arreglar esa parte, esos botones quedaron ahí por error. 3: No hay 3era pantalla así que tocar dos veces el botón de la derecha es mala idea. 4: Si habiendo X colores definidos (por ejemplo 3) se define uno salteando intermedios (por ejemplo habiendo 3, se define el 5), entonces al producirse los dibujos los colores intermedios serán negro. Solución planeada: Se elegirán colores al azar para esos. 5: Aparentemente, si mientras se generan los dibujos señalas un botón de colores preestablecidos y quitas el mouse antes de que el proceso termine, el botón quedará parpadeando. Es un efecto que debería ocurrir sólo mientras el mouse apunta al botón, pero como el programa estaba haciendo otras cosas no notó que el mouse se fue de ahí, supongo. En PC rápidas posiblemente no ocurra por poca cosa, tendrían que aumentar la cantidad de dibujos y cuadraditos, tal vez. 6: Puede que se vean pequeñas líneas entre los cuadraditos, como si no ocuparan todo el espacio que deben. Un problema del largo y ancho supongo, que es calculado, si el resultado es en decimales ya saben que pueden pasar ese tipo de cosas. 7: Si bajas la cantidad de cuadraditos por fila, la mínima cantidad de colores requeridos debe bajar, porque si por ejemplo es 3 pero sólo hay 2 cuadraditos pintables (el resto son simétricos), entonces podrá haber 3 colores en el dibujo. Eso se corrige pero la corrección hace que a partir de ahí el último color definido se elimine, o se deje de usar, aunque en el la pantalla se vea que está definido. 8: Si agregas un color, luego aumentas la cantidad de mínimos requeridos, y luego bajas la cantidad de cuadraditos por fila, el programa se tranca por lo que expliqué en el punto anterior. No sé por qué no lo corrige en este caso. Estoy corrigiendo, me toma tiempo...
|
|
|
46
|
Programación / Python / Ayuda para poner prints en código que no entiendo bien.
|
en: 14 Enero 2025, 15:32 pm
|
El programa genera las combinaciones de 2 letras. Carga un diccionario en inglés y otro en español. Anota las combinaciones de 2 letras que hay en las palabras. Luego anota las combinaciones de 2 letras que ocurren cuando 2 palabras se unen. Así por ejemplo se obtiene zh, por nariz y hoy. Finalmente, muestra las combinaciones que no ocurrieron, lo hace quitando de la 1er lista (la del inicio) las que anotó. Eso si funciona bien, no sé. Lo que quiero es que cuando anote una combinación, me diga cual anotó. Así me entero de cómo se forma qq por ejemplo. import itertools def cargar_diccionario(ruta): """Carga el diccionario desde un archivo .txt y devuelve un conjunto de palabras en minúsculas.""" with open(ruta, 'r', encoding='utf-8') as archivo: return set(palabra.strip().lower() for palabra in archivo) def generar_combinaciones(alfabeto): """Genera todas las combinaciones posibles de dos letras del alfabeto.""" return {a + b for a, b in itertools.product(alfabeto, repeat=2)} def buscar_combinaciones(diccionario, combinaciones): """Busca combinaciones dentro de las palabras del diccionario.""" presentes = set() # Buscar combinaciones dentro de palabras individuales for palabra in diccionario: for i in range(len(palabra) - 1): presentes.add(palabra[i:i+2]) # Buscar combinaciones entre palabras consecutivas lista_palabras = sorted(diccionario) # Ordenar las palabras for i in range(len(lista_palabras) - 1): ultima_letra = lista_palabras[-1] primera_letra = lista_palabras[i + 1][0] presentes.add(ultima_letra + primera_letra) return combinaciones - presentes # Paso 1: Cargar diccionarios diccionario_es = cargar_diccionario('diccionario_es.txt') diccionario_en = cargar_diccionario('diccionario_en.txt') # Paso 2: Generar combinaciones posibles alfabeto_es = 'abcdefghijklmnñopqrstuvwxyz' alfabeto_en = 'abcdefghijklmnopqrstuvwxyz' combinaciones_es = generar_combinaciones(alfabeto_es) combinaciones_en = generar_combinaciones(alfabeto_en) # Paso 3: Buscar combinaciones inexistentes en cada diccionario inexistentes_es = buscar_combinaciones(diccionario_es, combinaciones_es) inexistentes_en = buscar_combinaciones(diccionario_en, combinaciones_en) # Paso 4: Combinar resultados y mostrar combinaciones inexistentes en ambos idiomas inexistentes_totales = inexistentes_es.intersection(inexistentes_en) print(f"Combinaciones inexistentes en ambos idiomas ({len(inexistentes_totales)}):") print(sorted(inexistentes_totales)) input("Presione Enter para continuar ...")
|
|
|
48
|
Foros Generales / Dudas Generales / ¿Qué es un archivo .nsm?
|
en: 13 Enero 2025, 21:42 pm
|
No conseguí la respuesta.
Al abrirlo con el bloc de notas no aparece algo claro, es mucho espacio vacío y caracteres raros.
Es de 2002 dice, aunque quién sabe.
Pesa 22,9 KB (23.530 bytes).
El nombre prefiero no decirlo por las dudas, pero no es algo vergonzoso ni algo así xP
¿Cómo averiguo qué es?
|
|
|
49
|
Media / Diseño Gráfico / Reducir tamaño de la hoja, no de la imagen.
|
en: 13 Enero 2025, 20:41 pm
|
Hace mucho, cuando pegaba una imagen en Paint más grande que la hoja actual, me parecía absurdo que me preguntara si quería agrandar la hoja ¡obvio que sí!
Pero con el tiempo, me empezó a servir poner que no, porque si tomaba una foto pero sólo quería una parte, y luego tomaba otras fotos, porque era un video por ejemplo, me servía que el tamaño de la hoja se mantuviera como lo dejé, para guardar los archivos más rápido, de modo que se viera lo que yo quería y no la foto entera.
Desde que tengo Windows 7, Paint agranda la hoja sin preguntarme, y no veo la opción de modificarle el tamaño (la opción que veo modifica también la imagen, antes creo que no era así, yo no quiero que se agrande/achique la imagen, sólo la hoja), así que ¿con qué programa y cómo podría lograr lo que quiero?
Son varias fotos de un archivo de Flash, que al tomar foto sale el menú y las herramientas, podría modificar algunas cosas pero si cada vez que quiera tomar fotos debo hacer eso no me conviene.
Tomo una foto, supongamos que es así: xxxx xAAx xAAx xxxx Yo sólo quiero guardar la parte de las A. Para eso pego la imagen en Paint, la muevo hacia arriba e izquierda para quitar las x de esos sitios, y me queda así: AAxb AAxb xxxb bbbb Donde b es blanco, y yo ahora quiero reducir la hoja de modo que sólo queden las A. Debería ser fácil...
|
|
|
50
|
Programación / Programación General / IA para 2 en línea horizontal.
|
en: 12 Enero 2025, 23:55 pm
|
El juego es una simplificación del 3 en línea: - El tablero en vez de ser de 3x3 casilleros es de 2x2. - Lo que debe formarse, en vez de ser una línea horizontal, vertical o diagonal de 3 signos iguales, debe ser de 2 pero horizontal. Claro que es menos interesante que el original, es que se me complicó. Hay a grandes rásgos 3 tipos de IA, díganme otras si me faltan: A- La que sabe jugar como el programador le dijo, no aprende. B- La que sabe jugar según lo que entrenó, aprendió todo lo necesario. C- La que está aprendiendo, aprende mientras juega. El problema de A es que si el juego es complejo, no hay persona que sepa el modo ideal de jugar, y tampoco es fácil expresarlo. B requiere más tiempo lograrse entre más complejo sea el juego, por lo que llaman explosión combinatoria o algo así. C, entre más complejo sea el juego, menos útil es, porque difícilmente llegue a aprender todo lo necesario para jugar bien. El jugador podría hacer cosas distintas hasta el cansancio y en tales casos la IA sería como si recién empezara. Supongo que pueden pulirse de distintos modos, pero no sé bien cómo. A, en este caso simple sería así creo: Si IA usa X: // Intentar ganar: Si Casillero1_1 == "" && Casillero1_2 == "X" Poner X en 1_1 sino si Casillero1_1 == "X" && Casillero1_2 == "" Poner X en 1_2 Si Casillero2_1 == "" && Casillero2_2 == "X" Poner X en 2_1 sino si Casillero2_1 == "X" && Casillero2_2 == "" Poner X en 2_2 sino // Ya no es posible ganar (perder nunca fue): Poner en cualquiera vacío. sino // Evitar perder: Si Casillero1_1 == "" && Casillero1_2 == "X" Poner 0 en 1_1 sino si Casillero1_1 == "X" && Casillero1_2 == "" Poner 0 en 1_2 Si Casillero2_1 == "" && Casillero2_2 == "X" Poner 0 en 2_1 sino si Casillero2_1 == "X" && Casillero2_2 == "" Poner 0 en 2_2 sino // Ya no es posible perder: Poner en el único vacío que queda. Sobre C no pensé mucho. B es más difícil de lo que creí, a ver si me dan ideas. Mi idea es algo así: - En la situación inicial (tablero todo vacío), se prueban las acciones posibles y si se llega a una situación que no está en la lista de situaciones no resueltas, se agrega. Al principio esa lista está vacía, ahora habrá 4 porque 4 son las posibles consecuencias de las 4 posibles acciones. - Se genera una de las situaciones de la lista. Probamos las posibles acciones, ahora el signo es 0 en vez de X. Si obtenemos situaciones que no estén en la lista, de nuevo, las anotamos. - Repetimos eso con cada situación, el signo a poner depende de cuales sean, y llegará un punto en que poner un signo causará una victoria, por ejemplo en esta: XV 0V (V es vacío) La acción nro 2 (casillero 1_2, al lado de la X) causa victoria. Cuando eso ocurre, creamos unas variables cuyos nombres implican la situación anterior a la victoria, en el ejemplo sería XV0V, y ponemos una S delante para menos lío, sabemos que S significa situación. Bueno, las variables van a ser por ejemplo: SXV0VBestAction = 2 SXV0VDistanciaDeVictoria = 1 Significa que en esa situación conviene la acción 2 y que hace falta sólo 1 acción para llegar a la victoria. Eliminamos esa acción de la lista de situaciones sin resolver. - Cuando hayamos recorrido la lista de situaciones, comenzamos a recorrerla de nuevo, pero no sé bien qué debería hacerse ahora específicamente. En programas "similares" que había hecho, lo que se hacía era que si se llega a una situación cuya DistanciaDeVictoria fuese 1, a la anterior situación se le asignaba que DistanciaDeVictoria fuese 2, y así se repite realizar acciones, asignar "puntajes" a las situaciones, eliminarlas de la lista, y en cada nueva repetición aumentar el número asignado a DistanciaDeVictoria, hasta que ya no queden situaciones a investigar. Pero en este caso no se puede porque hay turnos, hay rivales, a ver: Si sólo hubiera X, sería así: Comenzamos investigando la situación VV VV Probamos una acción XV VV Anotamos esa situación en la lista de no resueltas. Probamos otra acción en la situación que estamos investigando, nos queda: VX VV En fin, en cierto punto vamos a investigar esta: XV VV Realizamos una acción que causa victoria XX VV Entonces definimos: SXVVVBestAction=2 SXV0VDistanciaDeVictoria = 1 Y en otro punto, cuando volvamos a investigar situaciones aún no resueltas, como esta: VV VV Cuando hagamos esto: XV VV Llegamos a una que la tenemos evaluada como 1, entonces a la anterior (la que puse arriba, todo V) le vamos a poner 2. Está clarísimo, se requieren 2 acciones para ganar desde el inicio. Pero hay 0, así que luego de hallar todas las victorias posibles, cuando volvamos a investigar situaciones aún no resueltas, como esta: XV VV Sabemos que es turno del 0, que si pone en 2_1 o 2_2 se llegará a una situación cuya DistanciaDeVictoria es 1, pero para X, para 0 es 1 de la derrota, así que el programa no puede ponerle 2, eso se interpretaría como que a 0 le hacen falta 2 acciones para ganar, que es segurto que ganará, lo cual no es así. ¿La solución es crear otra variable? ¿que exista DistanciaDeVictoriaDeX y DistanciaDeVictoriaDe0? Hay que tener en cuenta la explosión combinatoria, no conviene crear variables en lo posibñe, además no veo bien cómo eso lo resolvería. A ver, si no llega a una situación cuya DistanciaDeVictoriaDe0 sea 1 (cosa imposible, 0 no puede ganar), nada se anota al respecto. Y cuando la distancia de X es 1, se anota que de 0 es -1, es decir que está a 1 acción de ser derrotado. La distancia ideal es positiva y en 2nda instancia lo más cercana a 0 posible. Bueno... cuando en una búsqueda no se anoten cosas, es decir no se llegue a situaciones resueltas, se comenzaría a anotar las que lleguen a distancias -1, luego a -2, y así, podría ser que se llegue a resolver todas las situaciones. ¿Creen que eso funcionará? ¿no, por qué? ¿Es posible usar sólo una distancia? ¿sí, cómo? ¿Cómo sería un método más rápido y eficiente? Imagino que deduciendo en base a rotar el tablero o considerar simetría, pero creo que debe haber algo como aprender la regla, aprender un código a seguir, no esto de aprender qué hacer en la situación 1, 2, 3... Cuando juegue, sería bueno que siga un código como el que puse al inicio, en vez de "llamar a la función SXVVV" (o sea, cargar los datos de esa situación a ver qué acción conviene en ella), porque cuando sean MUCHAS posibles situaciones, es un disparate hacerlo así, por la explosión ¿no? Imagina un 5 en línea en un tablero de 25x25 con 5 jugadores, por decir algo.
|
|
|
|
|
|
|