Un ejercicio interesante.
Así sobre la marcha, se me ocurre que para decidir al azar el tipo de operación matemática, previamente podemos declarar un array de tipo char con los 3 símbolos para cada tipo de operación.
De ese array iremos seleccionado un elemento al azar para cada pregunta que vayamos generando.
Para las selecciones al azar, necesitaremos un objeto
Random, el cuál además nos servirá para generar números y otras selecciones.
Para generar preguntas, podemos desarrollar un método al que cada vez que lo llamemos, haga todo el trabajo de generar la pregunta y nos retorne la respuesta correcta, para luego poder comparar con la respuesta del usuario.
De momento, comenzaríamos así:
Vamos a ver cómo desarrollamos el método
generarPregunta(), que es quien llevará todo el peso del programa.
Primero vamos a generar los dos valores con los que vamos a operar, nos dicen que han de ser entre 5 y 25.
Para ello le pedimos al objeto random que genera un entero con un límite de 21. Esto nos dará un entero entre 0 y 20(límite 21 queda excluido)
Si a este entero, le sumamos 5, pues ya tendremos valores entre 5 y 25
Ahora necesitamos seleccionar un operador al azar. Para ello cogemos un char del array de OPERADORES pidiéndole al objeto random que nos de un entero con limite 3, es decir, nos dará un valor entre 0 y 2, que son las posibles posiciones del array.
Vale, tenemos los valores y el operador.
Ahora hay que analizar que operador nos ha tocado y decidir si creamos una suma, una resta, etc..
Es muy fácil hacerlo con un switch
Bueno, hasta aquí un camino de rosas.
Ahora se complica un poco la cosa. Hay que generar 3 respuestas.
Una es la respuesta correcta.
Las otras dos son respuestas falsas que hemos de generar, cada una con determinadas reglas, y utilizando la respuesta correcta como base.
Y además, ojo a esto, cuando tengamos las tres respuestas, hemos de mostrarlas en pantalla en posiciones al azar. Es decir, la Respuesta #1 no tiene que ser siempre la correcta.
Para hacer selecciones de elementos al azar, ya hemos visto que es imprescindible contener esos elementos en algún tipo de colección de datos.
Para los operadores hemos usado un array primitivo. Para las respuestas podríamos usar otro, pero aquí hay una diferencia.
Con los operadores no importa si al elegir al azar, se repite o no el operador seleccionado. Si el azar decide que nos van a salir 5 sumas, pues que así sea.
En cambio para las respuestas, queremos elegirlas al azar al decidir quién es respuesta #1, quién es respuesta #2,... , pero que no se repitan. Hay que evitar que una misma respuesta salga al azar como respuesta #1 y también #3
Para poder controlar esto mejor, podemos usar esta vez un ArrayList, que es un tipo de colección más avanzada que un array primitivo. Y nos permite eliminar de la colección una respuesta que ya haya sido seleccionada, así no hay riesgo de que se repita dos o más veces.
Entonces, por ahora, justo antes del switch vamos a declarar un ArrayList para guardar enteros, que serán las tres posibles respuestas.
Además una variable int donde calcularemos la respuesta correcta.
Y en cada case del switch, comenzaremos añadiendo a este ArrayList la respuesta correcta en cada caso:
Vale, ahora viene la tarea de generar las otras dos respuestas falsas.
La segunda respuesta es fácil, es un valor entre -35 y la respuesta correcta - 1.
Así que basta con generar un int entre 0 y "correcta", y luego restarle -35
La tercera respuesta es un poco más enrevesada, un valor entre "correcta" + 1 y 900 inclusive.
Vale, respuestas calculadas y contenidas en el ArrayList.
Ahora hay que presentar en pantalla la pregunta y las respuestas en un orden al azar.
Para ello mostramos un mensaje cualquiera con los dos valores y el operador.
Luego las respuestas, extrayendo al azar elementos del ArrayList. En cada extracción, el valor elegido desaparece del ArrayList, así no hay riesgo de repeticiones indeseadas.
Una vez mostrado esto en pantalla, el método termina retornando la respuesta correcta. En este método no vamos a pedir nada al usuario ni vamos a evaluar si acierta o se equivoca. Esto lo haremos en el programa principal
Este método se dedica exclusivamente a crear la pregunta, la respuestas, mostrarlas en pantalla y retornar la respuesta correcta.
Ahora nos vamos al método main() de nuestra clase, y podemos hacer una prueba inicial de este método que hemos escrito.
Simplemente lo llamamos para que se ejecute, y así veremos si no da errores y si genera una pregunta y unas respuestas que se ajuste a los que nos han pedido.
Podemos ver en pantalla que parece funcionar bien:
Si lo probamos varias veces, veremos que la respuesta correcta sale en distintas posiciones, así que la selección al azar funciona perfectamente.
Vale, pues sabiendo que esto funciona, vamos a desarrollar el programa principal.
La mecánica es realizar 5 preguntas, recoger la respuesta del usuario y al final decirle cuántas ha acertado y cuántas ha fallado.
Bien, pues necesitaremos un objeto
Scanner para pedir respuestas al usuario y un contador de respuestas acertadas.
Usamos un bucle FOR que se repita 5 veces.
En cada repetición llamamos a nuestro método para que genera la pregunta trivia y recogemos la respuesta correcta que nos va a retornar.
Pedimos al usuario que nos de su respuesta y comparamos con la correcta para ver si ha acertado.
Si acierta, le felicitamos y aumentamos contador de aciertos.
Si falla, le abucheamos e indicamos la respuesta correcta.
Cuando termine el bucle FOR, mostramos cuántas ha acertado y cuántas ha fallado.
Y fin de programa.
Si probamos el programa, todo parece funcionar bien, se cuentan aciertos y errores correctamente.
Entonces, ¿ya está? ¿Hemos terminado? :-)
Pues casi, pero no.... (-_-x)
Como todo programa con cierta complejidad..., puede presentar errores inesperados.
Y este programa lo tiene, hay un error que puede ocurrir aleatoriamente.
En el caso de que se genere una resta, si el valor1 es MENOR que el valor2, la respuesta correcta será un valor negativo.
Por ejemplo: 5 - 7 = -2
Vale, ¿y cuál es el problema?
Pues que en este caso, luego al querer generar la respuesta 2, le estaremos pasando un valor negativo al método
nextInt() del objeto
Random
Y esto producirá una excepción interrumpiéndose el programa, porque este método no acepta ni negativos ni valor 0.
Así que tenemos buscar una solución para impedir que esta casuística nos fastidie el programa.
Una forma rápida de solucionarlo, podría ser capturar la excepción y cuanto esta ocurra, retornar una llamada recursiva al propio método para que genera una nueva pregunta, quedando esta pregunta actual descartada.
Así que envolvemos el switch donde analizamos el operador con un try catch para poder capturar la posible excepción y actuar en consecuencia:
Y con esto parece quedar solucionado dicho problema. He estado probando varias veces, forzando a que solo se generen restas y haciendo que muestre un mensaje en pantalla cada vez que ocurre una excepción, y parece que se gestiona bien esta incidencia.
El ciclo de 5 preguntas no se ve afectado aunque se estén descartando y generando preguntas extra.
Otra forma de solucionarlo sería comparar los valores antes de hacer la resta. Si son iguales o si valor1 es inferior a valor 2, tendríamos un negativo, así que habría que evitarlo intercambiando los valores o alternadolos para asegurarnos de que valor1 SIEMPRE es mayor que valor2.
En fin, espero que tanta explicación haya servido para que todo quede lo más claro posible.
Si tienes dudas, pregunta por aquí.
Un saludo.