Cita de: NEBIRE en 31 Diciembre 2017, 02:13 AM
Simplemente debes tener una estructura (sencilla) donde mantener dicha info, para seguir indagando.
Una imagen para que hagas una idea de como queda y luego la estructura, detrás las explicaciones
Cerco:
.|0 1 2 3 4 5 6
A|X X X 4 X X X
B|X X X 4 X X X
C|X X X 4 X X X
D|2 2 2 @ 1 1 1
E|X X X 3 X X X
F|X X X 3 X X X
G|X X X 3 X X X
Finalmente tendrías una estructura para mantener junto los datos tal que así:Código [Seleccionar]
Estructura DatosDisparo
byte Tocado // indica cuando se toca por vez primera una nave, y luego con cada nuevo 'tocado' aumenta en uno. asi este valor hasta hundirlo.
byte Orientacion // indica a qué lado estamos disparando del cerco.
//byte cX // cordenada 'x' del primer tocado en la nave.
//byte cY // cordenada 'y' del primer tocado en la nave.
//arrayBytes Cerco(7,7) // Array imaginario, operamos sobre un área de 7x7 (dado un tamaño de nave de 4 casillas)
Fin estructura
DatosDisparo dDisparo // instancia de la estructura.
La arroba, representa tu primer disparo con acierto. Tocado se pone a 1, Luego siempre sigues la dirección del reloj, empiezas por donde quieras, yo he puesto 1 al este... si aciertas de nuevo sumas 1 a tocado y se avanza en la orientacion y sentido que lleva. Así si es 1, sigues en 1... pero si falla, continúa en la misma dirección pero en el otro sentido, y el valor de orientación se actualiza como toca...
El orden de 1,2,3 y 4, obedece a facilitar el código... otras maneras son posibles, pr supuesto.
La estrategia es que si el disparo ha tocado un buque (valor 2 en tu caso), por primera vez, se consdiera una zona centrada en dicha posición, del mapa de disparos, centrnado el disparo en dicho array, es decir Cerco(3,3) = 2 // tocado
Y estableces un valor buleano Tocado=1, ahora la posición donde disparar la siguiente vez, va condicionado...
Voy mejor con pseudocódigo, sino con tantos condicionantes es fácil perderse...Código [Seleccionar]
buleano = Funcion SiguienteDisparo(byte resultado, byte x, byte y) //tu llama la función como te dé la gana... o atendiendo a como te reclamen.
Si (resultado = 2) // Tocado
Si (dDisparo.Tocado > 0)
Si (dDisparo.Tocado < 4)
dDisparo.Tocado += 1 // Otra casilla tocada de la nave (o de una nave contigua)
Si (dDisparo.Orientacion = 1) // avanzamos a derecha
x += 1
OSi (dDisparo.Orientacion = 2) // avanzamos hacia izquierda
x -= 1
OSi (dDisparo.Orientacion = 3) // avanzamos hacia abajo
y += 1
OSi (dDisparo.Orientacion = 4) // avanzamos hacia arriba
y -= 1
Fin si
Si no
dDisparo.Tocado = 0
Devolver FALSE
// NOTA2: Si se ha tocado tantas veces como casillas tiene la nave mayor, cabe decir que hay un buque contiguo a éste (o más)...
// no se ha hundido, porque sino, se hubiera recibido un resultado 3.
// Es decir: al menos dos buques tienen casillas en este área y están tocándose
// Luego la suma de 'dDisparo.tocado' ha tocado casillas de al menos dos naves,...
// Resolver este caso, lo dejo a tu esfuerzo y consideración...
Fin si
Sino // aquí hay un buque (lo acabamos de descubrir)... insistiremos hasta hundirlo.
// Reset valores de la estructura.
dDisparo.Tocado = 1
dDisparo.Orientacion = 1
//dDisparo.cX = x
//dDisparo.cY = y
//CopiarParteDelMapaACerco
x += 1 // orientación: 1, avanzamos a derecha, 'y' no cambia.
Fin si
Devolver TRUE
Osi (Resultado = 3) // Hundido, se supone ya restada una nave.
dDisparo.Tocado = 0 // si esta nave está hundida, retiramos la marca para seguir buscando alrededor...
Devolver FALSE
Sino
Si (dDisparo.Tocado > 0) // un disparo previo acertó,
Si (dDisparo.Orientacion < 4) // si no se han agotado todas las posibilidades.
dDisparo.Orientacion += 1 // cambiamos de orientación.
Si (dDisparo.Orientacion = 2) // ---> cambia de sentido en horizontal... hacia izquierda
x -= (dDisparo.Tocado + 1) // 'y' no cambia
OSi (dDisparo.Orientacion = 3) // ---> cambia a vertical abajo
x -= dDisparo.Tocado // vuelve a la cordenada central (de Cerco) en el eje 'x'
y +=1 // y baja una fila
OSi (dDisparo.Orientacion = 4) // ---> cambia de sentido en vertical... hacia arriba...
y -= (dDisparo.Tocado + 1) // 'x' no cambia.
Fin si
Devolver TRUE
Sino
dDisparo.Tocado = 0
Devolver FALSE
// NOTA2: Agotada todas las orientaciones cabe decir que hay un buque contiguo a éste...
// no se ha hundido, porque sino, se hubiera recibido un resultado 3.
// Es decir: al menos dos buques tienen casillas en este área y están tocándose
// Luego la suma de 'dDisparo.tocado' ha tocado casillas de al menos dos naves,...
// Resolver este caso, lo dejo a tu esfuerzo y consideración...
Fin si
Sino
Devolver FALSE
Fin si
Fin si
Fin funcion
Observa que en realidad el array 'cerco', no lo usamos para nada, ni copiamos ni escribimos, ni leemos de él, es una idealización para saber que estamos haciendo y 'no perder el norte'...
Los parámetros 'x' e 'y' son de entrada y salida...
La función devuelve un buleano, para indicar si el próximo disparo debe dirigirse el disparo a los valores x,y devueltos si la función devuelve TRUE, si devuelve false, se debe elegir otra posición... pero devlviendo TRUE, 'x' e 'y', contiene la dirección donde disparar para cercar al buque tocado hasta hundirlo.
- Una vez que se ha tocado, un barco, sigue la estrategia de recorrer en la misma orientación hasta el fallo, en cuyo caso se recorre en el sentido opuesto, acabado el otro sentido, cambia la orientación a vertical y finalmente invierte el sentido de este... ese es el orden de recorrido.
- Nota que caben posibilidades de que haya 2 o más naves que estén contiguas (paralelas), por lo que puede darse falso positivo (tocar dos naves distintas y no dos casillas de la misma nave (incluso 3, 4 naves...), con dos disparos seguidos). He dejado un comentario de //NOTA1 y //NOTA2, donde esto sucede... y aún puede darse un caso de NOTA3...
// NOTA2: al caso dDisparo.Tocado contiene el valor de cuantas naves han sido tocadas y la orientación actual descubre que están en una orientación atravesada.
//NOTA1: También cabe la posibilidad de una nave pongamos vertical (que tocamos con 'dDisparo.Tocado = 1, el centro del 'Cerco'), incluso alguna más también en vertical y luego otra en horizontal a continuación de áquella última tocada, luego llegamos a 4 tocados, pero no hay ninguna nave hundida (hubiéramos recibido un valor de resultado = 3)... luego hay que continuar la dirección más allá de las medidas de 'Cerco', para hundirlo y tras hundirlo regresar sus casillas hacia atrás, y continuar en otra dirección...
Ambos casos, los dejo en el limbo, a tu esfuerzo... es más de lo mismo, puede resolverse descontando los Tocados de la nave hundida y cambiar en la otra dirección vertical desde la posición previa (descontada en dicho eje de la nave hundida) //NOTA3: Todavía existe el caso de que dos naves estén colocadas 'a testa' una de otra, también dejo a tu esfuerzo incluso donde va este caso dentro del árbol de decisiones....
Si quieres evitar esos casos molestos, basta que añadas una regla al juego: dos naves no pueden posicionarse tocándose, siempre debe haber al menos un casilla de espacio entre ellas (con la excusa de que eso impediría el movimiento en un caso real ). Esto elimina todas esa complicaciones...
Cerco:
.|0 1 2 3 4 5 6
A|X X X 4 X X X
B|X X X 4 X X X
C|X X X 4 X X X
D|2 2 2 @ 1 1 1
E|X X X 3 X X X
F|X X X 3 X X X
G|X X X 3 X X X
Nota que habiendo tocado una casilla y considerando a dicha casilla como el centro de un cerco, basta tocar otras 3, para hundir el barco más grande que haya (supuesto el caso de naves de tamaño 4 como máximo), sin embargo, el cerco aunque sea imaginario de 4 casillas en una dimensión en realidad queda determinado por el valor de Tocado... es decir mientras se toque en una dirección se avanza en ella, así podría a llegar a 5, 6, 10... con lo que en realidad no importa el tamaño de las naves. Pero es preciso, hacer siempre una idealización razonada y cuando procede un dibujo...
Para hacer el pseudocódigo independiente del tamaño de las naves habría que tener una variable donde está línea, para el valor 4, con el valor propio de casillas que tenga la nave de mayor tamaño.
Si (dDisparo.Tocado < 4)
Como el pseudocódigo está escrito al aire (sobre la marcha), es posible que se haya escapado algún gazapo...
-----------------------
Todo lo previo, respecto de tu interés, y ahora respecto de otras observaciones que pareces obviar...
- El valor de: "casilla repetida = 0", es absurdo... es obligado llevar dos mapas (por flota), aunque en realidad el segundo mapa de una flota, es el primero de la otra, luego pueden compartirse parcialmente.
Me explico: ¿quién en su sano juicio tira dos 'bombas' al mismo sitio, si ya fue agua, o tocado???. Y se sabe que fue agua o tocado, porque... en efecto llevas un mapa de donde has tirado previamente, no llevar un mapa es carecer de memoria, luego una IA, no tiene sentido donde no hay ni persistencia de la memoria. La IA es precisamente operar en consideración de la memoria, de la 'experiencia', mediante la retroalimentación... si no hay memoria, no hay nada que retroalimentar... por eso mantener una estructura de lo que ha sucedido previamente es la IA mínima que se puede prestar...
Así los dos mapas son: Donde yo tiro a la flota enemiga y 2º, donde el enemigo me tira a mi. es inverso para el caso del enemigo, excepto en que en el mapa propio, están todas las naves y 'el enemigo solo ve', lo que ha tocado o hundido, es decir... si tenemos un valor de nave intacta en el mapa, para el enemigo, se le reprseenta como agua... y si no, toca mantener dos mapas independientes por cada flota.
Es abusrdo hablar de IA, si luego uno va a volver a tirar a casillas a las que ya ha tirado. Hay un caso donde esto es posible, y es en una versión más compleja del juego, donde en cada turno, el que tira mueve una de sus naves (la que quiera) una casilla en uno de los dos sentidos de la orientación que tiene, por lo que en efecto, podrá dispararse a casillas ya disparadas, porque las flotas 'se mueven', pero es una regla que hace el juego mucho más complejo...
---------------
Siento todo el párrafo del mensaje anterior, que al parecer te resulta innecesario, porque al hacer preguntas, los usuarios a menudo os dejais en el tintero detalles importantes... como "ya tengo listo todo lo demás, me falta solo esto". ...pero bueno, a alguien podrá servirle.
Primero decir que muchas gracias por toda su colaboración. Hoy mismo me pongo con la implementación de dicha logica. He hechado partidas sobre papel, y a la hora de decidir el siguiente disparo he anotado paso a paso que es lo que hacía, como recorria las direcciones, como cambio el sentido, etc. Ahora sabiendo más o menos que tipo de estructura de datos seguir para guardar dicha información, me pongo a la implementación del codigo.
También aclarar, que el tema de los barcos contiguos no se observa en mi proyecto. A la hora de colcoarlos si o si debe de haber una casilla agua de separación.
El tema del valor 0 casilla repetida o -1 error. Cuando dispara la máquina no se contemplan, por lo que nunca se darán esas dos condiciones. Pero como uso el mismo procedimiento para los disparos del jugador, puede ser que hagas un "missclick" y teclees una coordenada ya repetida, desgraciadamente obligandote a perder turno y a sumar un intentos++; a los disparos necesarios para ganar.
Cada jugador (usuario y maquina) tiene sus dos mapas, mapas de barcos (suyos) y tablero de disparos del enemigo.
Yo disparo en el tablero de disparos y actualizo el resultado en el tablero de barcos del enemigo.
El procedimiento que yo tengo realizado para decidir el disparo es el siguiente:
Con ésto lo que consigo es, si es tocado disparo a las casillas vecinas. El problema se encuentra cuando en la casilla adyacente no hay un barco, cuando vuelve a entrar en el procedimiento, si no ha sido tocado, me dispara al azar nuevamente, en lugar de recorrer en busca de su orientación. Ahi es donde creo que deberia añadir si ha sido primero tocado ir en busca de una dirección por cada disparo realizado. Cómo al hundir un barco se rodea todo de Agua tocada "." de ésta forma puedo saber cuando un barco ha sido hundido y en el siguiente disparo, realizarlo aleatoriamente.
EDIT: Añadir también que, hay que tener en cuenta si el barco se encuentra en los laterales del talbero (columna 1 o 9) y (fila A o G). Entonces, en mi procedimiento, en lugar de generar valores aleatorios en las direcciones arriba abajo izq derecha, dependiendo de la situacion en la que se encuentre, se exactamente dónde disparar.