elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Introducción a Git (Primera Parte)


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación General
| | |-+  ¿Hacer fuerza bruta para ganar en juego similar a Mastermind?
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: ¿Hacer fuerza bruta para ganar en juego similar a Mastermind?  (Leído 1,403 veces)
Tachikomaia


Desconectado Desconectado

Mensajes: 440



Ver Perfil
¿Hacer fuerza bruta para ganar en juego similar a Mastermind?
« en: 18 Abril 2019, 10:21 am »

Este post está dividido en 3 partes.
La 1era es esta aclaración,
la 2nda es la clave y la 3era es info extra a quien requiera o le interese.
Además en café puse lo menos importante.


--------------------------------------------------------------------------------------------

El juego es así:
1- Se genera un número al azar de 3 cifras usando números enteros del 0 al 5, sin repetir. Yo no sé el número que se genera (a menos que haga trampa, pero no quiero).
2- Yo elijo un número de dichas condiciones (excepto el ser por azar).
3- El juego informa cuántos números bien colocados (considerando el número elegido por la computadora) puse, y cuántos números están mal colocados.
El paso 2 y 3 se repiten hasta digamos decir 6 códigos fallidos o hasta que yo acierte el número elegido por la compu.

Cuando digo hacer fuerza bruta me refiero a hacer un "programa" (lo digo entre comillas porque más de uno dice que yo no programo, que hago otra cosa) que encuentre las mejores respuestas o algo que luego un humano pueda usar para ganar rápido en el juego, digamos procesos a seguir. Y que además dicho "programa" sea lo más fácil posible de hacer sin importar lo poco eficiente que sea. Pero que además esté hecho en un lenguaje "normal", no en lenguaje máquina.

Bueno, yo hice algunas cosas así, pero esto la verdad me sobrepasa por el tema de las pistas creo (entiendo que es muy vago decirlo así, pero no lo entiendo más que eso), por ahora no sé hacerlo, por eso hago este tema para pedir ayuda.

Lo que hice hace años fue algo así:
Hay un objeto en el punto 0 del eje de las X.
El objetivo es que llegue al 10 en la menor cantidad de movimientos posibles teniendo estos 2:
1: Moverse +1 a la derecha (hacia el 10).
2: Moverse -1 a la izquierda.
Es obvio que conviene usar la acción 1 10 veces, pero mi idea era que el programa lo descubriera sin que yo le diera pistas como "te estás acercando", no me gusta hacer eso porque uno no siempre sabe cuando una acción es buena o mala, prefiero evaluar "desde el final". Mi programa realizaba una acción, si llegaba a una situación nueva generaba un archivo cuyo nombre la describía y el contenido marcaba cual fue la anterior y qué hizo en ella, y se generaba otro archivo que marcaba que esa situación aún no había sido analizada. Tras probar todas las acciones en una situación (reseteándola luego de cada una), se hacía lo mismo pero desde una de esas situaciones no analizadas. El resultado básicamente son archivos así:
1.txt que tiene X=0; Action=1
2.txt que tiene X=1; Action=1
3.txt que tiene X=2; Action=1
etc, hasta
10.txt que tiene X=9; Action=1
Y por supuesto los otros archivos de situaciones por acciones estúpidas como -1.txt por haberse movido hacia atrás.
Cuando el programa llegaba a colocar el objeto en el punto 10, decía la acción que realizó, cargaba la situación anterior, decía la acción que se realizó en ella, y así sucesivamente hasta llegar a la situación inicial.

Eso me parece que es aplicable a "todo":
Hacer un jaque mate, hallar la cura a una enfermedad o a un país mal gobernado, etc.
Si no se puede es porque hay variables desconocidas por ejemplo, pero quizá el mismo método con los ajustes necesarios las puede averiguar, al fin y al cabo es un método para averiguar cosas.
En un foro me plantearon un problema del que sin embargo no podía: Hacer la serie de fibonacci con alguna condición que no creo venga al caso. Quizá no pude porque no lo apliqué bien, pero tampoco creo que venga mucho al caso, aunque por decir algo...:
Si se genera una serie a comprobar si sirve o no, necesito la serie verdadera para hacer esa comprobación. Si no sé cómo es ("variable desonocida") no puedo hacer la comprobación, y si sé cómo es y la voy a usar para hacer comprobaciones entonces qué sentido tiene buscarla.
Es un caso distinto de lo que yo plantee, en que se puede saber qué se quiere pero no cómo conseguirlo, saber el final de una serie pero no la serie en sí que además es irrelevante (pueden ser cualquier números, simplemente dependen de las acciones/situaciones posibles). Sólo porque un número esté bien ya tengo "la serie" (los movimientos para llegar a dicho número), pero en el caso de la serie de fibonacci es necesario que estén bien todos sus números y si no tengo la serie (o no la genero a propósito) no puedo. En fin, no tengo mucha idea de eso (quizá hay una ecuación matemática para saber si un número está en la serie, aunque no se tenga la serie, pero ni idea tampoco, no sé hallar condiciones o efectos aún, sólo hallé series de números basados en el último principalmente).

Y aquí estoy de nuevo con un problema que ese método supuestamente "todo terreno" no sé cómo puede solucionar esto, y si es que no puede, por qué no.

¿Cual sería el método más parecido al mío, que solucionaría el problema?

¿Cómo deben ser los archivos?
Se me ocurre por ejemplo esto:
012,00_345,03_453,03_534.txt
El nombre contiene las acciones realizadas y las pistas recibidas (el contenido en sí del archivo no se me ocurre). ¿pero cómo se generaría eso?

¿Cual es la situación inicial, debo mencionar el número que yo en teoría no conozco? El resultado sería este:
Para el 012 conviene usar 012
Para el 013 conviene usar 013
Inútil.

Necesito que se generen los procesos y contar la cantidad de pasos que requieren en cada caso, o al menos la máxima cantidad de pasos que requiere en un caso.

¿Esos procesos no se pueden describir mediante una línea?

Pero a ver, por ejemplo me serviría que exista un archivo
012,01_304,01_135,02_253,01_541.txt
y otro:
012,01_304,02etc.txt
Suponiendo que iniciar con 012 y luego 304 (si la pista es 01) fuese uno de los procesos que mejor funciona en general. O sea, no necesito que un proceso con todas sus variaciones esté en 1 línea, pueden ser muchas líneas/archivos indicando las diferentes variaciones según las pistas.

Luego de algún modo buscaría los archivos más cortos, de hecho podría ponerles LX al inicio y sustituir X por la cantidad de números que tienen luego.
Entonces si jugando al juego pongo 012 y obtengo 11 busco el proceso 012,11, veo qué dice después, y así sucesivamente.


Algo que se me ocurrió es generar un proceso, que puede ser 012,013,014etc, y contar en todos los casos cuánto tardaría en averiguarlos. Es decir, ignora las pistas. ¿Será esa la respuesta? No creo, sin pistas cualquier proceso puede tardar mucho.

¿Pistas en los nombres de archivos y acciones dentro? No sabría bien cómo contar qué tarda más. Podría eliminar los archivos más largos y ver cual proceso se repite más ¿?
Creo que esto no serviría, iguales pistas pueden obtenerse por distintas situaciones, los archivos serían sustituidos por otros.

Af. dado un número N el proceso P1 tarda 1 paso.
No, tampoco, porque cuando digo proceso me refiero a una línea y si me basara sólo en los que tardan menos obtendría los que por suerte aciertan de una.

En fin, como ven le doy vueltas pero no me sale.


--------------------------------------------------------------------------------------------

MasterMind:
https://es.wikipedia.org/wiki/Mastermind
Más info aquí:
https://en.wikipedia.org/wiki/Mastermind_(board_game)#Algorithms

Ejemplo del juego que dije:
1- Se genera el número 210
2.1- Digo 012
3.1- Me dice 1-2, lo cual significa que hay 1 número bien colocado (el 1, pero yo eso en realidad no puedo saberlo en este punto porque en el caso real no sé el número generado) y 2 mal colocados.
2.2- Debido a que en este caso habría tenido bastante suerte porque acerté cuales números son los presentes, sólo me queda averiguar el orden correcto. Sé que el número es alguno de estos 3: 021, 210 o 102. A partir de ahora es cuestión de probar esos 3, no sé si hay un orden de pruebas mejor que otro.

Búsqueda de modos de ganar antes de hacer este tema:
Quería tener un diagrama de flujo o algo similar:

Dado que habría muchas flechas en cada caso, pensé en hacer algo así:
012__0-0__345__0-3__453__0-3__534
_______________1-2__354__0-3__435__0-3__543
_____0-1

Por otro lado, pensando una explicación para un ejemplo en que me equivoqué, se me ocurrió un método que no me interesa usar en programación pero es interesante:
En cada columna de la siguiente "tabla" están los posibles números de cada cifra:
000
111
222
333
444
555
La mayoría de las posibles pistas nos permiten tachar algunos números.

El ejemplo siempre será 012.

0-1 o 0-2:
_00
1_1
22_
333
444
555

0-3:
_00
1_1
22_
___
___
___

1-0 o 2-0:
0__
_1_
__2
333
444
555

0-0:
___
___
___
333
444
555

1-2:
000
111
222
___
___
___

1-1:
Creo que esta no.


En línea

Tachikomaia


Desconectado Desconectado

Mensajes: 440



Ver Perfil
Re: ¿Hacer fuerza bruta para ganar en juego similar a Mastermind?
« Respuesta #1 en: 24 Abril 2019, 19:10 pm »

La respuesta parece estar relacionada con lo que llaman "árboles de decisión".
https://es.wikipedia.org/wiki/%C3%81rbol_de_decisi%C3%B3n#Ejemplo
O algo similar.

Intento aplicarlo a una versión simplificada, en que el número sólo tiene 2 caracteres y pueden ser del 0 al 3.

El 1er número con el que se intenta acertar puede ser cualquiera (si el juego admitiese que contenga números repetidos entonces sí la eficiencia puede que varíe y por tanto este número importaría). Digamos 01.

A partir de ahí hay 4 posibles "ramas", según las 4 posibles pistas que se reciba:
Código:
   /--> 0-0
   /--> 0-1
01
   \--> 0-2
    \--> 1-0
También existe la posibilidad de 2-0 pero en tal caso se entiende que se llegó al resultado así que no es necesario ver qué se hace después, pues si este método es aplicado por una persona la respuesta es nada, ya ganó.

Ahora a partir de cada posible pista ponemos otro número. Por ejemplo:
Código:
   /--> 0-0 --> 02
   /--> 0-1 --> 02
01
   \--> 0-2 --> 02
    \--> 1-0 --> 02
Y el proceso se repite 1 vez más, porque según he visto en este caso simplificado hay un método que adivina el num en 3 "tiros".

Una vez hecho eso, se probaría dicho método para cada posible número y se contaría cuánto tardó en hallar los números, si es que los halló todos.

Luego, el método se variaría y se repetiría el paso anterior.

El programa terminaría cuando ya no sea posible variar el método, en cuyo caso diría cual fue el que halló los números en menos "tiros".

Esto daría el método que tiene el mejor promedio, es decir, si uds leen por ahí info de esto verán que se habla de métodos que no llegan a tardar X tiros, y otros que sí pero en promedio tardan menos. No sé realmente qué me sirve (en el modo difícil puede que el "mínimo máximo", porque si es posible saber que viene un caso de los que tardará podría cancelar el juego y de ese modo ganar más rápido (es un juego para ganar fichas), pero esto me parece poco probable (no creo que sea posible en general ganar tan rápido como para que convenga abandonar ciertas apuestas)), pero me parece que es eso, el mínimo promedio.


Bueno, el problema ahora es implementar eso.

El 1er número del método sería N1.
N1="01";
Nótese el problema de eso. No puedo poner 01. Tiene que ser "01". Pero si es texto es más difícil sustituir caracteres por otros (si fuese posible decir 01+1 y que quede 02, buenísimo, pero como es texto y no números hay que usar ifs y cosas...).
Otra opción sería poner 12 y que se interprete que el 0 representa al 1, el 1 al 2. etc. Y sí, voy a hacerlo así, porque es mucho más fácil aunque requiera una traducción humana (o más código al final).
Entonces N1=12

Luego vienen los otros números a los que no sé cómo llamarles porque debo referirme a ellos más adelante y no sé cual es la mejor forma. No se olvide que esto es una versión simplificada. Entiendo que no me esté explicando bien pero es que no sé, verán más adelante el problema.

Supongamos que les llamo así:
Código:
   /--> 0-0 --> N2 -> (N3, N4, N5, N6)
   /--> 0-1 --> N7 -> (N8, N9, N10, N11)
N1
   \--> 0-2 --> N12 -> (N13, N14, N15, N16)
    \--> 1-0 --> N17 -> (N18, N19, N20, N21)

Entiéndase que lo que está entre paréntesis son los números de las 4 posibles ramas que salen de esos puntos, no me pidan que dibuje las ramas...

Y supongamos que todas esas variables son 13.

Probamos cuánto tarda en adivinar el número 34 (X). Lo principal es algo así:
Código:
Si el 1er número de N1 es el 1er número de X
   Si el 2ndo número de N1 es el 2ndo número de X
      Acertó.
   sino
      Pista: 1-0
sino si el 1er número de N1 es el 2ndo número de X
   Si el 2ndo número de N1 es el 1er número de X
      Pista: 0-2
   sino
      Pista: 0-1
sino si el 2ndo número de N1 es el 1er número de X
   Pista: 0-1
sino
   Pista 0-0
Ahora dependiendo de qué pista sea chequearemos lo mismo pero cambiando N1 por el número que sea. Acá es donde viene lo difícil, hay que hacer referencia a ese número, yo no quiero hacer tantos ifs para eso. Además, como esto es una versión simplificada sólo hay que hacerlo 1 o 2 veces, pero en la versión normal serían digamos 7 tiros a decir y en la versión difícil unos 15. No tengo idea de cuántos, pero son bastantes.


Probablemente no se entienda lo que estoy diciendo pero bueno ¿alguna idea hasta ahí? ¿hay algo que me pueda simplificar la tarea? ¿quizá arrays? ¿nombrar las variables de otro modo?

----------------------------------------------------------------------------------------

Edit:
Olvidé unas cosas porque debía irme.

Hay basicamente 2 problemas.
1- Cuando se quiere ver cómo sigue el método, cual es la variable luego de la pista.
2- Cuando se quiere variar el método, qué variable se variará, y en caso de llegar al límite cual es la siguiente, etc.

Con los nombres que les puse, el 2 está solucionado. Porque, imaginen que en 7285, 7=V1, 2=V2, etc.
O sea, cada posición está marcada por una variable. El número se podría variar haciendo V5+1, cuando llegue a 9 pasa a 0 y se hace V4+1 y así sucesivamente. Bueno, el método es parecido, está hecho de unos números representados con variables, variamos desde la 21 hasta la 1.
Pero el 1 no sé cómo arreglarlo.

Otro modo de nombrar las variables sería algo así:
Código:
   /--> N1 --> (N11, N12, N13, N14)
   /--> N2 --> (N21, N22, N23, N24)
N
etc.
Entonces si obtengo la pista 1, para ver cual número probar luego busco la variable cuyo nombre es igual a la anterior pero agregando 1.
Esto resuelve el problema 2 pero el 1 se complica. Aún así me parece suficientemente viable... Lo probaré.


« Última modificación: 25 Abril 2019, 19:14 pm por Tachikomaia » En línea

srWhiteSkull


Desconectado Desconectado

Mensajes: 437



Ver Perfil WWW
Re: ¿Hacer fuerza bruta para ganar en juego similar a Mastermind?
« Respuesta #2 en: 27 Abril 2019, 03:12 am »

Para ganar en juegos de tablero o en juegos donde las posibles jugadas abran ramas de múltiples decisiones se usan sistemas de redes neuronales. Como casi te aproximaste, hay que crear árboles con millones de combinaciones para que el algoritmo encuentre en un tablero dinámico, que constantemente cambia, las siguientes jugadas que le lleven a la victoria. Éstos sistemas suponen muchísimo consumo de recursos. Actualmente existen muchas IAs basadas en estos sistemas, con machine learning incluido(lo que permite ser entrenadas para ganar a cualquier juego de tablero), que son prácticamente imbatibles.

Yo que tú primero aprendería a programar algo menos ambicioso como un algoritmo que use ese sistema (árboles n-arios) para ganar un cuatro en línea contra un humano.





« Última modificación: 27 Abril 2019, 03:14 am por srWhiteSkull » En línea

Tachikomaia


Desconectado Desconectado

Mensajes: 440



Ver Perfil
Re: ¿Hacer fuerza bruta para ganar en juego similar a Mastermind?
« Respuesta #3 en: 28 Abril 2019, 18:59 pm »

Para ganar en juegos de tablero o en juegos donde las posibles jugadas abran ramas de múltiples decisiones se usan sistemas de redes neuronales.
Lo que había visto de eso eran unos árboles en los que cada punto o neurona multiplicaba el valor por un número que se iba ajustando, y me pareció algo confuso y menos eficiente u ordenado que una fuerza bruta. Además, como está tan de moda, qué sé yo, prefiero ir por otro lado.

Citar
Yo que tú primero aprendería a programar algo menos ambicioso
Es que no pensé que lo fuera tanto. De momento lo que me jode como comenté en el 2ndo post es que no sé cómo nombrar las variables como para poder llamarlas o modificarlas sin problema.
Algo que quizá me serviría es poder convertir conteos de 10 números (0, 1, 2, 3, 4... 10, 11...) a 4 (1, 2, 3, 4, 12) pero salteando repeticiones (olvidé eso) uf...
No hice aún lo que dije que haría, veré.

Citar
un algoritmo que use ese sistema (árboles n-arios) para ganar un cuatro en línea contra un humano.
Con mi antiguo sistema no sé cómo hacerlo debido a que hay un rival. Capaz que no es tan difícil pero nunca probé y como digo estoy muy olvidado de aquello y desganado de volver a usarlo por ahora.
Para lo que me pides y cómo lo pides, se me ocurren 2 posibles formas:
Los casilleros del tablero son numerados de esta forma:
1, 2, 3, 4
5, 6, 7, 8
etc

Y:
0 significa que hay un 0
1 significa que está vacío
2 significa que hay cruz

Método A:
Código:
2111111111111111
   2011111111111111
   2101111111111111
   etc
1211111111111111
etc
Eso habría que generarlo con código. Son todos los posibles tableros en el orden conque pueden ocurrir, si empieza la X.
Desventaja: Es posible producir situaciones repetidas, en que sólo cambia el cómo se llega a ella. Supongo que no es mucho problema si hay forma de dejar marcado que sí se llegó a ella y ya fue revisada.
Se parece mucho a mi antiguo método.

Método B:
Código:
        /-2-Win
       /-1
      /-0
  /-2
2--1
 \-0

1

0
Obviamente tampoco está completo. Eso muestra, en cada "columna", los posibles estados de un casillero. En la izquierda, el casillero 1, más a la derecha el 2, etc.
Ventajas: Más fácil de hacer.
Desventajas: Se generan situaciones imposibles.
Si puedes evitar la desventaja, bárbaro, pero veo otra...: No sé cómo esto puede servir para que el programa aprenda, es decir, le estás dando las soluciones, eso no es que aprenda experimentando, es que copie...


El video no me pareció muy instructivo que digamos... Habla de muchas cosas complejas que no explica y que no sé si en última instancia sirven (quizá son sólo optimizadores, pero no son algo necesario; yo por ahora sólo necesito lo necesario).

¿Qué opinas de lo que había dicho? ¿no es la fuerza bruta un método que puede resolver cualquier problema? ¿por qué entonces parece que no puedo aplicarlo aquí? ¿es que no logro ingeniarme o que el método no sirve aquí? ¿qué propiedades así de determinantes hay en los problemas? En el sentido de qué cosas en ellos hacen que la fuerza bruta u otros métodos conocidos se vuelvan inaplicables. El video habla por ejemplo de variables desconocidas, pero me gustaría ver una clasificación más clara, o algo más explicado.
¿Y cómo hago referencia a variables cuando...? Lo planteado en el 2ndo post.

Mira, puede que no sepa hacer siquiera un 2 en línea (tablero de 2x2 imagino), pero más cierto me parece que no tengo ganas de intentarlo, pues siento que me desviaría mucho. Lo que haré es intentar el juego que propose pero con 2 números y sólo 2 posibles números, y luego 3. Luego, recién los 4, y luego sí 3 números y 6 posibles. A ver qué sale.
En línea

srWhiteSkull


Desconectado Desconectado

Mensajes: 437



Ver Perfil WWW
Re: ¿Hacer fuerza bruta para ganar en juego similar a Mastermind?
« Respuesta #4 en: 28 Abril 2019, 20:00 pm »

El árbol lo podrías llamar Jugada o Juego, y cada nodo llamarlo Movimiento, cada Movimiento indica un estado (posición celda ocupada) enlaza al siguiente Movimiento.

Habría un algoritmo recursivo que comprueba el tablero y mira las celdas desocupadas y las celdas ocupadas por el contrincante. Si hay amenaza ocupa la celda desocupada que implica peligro y si no, ocupa una celda desocupada que favorezca la victoria. Cada movimiento conlleva la creación de un nodo o en caso de no poder llevar a cabo el objetivo de crear una línea retrocede a un nodo que si pueda hacerlo.

La explicación es aparentemente sencilla pero requieres de un buen conocimiento de programación ¿lo tienes?  :rolleyes:
En línea

tincopasan


Desconectado Desconectado

Mensajes: 1.281

No es lo mismo conocer el camino que recorrerlo.


Ver Perfil
Re: ¿Hacer fuerza bruta para ganar en juego similar a Mastermind?
« Respuesta #5 en: 28 Abril 2019, 20:05 pm »

partamos de la base de que el el concepto fuerza bruta está errado, que hacerlo, sería probar cada combinación hasta encontrar la correcta.
En línea

Tachikomaia


Desconectado Desconectado

Mensajes: 440



Ver Perfil
Re: ¿Hacer fuerza bruta para ganar en juego similar a Mastermind?
« Respuesta #6 en: 28 Abril 2019, 21:34 pm »

WS:
Me pones en un lío, porque mira:
Código:
Si sé hacerlo,
   y te digo que sí,
      creo que desmostrártelo me tomaría mucho tiempo/esfuerzo que no tengo ganas de perder/hacer, por lo tanto no me creerías y me haría más mal que bien decirte que sí. Y a la conversación supongo que igual. También podría decirte que sí y que si no me crees no es mi problema, pero creo que estaríamos más o menos en la misma, o peor. O es un riesgo que no quiero correr.
   sino si te digo que no,
      me siento mal porque yo es como si creyera en el karma, lo cual en este sentido, me causaría perder la habilidad de hacer algo que sí sé.
si no sé hacerlo
   y te digo que no sé,
      no hay problema.
   sino si te digo que sí
      sería un imbécil
Así que, o lo sé y no te daré pruebas, o no lo sé. Quizá soy demasiado soberbio como para admitir que no lo sé. Lo dejo a tu criterio.

Pero antes de intentar un árbol que se cree sólo, intentaría hacerlo manualmente. Precisamente eso haré. Además, como te dije, hacer referencia a los nodos me resulta muy complicado. Si por ejemplo lo hago así:
Código:
   /--M11
  M1-M12
 /
M
Entonces para volver al nodo anterior simplemente llamo a una variable que tenga un número menos. Si fuesen más de 10 nodos (posibles movimientos a partir de una situación) en un caso se me complica, pero (se me acaba de ocurrir) podría llamarles M01 y sé que siempre tengo que borrar 2 números por cada nodos a los que vuelva. Lo que me complicaría de ese modo, creo, es la creación del árbol. No quisiera hacerlo manualmente.
Pero yo no lo quiero hacer de ese modo...
¿Vos me planteas representar en 1 árbol todas las posibles situaciones del juego? Entonces yo no tengo problema con las referencias.
Pero yo en el juego que te dije quiero que los posibles caminos representen las pistas, mientras que el contenido de los nodos sea variable. Y eso es lo que me resulta difícil. Supongamos que varío el M44. Cuando ya no quedan más opciones, variaré el M43 y el M44. Así sucesivamente, hasta el 41. Luego tengo que bajar al 34. Eso es lo que me complica, esos saltos que tengo que dar. No le veo mucho sentido a poner ifs indicando esos saltos. Si no me entendés esperá algunos días a que haga el code en modo super simplificado. Estoy más enganchado con el juego 2d que con esto, por eso en parte tardo.
Con mi método creo que el árbol sería más pequeño, no representa todo en 1 imagen, y aún así encuentra la solución.


tincopasan:
Es lo que quiero, si es posible que eso funcione. En cuanto al nombre me baso en esto:
https://es.wikipedia.org/wiki/B%C3%BAsqueda_de_fuerza_bruta
"consiste en enumerar sistemáticamente todos los posibles candidatos para la solución de un problema, con el fin de chequear si dicho candidato satisface la solución al mismo."

"es sencilla de implementar y, siempre que exista, encuentra una solución."

¿Qué es lo que está ocurriendo entonces? ¿el jueguito en cuestión es tan complicado que hasta este método "sencillo de implementar" no es tal?
En línea

Tachikomaia


Desconectado Desconectado

Mensajes: 440



Ver Perfil
Re: ¿Hacer fuerza bruta para ganar en juego similar a Mastermind?
« Respuesta #7 en: 29 Abril 2019, 07:27 am »

WS:
Acabo de darme cuenta que la respuesta es no. Porque como dije en el 1er post, y lo olvidé, muchos me han dicho que yo no sé programar o programación y entonces ya ni lo discuto.

De momento tengo esto:
Código:
Escena 1
   actions for fotograma 1
      MejorMetodo = "¿?";
      MMIntentosRequeridos = 10;
      MaxIntentosporSecreto = 3;
      // Nodos.
      // El nombre describe la situación.
      // El contenido es sustituido por V(X).
      N = 1;
      N00 = 1;
      N01 = 1;
      N02 = 1;
      N10 = 1;
      N0000 = 1;
      N0001 = 1;
      N0002 = 1;
      N0010 = 1;
      N0100 = 1;
      N0101 = 1;
      N0102 = 1;
      N0110 = 1;
      N0200 = 1;
      N0201 = 1;
      N0202 = 1;
      N0210 = 1;
      N1000 = 1;
      N1001 = 1;
      N1002 = 1;
      N1010 = 1;
      // Valores. También usados por NúmeroSecreto.
      V1 = 12;
      V2 = 13;
      V3 = 21;
      V4 = 23;
      V5 = 31;
      V6 = 32;
   actions for fotograma 2
      NumeroSecreto = 1;
      Intentos = 0;
      MetodoProbandose = N+""+N00+N01+N02+N10+N0000+N0001+N0002+N0010+N0100+N0101+N0102+N0110+N0200+N0201+N0202+N0210+N1000+N1001+N1002+N1010;
   actions for fotograma 3
      Chequear = "N";
      ChequearTraducido = eval("V"+eval(Chequear));
      IntentosEnesteSecreto = 0;
      NumeroSecretoTraducido = eval("V"+NumeroSecreto);
      trace ("El número secreto es "+NumeroSecretoTraducido);
   actions for fotograma 4
      IntentosEnesteSecreto = IntentosEnesteSecreto+1;
      trace (MetodoProbandose+" probó "+ChequearTraducido);
      if (NumeroSecretoTraducido == ChequearTraducido) {
         // Secreto adivinado.
         trace (MetodoProbandose+" adivinó "+NumeroSecretoTraducido);
         Intentos = Intentos+IntentosEnesteSecreto;
         if (NumeroSecreto<6) {
            // Probar el método con otro secreto.
            NumeroSecreto = NumeroSecreto+1;
            gotoAndPlay (3);
         } else {
            // El método adivinó todo secreto dentro del plazo.
            if (Intentos<MMIntentosRequeridos) {
               // El método es el mejor por ahora, guardarlo.
               MMIntentosRequeridos = Intentos;
               MejorMetodo = MetodoProbandose;
               trace ("El mejor método por ahora es "+MejorMetodo);
            }
            // Modificar método.
            gotoAndPlay (6);
         }
      } else if (NumeroSecretoTraducido.charAt(0) == ChequearTraducido.charAt(0)) {
         Chequear = Chequear+10;
      } else if (NumeroSecretoTraducido.charAt(0) == ChequearTraducido.charAt(1)) {
         if (NumeroSecretoTraducido.charAt(1) == ChequearTraducido.charAt(0)) {
            Chequear = Chequear+0;
         } else {
            Chequear = Chequear+0;
         }
      } else if (NumeroSecretoTraducido.charAt(1) == ChequearTraducido.charAt(0)) {
         Chequear = Chequear+0;
      } else {
         Chequear = Chequear+0;
      }
   actions for fotograma 5
      if (IntentosEnesteSecreto<MaxIntentosporSecreto) {
         // Probar siguientes nodos.
         ChequearTraducido = eval("V"+eval(Chequear));
         gotoAndPlay (4);
      }
      // sino modificar método.
   actions for fotograma 6
      // Modificar método.
      if (N10<6) {
         N10 = N10+1;
      } else {
         N10 = 1;
         if (N02<6) {
            N02 = N02+1;
         } else {
            N02 = 1;
            if (N01<6) {
               N01 = N01+1;
            } else {
               N01 = 1;
               if (N00<6) {
                  N00 = N00+1;
               } else {
>>>           // Hay que seguir poniendo ifs aquí, por ej para N0000.
                  // Ya se probaron todos los métodos. Mostrar el mejor.
                  trace (MejorMetodo);
                  stop ();
               }
            }
         }
      }
   actions for fotograma 7
      gotoAndPlay (2);
Independientemente de lo que falta, no sé si funciona bien. Hallé una solución para las referencias, pero me hice un poco de lío porque hice un código para resolver el problema 2/2 y de repente estaba haciendo el 2/3, sin haber chequeado que el 2/2 lo resolviera bien.
Los ifs creo que pueden mejorarse con algo de eval, pero de momento no lo intenté, otro día será.

En cuanto a las referencias, no sé si se entiende.
Estos son los nombres de los nodos:
Código:
   /--> N00 --> Dependiendo de cual sea la pista: (N0000, N0001, N0002, N0010)
   /--> N01 -->
N
   \--> N02 -->
    \--> N10 -->
Se entiende que no los escribí todos en eso, pero que los nombres están basados en las pistas. Se pueden hacer más cortos, pero para mí sería más complicado.
Estos son los contenidos iniciales:
Código:
   /--> 1 --> (1, 1, 1, 1)
   /--> 1 --> (1, 1, 1, 1)
1
   \--> 1 --> (1, 1, 1, 1)
    \--> 1 --> (1, 1, 1, 1)
Sí, todos 1. Sí, obviamente eso no es la solución, es tonto probar eso, pero así es la fuerza bruta, sólo pensar cómo hacer que la compu resuelva el problema, no pensar más de lo necesario.
Y esos contenidos se interpretan o traducen a valores marcados por variables V.

¿Y por qué rayos eso?
En este momento no sé explicarlo, me perdí (pronto me voy a dormir). Pero háganlo de otra forma si saben, me serviría.

Por otro lado, tengo esta versión anterior, una parte:
Código:
function AumentarSecreto () {
if (NumeroSecreto.charAt(1) < 3) {
NumeroSecreto = Number(NumeroSecreto.charAt(0)+""+(NumeroSecreto.charAt(1)+1));
} else {
NumeroSecreto = Number(NumeroSecreto.charAt(0)+"1");
if (NumeroSecreto.charAt(0) < 3) {
NumeroSecreto = Number((NumeroSecreto.charAt(0)+1)+NumeroSecreto.charAt(1));
} else {
//Imposible aumentar, avisar.
}
// Chequear que no haya repets.
}
function AumentarvalordeNodos () {
if (X < 13) {
X = X+1;
} else if (X == 13) {
X = ;
A pesar de todo, lo que hice me parece más simple que eso. Para variar el número secreto, como no podía hacer+1 porque por ejemplo de 13 pega un salto a 21, tenía que modificar el último caracter, y si llega al límite entonces también el 1ero. Además, de esa forma podía haber números repetidos, cosa que en el juego no sucede.
Lo que hice en la nueva versión fue hacer una lista de los valores y que la variable a aumentar tuviese una referencia a una parte de dicha lista, así que al aumentar el valor de esa referencia pasa al siguiente valor, sin que sea posible que haya números repetidos.

En cuanto a aumentar el valor de los nodos, es igual pero con un montón de ifs porque es uno para cada nodo, pero es algo que tendré que optimizar.
Ahora bien, lo que estaba haciendo en la versión vieja es intentar evitar manejar cambios por caracteres, entonces iba a hacer varios ifs como que si es 11 o 12 se le suma 1, sino si es 13 salta a 21, etc.
La X era un intento de reducir los ifs, porque imagínense, por cada nodo había que poner como 10 ifs.

En fin, creo que lo peor ha pasado. Gracias por el apoyo.
En línea

Tachikomaia


Desconectado Desconectado

Mensajes: 440



Ver Perfil
Re: ¿Hacer fuerza bruta para ganar en juego similar a Mastermind?
« Respuesta #8 en: 30 Abril 2019, 18:13 pm »

Aún no vi que el siguiente código halle alguna solución, por lo que quizá no funciona.
Código:
Escena 1
   actions for fotograma 1
      MejorMetodo = "¿?";
      MMIntentosRequeridos = 100;
      MaxIntentosporSecreto = 3;
      // Nodos.
      // El nombre describe la situación.
      // El contenido es sustituido por V(X).
      N = 1;
      N00 = 1;
      N01 = 1;
      N02 = 1;
      N10 = 1;
      N0000 = 1;
      N0001 = 1;
      N0002 = 1;
      N0010 = 1;
      N0100 = 1;
      N0101 = 1;
      N0102 = 1;
      N0110 = 1;
      N0200 = 1;
      N0201 = 1;
      N0202 = 1;
      N0210 = 1;
      N1000 = 1;
      N1001 = 1;
      N1002 = 1;
      N1010 = 1;
      // Valores. También usados por NúmeroSecreto.
      V1 = 12;
      V2 = 13;
      V3 = 21;
      V4 = 23;
      V5 = 31;
      V6 = 32;
      // Referencias. Usado para variar fácilmente el contenido de los nodos.
      R0 = "N";
      R1 = "N00";
      R2 = "N01";
      R3 = "N02";
      R4 = "N10";
      R5 = "N0000";
      R6 = "N0001";
      R7 = "N0002";
      R8 = "N0010";
      R9 = "N0100";
      R10 = "N0101";
      R11 = "N0102";
      R12 = "N0110";
      R13 = "N0200";
      R14 = "N0201";
      R15 = "N0202";
      R16 = "N0210";
      R17 = "N1000";
      R18 = "N1001";
      R19 = "N1002";
      R20 = "N1010";
   actions for fotograma 2
      NumeroSecreto = 1;
      Intentos = 0;
      MetodoProbandose = N+""+N00+N01+N02+N10+N0000+N0001+N0002+N0010+N0100+N0101+N0102+N0110+N0200+N0201+N0202+N0210+N1000+N1001+N1002+N1010;
   actions for fotograma 3
      Chequear = "N";
      ChequearTraducido = eval("V"+eval(Chequear));
      IntentosEnesteSecreto = 0;
      NumeroSecretoTraducido = eval("V"+NumeroSecreto);
   actions for fotograma 4
      IntentosEnesteSecreto = IntentosEnesteSecreto+1;
      if (NumeroSecretoTraducido == ChequearTraducido) {
         // Secreto adivinado.
         Intentos = Intentos+IntentosEnesteSecreto;
         if (NumeroSecreto<6) {
            // Probar el método con otro secreto.
            NumeroSecreto = NumeroSecreto+1;
            gotoAndPlay (3);
         } else {
            // El método adivinó todo secreto dentro del plazo.
            if (Intentos<MMIntentosRequeridos) {
               // El método es el mejor por ahora, guardarlo.
               MMIntentosRequeridos = Intentos;
               MejorMetodo = MetodoProbandose;
               trace ("El mejor método por ahora es "+MejorMetodo);
            }
            // Modificar método.
            gotoAndPlay (6);
         }
      } else if (NumeroSecretoTraducido.charAt(0) == ChequearTraducido.charAt(0)) {
         Chequear = Chequear+"10";
      } else if (NumeroSecretoTraducido.charAt(0) == ChequearTraducido.charAt(1)) {
         if (NumeroSecretoTraducido.charAt(1) == ChequearTraducido.charAt(0)) {
            Chequear = Chequear+"02";
         } else {
            Chequear = Chequear+"01";
         }
      } else if (NumeroSecretoTraducido.charAt(1) == ChequearTraducido.charAt(0)) {
         Chequear = Chequear+"01";
      } else {
         Chequear = Chequear+"00";
      }
   actions for fotograma 5
      if (IntentosEnesteSecreto<MaxIntentosporSecreto) {
         // Probar siguientes nodos.
         ChequearTraducido = eval("V"+eval(Chequear));
         gotoAndPlay (4);
      }
      // sino modificar método.
   actions for fotograma 6
      // Modificar método.
      Puntero = 0;
   actions for fotograma 7
      if (eval(eval("R"+Puntero))<6) {
         set (eval("R"+Puntero), eval(eval("R"+Puntero))+1);
         gotoAndPlay (2);
      } else {
         if (Puntero<20) {
            set (eval("R"+Puntero), 1);
            Puntero = Puntero+1;
         } else {
            // Ya se probaron todos los métodos. Mostrar el mejor.
            trace (MejorMetodo);
            stop ();
         }
      }
      // Problema en casos más difíciles: Está abierto a dar números con subnúmeros repetidos. No debería.
   actions for fotograma 8
      gotoAndPlay (7);
Vale decir, no obstante, que cuando hice las pruebas, en el frame 4 donde por ejemplo dice +"00" antes era +00 y por lo que acabo de ver, en el modo Explorador de películas se mostraba como +0, por lo que quizá el intérprete, compilador o lo que sea, lo interpretaba así también. Extraño. Pero le puse las comillas por las dudas.
Ayer dejé la compu prendida pero se apagó, y no sé cuánto tarda el código pero es mucho. Creo que debe probar 6^20 métodos variando a su vez los números secretos, o sea (6^20)*6 aunque descartando un método cuando no haya un número, lo cual ocurre en la mayoría de esos nuevos casos.

Definitivamente sería bueno agilizar ese código. ¿Ideas?

En cuanto a cómo funciona, escribí esto:
Citar
El árbol es más o menos así:
Código:
  /-N00 -> N0000, N0001, etc
  /-N01
N
  \-N02
   \-N10
No está completo porque me aburre mucho completarlo, pero eso que ven son los nombres de las variables que marcan qué número se usará al inicio (N), al recibir la pista 0-0 (N00), al recibir la pista 00 y luego de nuevo 00 (N0000), etc.
Por ejemplo N puede ser 12. Inicialmente digamos que todas son 11 (recuerden que el juego sólo admite poner subnúmeros distintos, pero por ahora para no complicarme lo dejo así)..

¿Por qué esos nombres?
Porque así me resulta fácil referirme a la variable que necesito. Si me estoy refiriendo a la variable N y obtengo la pista 00, agrego 00 a lo que ya tenía (en este caso N) y sé que la siguiente variable a usar será N00.

El programa tomará uno de los números secretos posibles y usará el árbol para intentar adivinarlo.
Si lo adivina en 3 tiradas o menos, cambia el número secreto.
Si adivina todos los números así, entonces ese método se guarda si es mejor que los anteriores guardados.

Sea que el método resultó malo o bueno, ahora hay que variarlo, probar otro. Esto es un problema, porque debido al nombre que puse a las variables, no puedo decir "varía la V1, si está al máximo entonces la V2, etc",. hablamos por ejemplo de 0000, luego 0001, luego 0002, luego 0010, no es fácil o rápido indicar cual variar luego de cual.
La solución que hallé, es crear R1, R2, etc, que son referencias a las variables de nombres raros. Así:
R0 = "N"
R1 = "N00"
R2 = "N01"
etc
Entonces si eval(eval(R1)) no está al máximo eso aumenta, sino aumenta evalevalR2, etc.
Pero otra cosa más es necesaria para simplificar. Como los posibles códigos secretos dan saltos de por ejemplo 13 a 21, los he puesto en una lista y las variables N00, etc, no contienen 12 por ejemplo, sino referencias a una posición de la lista, donde sí está el 12, etc.
La variación del número secreto también hace eso.

Esto es el árbol inicial, es decir, el contenido de las variables, no sus nombres.
Código:
  /-1 -> 1, 1, etc
  /-1
1
  \-1
   \-1
Esto es la lista de la que toman valores cuando se necesita ver qué números indican esos nodos:
V1 = 12
V2 = 13
etc (los nombré al inicio del tema).

Bueno, espero que se entienda, pero sino, si conocen otro método y me lo dicen de modo que yo lo pueda entender buenísimo.
« Última modificación: 30 Abril 2019, 18:20 pm por Tachikomaia » En línea

Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines