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
\rAsí que cuando escribimos esto:
Línea 1.
Línea 2.
Línea 3.
El ordenador recibe esto:
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:
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:
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.