Autor Tema: Java algoritmo pequeño juego en consola matriz mover caracter cuatro direcciones  (Leído 4753 veces)

CoduJ

  • Sin experiencia
  • *
  • Mensajes: 28
    • Ver Perfil
Buenas, espero que se encuentren bien.

He estado programando un algoritmo para simular un movimiento de un carácter en la consola, este mismo se puede mover en 4 direcciones, me gustaría saber su opinión y de que otras formas se les hubiera ocurrido hacer esto.


Código: [Seleccionar]
import java.util.Scanner;
import java.util.Random;

public class Main{
   public static void main(String[] args){
      Scanner input = new Scanner(System.in);
      Random numRandom = new Random();
      int x = 0, y = 0, dir = 0, planoX = 0, planoY = 0, opcTipoMapa = 0;
      //x = y = cordenada del jugador
      //dir = direccion del jugador
      //planoX = planoY = indice de la matriz de la posicion del jugador
      //opcTipoMapa = el mapa puede ser generado por valores que el usuario colocara o seran valores aleatorios
      boolean juego = true;
      char jugador = ' ';
     
      //aspecto del jugador
      System.out.print("Jugador: ");     
      jugador = input.next().charAt(0);
      //declarar valores del largo y ancho del mapa
      System.out.println("1: Escoger los valores del mapa | 2: Valores aleatorios (1-100)");
      opcTipoMapa = input.nextInt();
      while(opcTipoMapa < 1 || opcTipoMapa > 2){
         System.out.println("No ha seleccionado de manera correcta. . .");
         System.out.println("1: Escoger los valores del mapa | 2: Valores aleatorios (1-100)");
         opcTipoMapa = input.nextInt();
      }
      switch(opcTipoMapa){
         case 1:
            System.out.print("Ancho: ");
            planoX = input.nextInt();
            System.out.print("Largo: ");
            planoY = input.nextInt();
         break;
         case 2:
            planoX = numRandom.nextInt(100)+1;
            planoY = numRandom.nextInt(100)+1;
            System.out.println("Ancho: " + planoX + "\nLargo: " + planoY);           
         break;
      }
      int plano[][] = new int[planoX][planoY];
      plano[0][0] = jugador;
     
      //juego
      while(juego){
         for(int i = 0; i < planoY; i++){
            for(int j = 0; j < planoX; j++){
               if(plano[j][i] == jugador){
                  System.out.print("[" + jugador + "]");
               }else{
                  System.out.print("[ ]");
               }
            }
            System.out.println();
         }
         System.out.println("Direccion: 1: Derecha | 2: Izquierda | 3: Arriba | 4: Abajo");
         dir = input.nextInt();
         while(dir < 1 || dir > 4){
            System.out.println("No ha seleccionado de manera correcta. . .");
            System.out.println("Direccion: 1: Derecha | 2: Izquierda | 3: Arriba | 4: Abajo");
            dir = input.nextInt();
         }
         switch(dir){
            case 1: //x++
               x++;
               if(x == planoX){ //limite del mapa
                  x = 0;
                  plano[x][y] = jugador;
                  plano[x+planoX-1][y] = ' ';
               }else{ //movimiento
                  plano[x][y] = jugador;
                  plano[x-1][y] = ' ';
               }
            break;
            case 2: //x--
               x--;
               if(x < 0){ //limite del mapa
                  x = planoX-1;
                  plano[x][y] = jugador;
                  plano[0][y] = ' ';
               }else{
                  plano[x][y] = jugador;
                  plano[x+1][y] = ' ';
               } 
            break;
            case 3: //y--
               y--;
               if(y < 0){
                  y = planoY-1;
                  plano[x][y] = jugador;
                  plano[x][0] = ' ';
               }else{
                  plano[x][y] = jugador;
                  plano[x][y+1] = ' ';
               }
            break;
            case 4: //y++
               y++;
               if(y == planoY){
                  y = 0;
                  plano[x][y] = jugador;
                  plano[x][y+planoY-1] = ' ';
               }else{
                  plano[x][y] = jugador;
                  plano[x][y-1] = ' ';
               }
            break;
         }
      }
   }
}

Tengo una pequeña duda, hace ya mucho tiempo, creé un hilo sobre una duda que tenía acerca del objeto Scanner, el usuario Kabuto me respondió, y quede fuera de dudas, sin embargo, por alguna razón me estoy emepzando a cuestionar y se me generó una nueva pregunta. El problema que tenía era de que a veces el Scanner no me leía los datos y los "saltaba", es decir...

Código: [Seleccionar]
variableInt = input.nextInt();
System.out.println("Numero: " + variableInt);
variableString = input.nextLine(); //el objeto Scanner ignora esto
System.out.println("Frase: " + variableString);

A este suceso se le llama "retorno de coche", y he aquí mi duda, por lo que entiendo, al momento de utilizar X valor con el objeto Scanner, y cambiar ese mismo valor de manera bruta, puede que provoque este fenómeno, ¿no?
« Última modificación: 31 de Octubre 2020, 14:25 por Alex Rodríguez »

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 989
    • Ver Perfil
Re:Java - Mi algoritmo para un pequeño juego en consola; pequeña duda
« Respuesta #1 en: 05 de Septiembre 2020, 12:15 »
Interesante propuesta.
La verdad es que poco más se puede hacer, ya que en modo consola las posibilidades de lo que mostramos en pantalla son muy limitadas en Java.

Lo único que le faltaría añadir sería una opción para poder salir del programa, ya que el bucle de "juego" se repite infinitas veces.

Sobre lo del objeto Scanner, a ver si lo explico mejor.

Cuando tú escribes algo, ya sea en Java, en Bloc de Notas, en un foro...en cualquier soporte informático, con el teclado estamos enviando caracteres que se muestran en pantalla y forman palabras, instrucciones, números y operaciones, etc...

Pero hay algunas teclas que envían caracteres especiales, caracteres que no se ven en pantalla, pero que cumplen una función.

Uno de ellos es el carácter que se produce cuando pulsamos la tecla enter, o intro, o como queramos llamarla...
Este carácter, su función es poner fin a la línea que estamos escribiendo y se llama "retorno de carro". No de "coche", de carro.
Este nombre viene heredado de las antiguas máquinas de escribir, donde para poner fin a una línea y comenzar la siguiente se accionaba una palanca:



Al accionar esta palanca, el "carro" volvía a la posición original ,el rodillo saltaba a la línea siguiente, y se podía seguir escribiendo de izquierda a derecha.

Bueno, lo que nos interesa a nosotros... este carácter como digo, es invisible en pantalla y el usuario no lo ve, pero el ordenador sí, para él es otro carácter más y suele representarlo con el carácter \r

Así que cuando escribimos esto:

Citar
Línea 1.
Línea 2.
Línea 3.

El ordenador recibe esto:

Citar
Línea 1.\r
Línea 2.\r
Línea 3.\r

En Java, la clase Scanner se encarga de recibir datos de los sistemas de entrada. Generalmente el teclado, pero podrían ser otros como un fichero de texto.
Scanner funciona como una cola, va recibiendo bytes (para crear una carácter se usa un byte de información) y de estos captura, en orden de llegada, lo que le solicitemos.

Si a Scanner le pedimos que capture una entrada de datos usando el método nextLine(), es decir, que capture una línea, pues va a recoger todos los bytes/caracteres necesarios para crear una línea y eso incluye el carácter \r

Entonces, si al hacer nextLine() le tecleamos esto:
Citar
Hola que tal, buenas tardes\r
Capturará TODOS los caracteres, porque todos conforman una línea y la "cola de datos" (stream) del Scanner quedará vacía.

Pero, y ahora viene el problema, si le pedimos que capture datos con el método nextInt(), es decir, que capture los caracteres necesarios para crear un valor numérico entero, esto va a excluir el caracter \r, porque con eso no se hace un valor numérico.
El carácter retorno de carro, a nextInt() le va a servir para saber que tiene que dejar de buscar caracteres válidos para crear un número, pero no lo capturará.

Entonces, si a nextInt() le damos esto:

Citar
129\r
Cogerá el 1, el 2 y el 9.., pero no el \r. Y este \r se va a quedar en la "cola de datos".

Y aquí es donde viene el problema.

Si después de esto seguimos pidiendo leer números con nextInt(), nextDouble(), etc... no habrá problema.
Estos métodos se encontrarán el \r en la cola, pero no le harán caso porque todavía no han entrado caracteres para crear valores numéricos. Cuando empiecen a entrar, los irán capturando hasta que el usuario ponga fin enviando un nuevo \r, que los métodos no recogerán y también quedará olvidado en la cola de datos.

Pero, si tras leer números y dejar caracteres \r en la cola de datos, queremos leer una línea con nextLine(), será entonces cuando el usuario no podrá introducir nada.
Porque cuando nextLine() se vaya a la cola de datos a esperar que el usuario teclee cosas, se encontrará los \r olvidados de las lecturas anteriores.
Y este es un carácter que nextLine() NO DEBE ignorar, puede usarlos para conformar lo que se le ha pedido, una línea.

Y de hecho, es el carácter que pone fin a la línea, así que nextLine() da por finalizada la captura de datos, sin que el usuario haya podido teclear absolutamente nada.
nextLine() ha creado una línea vacía (que técnicamente es válida), pero el usuario se queda asombrado porque parece que el programa se ha saltado la entrada de datos.

Por esto, cuando en un programa queramos leer números y líneas, es mejor usar para todo nextLine() y si hace falta, parsear a Integer, Float o lo que sea...
Así se evita dejar retornos de carros abandonados en la cola del Scanner.

Si solo se van a leer valores numéricos y/o valores char (que en realidad también es un numérico) pues entonces no hay problema.

Espero que con esta explicación más extensa se entienda mejor.
He de decir que esto del Scanner nos vuelve locos a TODOS cuando empezamos a programar en Java, no eres el único je je..

Y además decir que no es un error de Java, ni nada parecido. En realidad es una consecuencia lógica al hacer lecturas de datos, no se si podríamos decir, a "bajo nivel".

Esto mismo ocurre también por ejemplo en lenguaje C.
« Última modificación: 05 de Septiembre 2020, 12:20 por Kabuto »
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

CoduJ

  • Sin experiencia
  • *
  • Mensajes: 28
    • Ver Perfil
Re:Java - Mi algoritmo para un pequeño juego en consola; pequeña duda
« Respuesta #2 en: 08 de Septiembre 2020, 23:17 »
Citar
Lo único que le faltaría añadir sería una opción para poder salir del programa, ya que el bucle de "juego" se repite infinitas veces.
No tenía pensado realmente añadirlo, ya que pretendía que el juego tuviera alguna meta o algo por el estilo (quería crear algo como Nethack, pero en Java), pero como veo que es algo complicado "manipular" cosas así, es buena idea añadir una opción para salir del juego.
Citar
y se llama "retorno de carro". No de "coche", de carro.
Oops, disculpa por eso.

Bien, creo que ahora sí comprendo mucho mejor. Entonces, este "problema" llamado "retorno de carro", se debe a que estoy utilizando valores que no devuelven un "/r" (generado por la tecla Enter) y este se queda almacenado en el Scanner; el Scanner, al no ver un carácter que devuelve "/r", simplemente se lo queda guardado hasta que vea uno,  por ejemplo:
Código: [Seleccionar]
Entrada de números/char: X, Y, Z... //no hay "/r"
Luego...
Entrada de carácteres: " " //podemos utilizar el "/r" que nos "sobraba", ya que este sí lo devuelve.
Al momento de que la entrada éste disponivle, toma el "/r" del Scanner, y como "/r" representa el tecleo de Enter, el Scanner lo considera como si el usuario ya terminó
Y para evitar este "problema", es mejor que todo se escriba como nextLine(), para luego transformarlo a un tipo diferente de dato.

 

Sobre la educación, sólo puedo decir que es el tema más importante en el que nosotros, como pueblo, debemos involucrarnos.

Abraham Lincoln (1808-1865) Presidente estadounidense.

aprenderaprogramar.com: Desde 2006 comprometidos con la didáctica y divulgación de la programación

Preguntas y respuestas

¿Cómo establecer o cambiar la imagen asociada (avatar) de usuario?
  1. Inicia sesión con tu nombre de usuario y contraseña.
  2. Pulsa en perfil --> perfil del foro
  3. Elige la imagen personalizada que quieras usar. Puedes escogerla de una galería de imágenes o subirla desde tu ordenador.
  4. En la parte final de la página pulsa el botón "cambiar perfil".