Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: oblivionxor en 11 Febrero 2013, 03:50 am



Título: Programa de Educacion Asistida por Computadora en C.
Publicado por: oblivionxor en 11 Febrero 2013, 03:50 am
Hola de nuevo, pues ahora hice un programa para practicar las operaciones aritméticas básicas (suma, resta, multiplicación y división). Solamente me gustaría su opinión sobre el mismo, es decir, que les parece la estructura del código. Hice un programa anteriormente (distinto a este) y me hicieron la recomendación de no comentar tanto el código por que se veia muy adornado y pues puse en practica ese consejo, esta comentado pero solo lo necesario. Me gustaría saber en que aspectos podría mejorar mi programa, me refiero a la estructura del código, hago este tipo de preguntas por que quiero aprender a programar limpiamente y hacer que mi código sea fácil de comprender. Agradecimientos por adelantado.

Código
  1. /* Este programa sirve para practicar sumas, restas, multiplicaciones y divisiones */
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <time.h>
  5.  
  6. /* Prototipos de funciones */
  7. float generarNumero( int nivelDificultad );
  8. float operacion( float numero1, float numero2, int operacionElegida );
  9. void respuestaCorrecta( void );
  10. void respuestaIncorrecta( void );
  11. void impresionTipoDeOperacion( int tipoDeOperacion );
  12.  
  13. /* Inicia la ejecucion del programa */
  14. int main()
  15. {
  16. int i, correcta, nivel, operando, operando2;
  17. float num1, num2, resultado, intento;
  18. correcta = 0;
  19.  
  20. srand( time( NULL ) ); /* Modificacion de la semilla de los numeros pseudoaleatorios */
  21.  
  22. printf( "Bienvenido al sistema de aprendizaje asistido por computadora, se te preguntaran\n" );
  23. printf( "10 operaciones y luego se te mencionara si necesitas ayuda tutorial.\n" );
  24.  
  25. printf( "Por favor ingresa el nivel que quieres practicar ( 1 al 3 )..." );
  26.  
  27. do {
  28. scanf( "%d", &nivel );
  29.  
  30. if ( nivel < 1 || nivel > 3 ) {
  31. printf( "Nivel no valido, intenta otravez..." );
  32. }
  33. } while ( nivel < 1 || nivel > 3 );
  34.  
  35. printf( "Que tipo de operaciones quiere resolver:\n" );
  36. printf( "1. Sumas\n2. Restas\n3. Multiplicaciones\n4. Divisiones\n" );
  37. printf( "5. Operaciones Aleatorias\n" );
  38. printf( "Recuerda que no es obligatorio hacer las operaciones mentalmente, puedes\n" );
  39. printf( "apoyarte de lapiz y papel para realizarlas. ATENCION! No se permite el\n" );
  40. printf( "uso de calculadora.\n..." );
  41.  
  42. do {
  43. scanf( "%d", &operando );
  44.  
  45. if ( operando < 1 || operando > 5 ) {
  46. printf( "Opcion no valida, intenta de nuevo..." );
  47. }
  48. } while ( operando < 1 || operando > 5 );
  49.  
  50. operando2 = operando; /* Esta variable guarda el valor de operando, esto es para tener intacta nuestra variable y modificar la copia */
  51.  
  52. for ( i = 1; i <= 10; i++ ) {
  53. /* Llamamos a las funciones generadoras de numeros aleatorios */
  54. num1 = generarNumero( nivel );
  55. num2 = generarNumero( nivel );
  56.  
  57. if ( operando == 5 ) { /* Y por este motivo es por el que debemos mantener intacta nuestra variable operando */
  58. operando2 = 1 + rand() % 4; /* Genera una operacion aleatoria */
  59. }
  60.  
  61. resultado = operacion( num1, num2, operando2 ); /* Llamamos a la funcion que resuelve la operacion elegida ( o generada ) */
  62.  
  63. printf( "Cuanto es %.0f ", num1 );
  64. impresionTipoDeOperacion( operando2 );
  65. printf( " %.0f?...", num2 );
  66.  
  67. do {
  68. scanf( "%f", &intento );
  69.  
  70. if ( intento != resultado ) {
  71. respuestaIncorrecta(); /* Llamada a la funcion que genera los mensajes aleatorios cuando se responde incorrectamente */
  72. correcta--; /* Se decrementa en uno cada vez que se ingresa una respuesta correcta */
  73. }
  74. } while ( intento != resultado );
  75.  
  76. /* Cuando se ingresa la respuesta correcta, se llama a a funcion que genera el mensaje aleatorio y se incrementa correcta */
  77. respuestaCorrecta();
  78. correcta++;
  79.  
  80. } /* Fin de for */
  81.  
  82. if ( correcta < 7 ) { /* Si hubo mas de 3 respuestas incorrectas, se imprime este mensaje */
  83. printf( "Cometiste varios errores, por favor pide ayuda adicional a tu profesor. Hasta la proxima!\n" );
  84. }
  85.  
  86. return 0;
  87. } /* Fin de main */
  88.  
  89. /* Definicion de funciones */
  90. float generarNumero( int nivelDificultad )
  91. {
  92. switch ( nivelDificultad ) { /* Para generar numeros de 1, 2 y 3 digitos en los niveles 1, 2 y 3 respectivamente */
  93. case 1:
  94. return 1 + rand() % 9;
  95. break;
  96.  
  97. case 2:
  98. return 10 + rand() % 90;
  99. break;
  100.  
  101. case 3:
  102. return 100 + rand() % 900;
  103. break;
  104. } /* Fin de switch */
  105. } /* Fin de funcion generaNumero */
  106.  
  107. float operacion( float numero1, float numero2, int operacionElegida )
  108. {
  109. switch ( operacionElegida ) { /* Para la resolucion de nuestra operacion, esto es para compararlo posteriormente con la respuesta del
  110. user*/
  111. case 1:
  112. return numero1 + numero2;
  113. break;
  114.  
  115. case 2:
  116. return numero1 - numero2;
  117. break;
  118.  
  119. case 3:
  120. return numero1 * numero2;
  121. break;
  122.  
  123. case 4:
  124. return numero1 / numero2;
  125. break;
  126. }
  127. } /* Fin de funcion operacion */
  128.  
  129. void respuestaCorrecta( void )
  130. {
  131. switch ( 1 + rand() % 4 ) {
  132. case 1:
  133. printf( "Muy bien!!\n" );
  134. break;
  135.  
  136. case 2:
  137. printf( "Excelente!!\n" );
  138. break;
  139.  
  140. case 3:
  141. printf( "Manten ese buen rendimiento!!\n" );
  142. break;
  143.  
  144. case 4:
  145. printf( "Buen trabajo!!\n" );
  146. break;
  147. } /* Fin de switch */
  148. } /* Fin de funcion respuestaCorrecta */
  149.  
  150. void respuestaIncorrecta( void )
  151. {
  152. switch ( 1 + rand() % 4 ) {
  153. case 1:
  154. printf( "No. Por favor intenta de nuevo...\n" );
  155. break;
  156.  
  157. case 2:
  158. printf( "Incorrecto. Trata una vez mas\n" );
  159. break;
  160.  
  161. case 3:
  162. printf( "No te rindas!!\n" );
  163. break;
  164.  
  165. case 4:
  166. printf( "No. Sigue intentando\n" );
  167. break;
  168. } /* Fin de switch */
  169. } /* Fin de funcion respuestaIncorrecta */
  170.  
  171. void impresionTipoDeOperacion( int tipoDeOperacion )
  172. {
  173. switch ( tipoDeOperacion ) {
  174. case 1:
  175. printf( "mas" );
  176. break;
  177.  
  178. case 2:
  179. printf( "menos" );
  180. break;
  181.  
  182. case 3:
  183. printf( "por" );
  184. break;
  185.  
  186. case 4:
  187. printf( "entre" );
  188. break;
  189. }
  190. } /* Fin de funcion impresionTipoDeOperacion */


Título: Re: Programa de Educacion Asistida por Computadora en C.
Publicado por: capsulasinformaticas en 11 Febrero 2013, 05:08 am
El codigo, estan bien, mucho mejor explicado que la mayoria de codigos que veo.


Título: Re: Programa de Educacion Asistida por Computadora en C.
Publicado por: oblivionxor en 11 Febrero 2013, 05:35 am
Que tal capsulasinformaticas! ¿Entonces no hay necesidad de modificarle nada respecto a la estructuración de código? ¿Alguna recomendación o algo?
   


Título: Re: Programa de Educacion Asistida por Computadora en C.
Publicado por: capsulasinformaticas en 11 Febrero 2013, 06:54 am
Que tal capsulasinformaticas! ¿Entonces no hay necesidad de modificarle nada respecto a la estructuración de código? ¿Alguna recomendación o algo?
  

Tampoco lo lei todo, pero note que al compilarlo se quejaba de las funciones generarNumero y operacion no les pusiste el caso default y un return en el  para hacer que en "cualquier caso" se devuelva un float (por que decia que esas funciones no retornaban un tipo float), pero igual con el while te aseguras que se ingrese un 1, 2 o un 3, asi que no encuentro que haya que cambiarle algo xD, igual no encuentro ser muy experto, pero bueno, esa es mi humilde opinion xD.


Título: Re: Programa de Educacion Asistida por Computadora en C.
Publicado por: oblivionxor en 11 Febrero 2013, 07:10 am
Ok capsulasinformaticas muchas gracias por tu opinion :D
 Respecto a lo de la compilacion, creo que es tu compilador por que a mi me compila sin ningun problema.


Título: Re: Programa de Educacion Asistida por Computadora en C.
Publicado por: amchacon en 11 Febrero 2013, 08:39 am
Bueno yo le cambiaría el diseño de las llaves:

Código
  1.  
  2. do {
  3.         scanf( "%d", &operando );
  4.  
  5.         if ( operando < 1 || operando > 5 ) {
  6.              printf( "Opcion no valida, intenta de nuevo..." );
  7.         }
  8. } while ( operando < 1 || operando > 5 );

Siguiendo las normativas de estilo las pondría abajo:

Código
  1.  
  2. do
  3. {
  4.         scanf( "%d", &operando );
  5.  
  6.         if ( operando < 1 || operando > 5 )
  7.         {
  8.              printf( "Opcion no valida, intenta de nuevo..." );
  9.         }
  10. } while ( operando < 1 || operando > 5 );

La ventaja que tiene es que puede ver mejor a que corresponde cada llave cerrada, ya que se encuentran al mismo nivel.


Título: Re: Programa de Educacion Asistida por Computadora en C.
Publicado por: oblivionxor en 11 Febrero 2013, 20:29 pm
Ok tomare en cuenta tu consejo amchacon! Muchas gracias!


Título: Re: Programa de Educacion Asistida por Computadora en C.
Publicado por: xassiz~ en 11 Febrero 2013, 20:45 pm
Así por encima, respeto a los comentarios yo creo que siguen sobrando cosas como "Fin de switch", "Fin de for", etc. Cualquiera ve que se acaba, para eso está bien identado :rolleyes:

Otra cosa que veo es en todos esos bucles do-while, realizas la misma comprobación dos veces (con el if).

Saludos!


Título: Re: Programa de Educacion Asistida por Computadora en C.
Publicado por: dato000 en 11 Febrero 2013, 21:03 pm
Así por encima, respeto a los comentarios yo creo que siguen sobrando cosas como "Fin de switch", "Fin de for", etc. Cualquiera ve que se acaba, para eso está bien identado :rolleyes:

Otra cosa que veo es en todos esos bucles do-while, realizas la misma comprobación dos veces (con el if).

Saludos!

No!! es mejor dejarlo así, a veces es muy bueno indicar en que momento se acaba el while, pues dependiendo del ide o el editor puede que muestre o no esa ubicación, por eso muy buena idea colocar esas referencias.

Y lo de los if, es solo una forma de validar el dato, hay otras formas, pero esa esta bien, es solo una tecnica, cada quien tiene su propio estilo.

Muy bueno el código, no lo compile, así que no puedo decirte que tal corre, pero mirandolo por encima no le veo problema, es la organización lo que me sorprende, me siento un poco avergonzado al darme cuenta lo mal que documento (o hago poco o nada, o a veces ocupo muchisimas lineas comentando) y creo que es buena idea hablar de este punto.

Lo que acaba de ocurrirseme es diferenciar un poco sobre comentar de una forma la estructura del codigo (fin do-while, fin funcion...) y comentar de otra el funcionamiento del programa (por ejm: Esta variable guarda el valor de operando...) creo que se podria empezar con un signo como % cuando es de estructura y con $ cuando de es de funcionamiento. desde ahora, todo el código que realice, lo hare de esta forma. Gracias muchachos me inspiraron a trabajar mejor, sea el lenguaje que sea.


Título: Re: Programa de Educacion Asistida por Computadora en C.
Publicado por: leosansan en 11 Febrero 2013, 21:43 pm
Pues como sólo va una instrucción después del if, yo no pondría llaves:

Código
  1. do
  2. {
  3.         scanf( "%d", &operando );
  4.  
  5.         if ( operando < 1 || operando > 5 )
  6.               printf( "Opcion no valida, intenta de nuevo..." );
  7.  
  8. } while ( operando < 1 || operando > 5 );

y arreglaría el "scanf( "%d", &operando );" por si entran un carácter en vez de un número.

Saluditos!.


Título: Re: Programa de Educacion Asistida por Computadora en C.
Publicado por: oblivionxor en 12 Febrero 2013, 05:58 am
Muchas gracias a todos por sus consejos! dato000 pondré en practica lo de poner signos al principio de los comentarios de funcionamiento y de estructura! leosansan respecto a lo que dices crees que de esta manera sea correcto validar la entrada? :
Código
  1.  
  2.    do
  3.    {
  4.            scanf( "%d", &operando );
  5.  
  6.            if ( operando != 1 && operando != 2 && operando != 3 && operando != 4 && operando != 5 )
  7.                  printf( "Opcion no valida, intenta de nuevo..." );
  8.  
  9.    } while ( operando != 1 && operando != 2 && operando != 3 && operando != 4 && operando != 5 );
  10.  

O hay otra forma? Todavia no llego al tema de arreglos ni punteros, soy super principiante pero solo me gustaria saber si hay otra forma de hacer la validacion sin usar los temas que no he visto?


Título: Re: Programa de Educacion Asistida por Computadora en C.
Publicado por: oblivionxor en 12 Febrero 2013, 06:22 am
Actualizo, no funciono mi metodo :\


Título: Re: Programa de Educacion Asistida por Computadora en C.
Publicado por: oblivionxor en 12 Febrero 2013, 07:29 am
Y vuelvo a actualizar jajaja, ya me puse a investigar y encontré un truco que limpia el buffer y pues lo use para que elimine cualquier carácter ingresado y deje intactas las variables con el valor que les preestableci en la declaración. leonsansan crees que lo haya hecho bien? El código quedo asi:
Código
  1. /* Este programa sirve para practicar sumas, restas, multiplicaciones y divisiones */
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <time.h>
  5.  
  6. /* Prototipos de funciones */
  7. float generarNumero( int nivelDificultad );
  8. float operacion( float numero1, float numero2, int operacionElegida );
  9. void respuestaCorrecta( void );
  10. void respuestaIncorrecta( void );
  11. void impresionTipoDeOperacion( int tipoDeOperacion );
  12.  
  13. /* Inicia la ejecucion del programa */
  14. int main()
  15. {
  16. int i, correcta, nivel, operando, operando2;
  17. float num1, num2, resultado, intento;
  18. correcta = 0;
  19. /* Estas declaraciones nos serviran para que si el usuario ingresa un caracter en vez de una letra, se falle la prueba de validacion.
  20. La variable intento esta declarada a ese valor por que hay veces que los resultados de las funciones dan 0 y puede haber un error de logica en
  21. el programa */
  22. operando = 0;
  23. nivel = 0;
  24. intento = -2000000;
  25.  
  26. srand( time( NULL ) ); /* Modificacion de la semilla de los numeros pseudoaleatorios */
  27.  
  28. printf( "Bienvenido al sistema de aprendizaje asistido por computadora, se te preguntaran\n" );
  29. printf( "10 operaciones y luego se te mencionara si necesitas ayuda tutorial.\n" );
  30.  
  31. printf( "Por favor ingresa el nivel que quieres practicar ( 1 al 3 )..." );
  32.  
  33. do
  34. {
  35. scanf( "%d", &nivel );
  36. while ( getchar() != '\n' ); /* Esta instruccion sirve para eliminar todos los caracteres que se ingresen. Esto dejara la variable
  37. nivel intacta con su valor original "0" y fallara la prueba de validacion */
  38.  
  39. if ( nivel < 1 || nivel > 3 )
  40. printf( "Nivel no valido, intenta otravez..." );
  41.  
  42. } while ( nivel < 1 || nivel > 3 );
  43.  
  44. printf( "Que tipo de operaciones quiere resolver:\n" );
  45. printf( "1. Sumas\n2. Restas\n3. Multiplicaciones\n4. Divisiones\n" );
  46. printf( "5. Operaciones Aleatorias\n" );
  47. printf( "Recuerda que no es obligatorio hacer las operaciones mentalmente, puedes\n" );
  48. printf( "apoyarte de lapiz y papel para realizarlas. ATENCION! No se permite el\n" );
  49. printf( "uso de calculadora.\n..." );
  50.  
  51. do
  52. {
  53. scanf( "%d", &operando );
  54. while ( getchar() != '\n' ); /* Esta instruccion sirve para eliminar todos los caracteres que se ingresen. Esto dejara la variable
  55. operando intacta con su valor original "0" y fallara la prueba de validacion */
  56.  
  57. if ( operando < 1 || operando > 5 )
  58. printf( "Opcion no valida, intenta de nuevo..." );
  59.  
  60. } while ( operando < 1 || operando > 5 );
  61.  
  62. operando2 = operando; /* Esta variable guarda el valor de operando, esto es para tener intacta nuestra variable y modificar la copia */
  63.  
  64. for ( i = 1; i <= 10; i++ )
  65. {
  66. /* Llamamos a las funciones generadoras de numeros aleatorios */
  67. num1 = generarNumero( nivel );
  68. num2 = generarNumero( nivel );
  69.  
  70. if ( operando == 5 ) /* Y por este motivo es por el que debemos mantener intacta nuestra variable operando */
  71. operando2 = 1 + rand() % 4; /* Genera una operacion aleatoria */
  72.  
  73. resultado = operacion( num1, num2, operando2 ); /* Llamamos a la funcion que resuelve la operacion elegida ( o generada ) */
  74.  
  75. printf( "Cuanto es %.0f ", num1 );
  76. impresionTipoDeOperacion( operando2 );
  77. printf( " %.0f?...", num2 );
  78.  
  79. do
  80. {
  81. scanf( "%f", &intento );
  82. while ( getchar() != '\n' ); /* Funcion de esta instruccion ya explicada arriba */
  83.  
  84. if ( intento != resultado )
  85. {
  86. respuestaIncorrecta(); /* Llamada a la funcion que genera los mensajes aleatorios cuando se responde incorrectamente */
  87. correcta--; /* Se decrementa en uno cada vez que se ingresa una respuesta correcta */
  88. }
  89. } while ( intento != resultado );
  90.  
  91. /* Cuando se ingresa la respuesta correcta, se llama a a funcion que genera el mensaje aleatorio y se incrementa correcta */
  92. respuestaCorrecta();
  93. correcta++;
  94.  
  95. } /* Fin de for */
  96.  
  97. if ( correcta < 7 ) /* Si hubo mas de 3 respuestas incorrectas, se imprime este mensaje */
  98. printf( "Cometiste varios errores, por favor pide ayuda adicional a tu profesor. Hasta la proxima!\n" );
  99.  
  100. return 0;
  101. } /* Fin de main */
  102.  
  103. /* Definicion de funciones */
  104. float generarNumero( int nivelDificultad )
  105. {
  106. switch ( nivelDificultad ) /* Para generar numeros de 1, 2 y 3 digitos en los niveles 1, 2 y 3 respectivamente */
  107. {
  108. case 1:
  109. return 1 + rand() % 9;
  110. break;
  111.  
  112. case 2:
  113. return 10 + rand() % 90;
  114. break;
  115.  
  116. case 3:
  117. return 100 + rand() % 900;
  118. break;
  119. } /* Fin de switch */
  120. } /* Fin de funcion generaNumero */
  121.  
  122. float operacion( float numero1, float numero2, int operacionElegida )
  123. {
  124. switch ( operacionElegida ) /* Para la resolucion de nuestra operacion, esto es para compararlo posteriormente con la respuesta del user*/
  125. {
  126. case 1:
  127. return numero1 + numero2;
  128. break;
  129.  
  130. case 2:
  131. return numero1 - numero2;
  132. break;
  133.  
  134. case 3:
  135. return numero1 * numero2;
  136. break;
  137.  
  138. case 4:
  139. return numero1 / numero2;
  140. break;
  141. } /* Fin de switch */
  142. } /* Fin de funcion operacion */
  143.  
  144. void respuestaCorrecta( void )
  145. {
  146. switch ( 1 + rand() % 4 )
  147. {
  148. case 1:
  149. printf( "Muy bien!!\n" );
  150. break;
  151.  
  152. case 2:
  153. printf( "Excelente!!\n" );
  154. break;
  155.  
  156. case 3:
  157. printf( "Manten ese buen rendimiento!!\n" );
  158. break;
  159.  
  160. case 4:
  161. printf( "Buen trabajo!!\n" );
  162. break;
  163. } /* Fin de switch */
  164. } /* Fin de funcion respuestaCorrecta */
  165.  
  166. void respuestaIncorrecta( void )
  167. {
  168. switch ( 1 + rand() % 4 )
  169. {
  170. case 1:
  171. printf( "No. Por favor intenta de nuevo...\n" );
  172. break;
  173.  
  174. case 2:
  175. printf( "Incorrecto. Trata una vez mas\n" );
  176. break;
  177.  
  178. case 3:
  179. printf( "No te rindas!!\n" );
  180. break;
  181.  
  182. case 4:
  183. printf( "No. Sigue intentando\n" );
  184. break;
  185. } /* Fin de switch */
  186. } /* Fin de funcion respuestaIncorrecta */
  187.  
  188. void impresionTipoDeOperacion( int tipoDeOperacion )
  189. {
  190. switch ( tipoDeOperacion )
  191. {
  192. case 1:
  193. printf( "mas" );
  194. break;
  195.  
  196. case 2:
  197. printf( "menos" );
  198. break;
  199.  
  200. case 3:
  201. printf( "por" );
  202. break;
  203.  
  204. case 4:
  205. printf( "entre" );
  206. break;
  207. } /* Fin de switch */
  208. } /* Fin de funcion impresionTipoDeOperacion */

Si todavia tienen mas consejos, por favor no duden en decirmelos jaja. Gracias.


Título: Re: Programa de Educacion Asistida por Computadora en C.
Publicado por: rir3760 en 12 Febrero 2013, 18:05 pm
Hice un programa anteriormente (distinto a este) y me hicieron la recomendación de no comentar tanto el código por que se veia muy adornado y pues puse en practica ese consejo, esta comentado pero solo lo necesario.
Un buen consejo. En mi opinión deberías eliminar todos los comentarios del tipo "fin de esto" ya que son las llaves las que indican el termino de un bloque. Si tienes problemas para detectar el inicio/fin de un bloque o función es mejor optar por un editor de texto para programadores con la característica de resaltado (por ejemplo los basados en Scintilla).

Bueno yo le cambiaría el diseño de las llaves [...] Siguiendo las normativas de estilo las pondría abajo:
Código
  1.  
  2. do
  3. {
  4.         scanf( "%d", &operando );
  5.  
  6.         if ( operando < 1 || operando > 5 )
  7.         {
  8.              printf( "Opcion no valida, intenta de nuevo..." );
  9.         }
  10. } while ( operando < 1 || operando > 5 );
La ventaja que tiene es que puede ver mejor a que corresponde cada llave cerrada, ya que se encuentran al mismo nivel.
Hay varios estilos y algunos de estos se pueden revisar en la pagina de la aplicación astyle (http://astyle.sourceforge.net/astyle.html#_Bracket_Style_Options)), lo importante no es buscar cual es el mejor (no hay respuesta, es subjetivo) sino utilizar uno de forma consistente.

----

En cuanto al programa la única forma 100% a prueba de fallos para la lectura de un numero es mediante funciones como strtol, strtoul y strtod. Se puede utilizar la familia scanf pero con sus limitantes. Con esta ultima se debe verificar primero su valor de retorno (numero de conversiones realizadas con éxito) y, si aplica, que el numero este en el rango valido. Un programa de ejemplo:
Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. int main (void)
  5. {
  6.   int opcion;
  7.   int ok;
  8.   int ch;
  9.  
  10.   while (1){
  11.      printf("Indica la opcion: ");
  12.      fflush(stdout);
  13.      ok = scanf("%d", &opcion) == 1 && opcion > 0 && opcion < 6;
  14.  
  15.      while ((ch = getchar()) != EOF && ch != '\n')
  16.         ;
  17.  
  18.      if (ok)
  19.         break;
  20.      else
  21.         puts("Opcion no valida, intenta de nuevo...");
  22.   }
  23.   printf("La opcion es la %d\n", opcion);
  24.  
  25.   return EXIT_SUCCESS;
  26. }

La función "generarNumero" se puede reducir utilizando la función pow (prototipo en <math.h>):
Código
  1. #include <math.h>
  2.  
  3. /* ... */
  4.  
  5. float generarNumero(int nivel)
  6. {
  7.   int a = pow(10.0, nivel - 1.0);
  8.  
  9.   return a + rand() % (9 * a);
  10. }

Y las funciones que seleccionan e imprimen una cadena al azar o indicando su posición se pueden reducir utilizando arrays:
Código
  1. void respuestaCorrecta(void)
  2. {
  3.   char *resp[] = {
  4.      "Muy bien!!",
  5.      "Excelente!!",
  6.      "Manten ese buen rendimiento!!",
  7.      "Buen trabajo!!"
  8.   };
  9.  
  10.   puts(resp[rand() % 4]);
  11. }
  12.  
  13. void impresionTipoDeOperacion(int num_op)
  14. {
  15.   char *op[] = {
  16.      "mas",
  17.      "menos",
  18.      "por",
  19.      "entre"
  20.   };
  21.  
  22.   printf("%s", op[num_op - 1]);
  23. }

Un saludo


Título: Re: Programa de Educacion Asistida por Computadora en C.
Publicado por: capsulasinformaticas en 13 Febrero 2013, 03:46 am
Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. int main (void)
  5. {
  6.   int opcion;
  7.   int ok;
  8.   int ch;
  9.  
  10.   while (1){
  11.      printf("Indica la opcion: ");
  12.      fflush(stdout);
  13.      ok = scanf("%d", &opcion) == 1 && opcion > 0 && opcion < 6;
  14.  
  15.      while ((ch = getchar()) != EOF && ch != '\n')
  16.         ;
  17.  
  18.      if (ok)
  19.         break;
  20.      else
  21.         puts("Opcion no valida, intenta de nuevo...");
  22.   }
  23.   printf("La opcion es la %d\n", opcion);
  24.  
  25.   return EXIT_SUCCESS;
  26. }

Me da lata extender mas el tema e irnos por las ramas, pero tengo una duda, ¿Siempre que quiera mostrar un printf sin que finalize con un '\n' seria conveniente usar un fflush(stdout)?

Y otra cosa que no entendi es el uso de
Código:
while ((ch = getchar()) != EOF && ch != '\n')
         ;
en ese codigo, es decir, probe el codigo sin esa parte y como que el bucle hace un loop infinito y no me puedo ingresar la opcion con scanf("%d", &opcion) si ingreso una opcion invalida, pero no se por que pasa.

Saludos.


Título: Re: Programa de Educacion Asistida por Computadora en C.
Publicado por: amchacon en 13 Febrero 2013, 11:18 am
Me da lata extender mas el tema e irnos por las ramas, pero tengo una duda, ¿Siempre que quiera mostrar un printf sin que finalize con un '\n' seria conveniente usar un fflush(stdout)?
En realidad, el buffer se vacía automáticamente al usar un \n. Por lo que no sería necesario

Y otra cosa que no entendi es el uso de
Código:
while ((ch = getchar()) != EOF && ch != '\n')
         ;
en ese codigo, es decir, probe el codigo sin esa parte y como que el bucle hace un loop infinito y no me puedo ingresar la opcion con scanf("%d", &opcion) si ingreso una opcion invalida, pero no se por que pasa.

Saludos.

Es una forma para limpiar el buffer de teclado (mientras no se llegue al salto de línea o al máximo buffer disponible...).

Por cierto muy elegante el código, me gusta (aunque sigo insistiendo que la llave del while estaría mejor abajo).


Título: Re: Programa de Educacion Asistida por Computadora en C.
Publicado por: rir3760 en 13 Febrero 2013, 18:52 pm
¿Siempre que quiera mostrar un printf sin que finalize con un '\n' seria conveniente usar un fflush(stdout)?
Si, es necesario.

En el caso de los bufers relacionados con streams de salida estos se vacían en tres escenarios, cuando:

A) Se llena, vaciado automático.
B) La secuencia de caracteres es seguida por el caracter '\n'.
C) Se indica de forma explicita mediante la llamada fflush(stream).

En nuestro caso la opción A no vale porque no se tiene control de este, la segunda tampoco porque la cadena no termina con el mentado carácter, la única opción es la restante.

Si ello no se hace el funcionamiento del programa puede resultar confuso ya que puede este esperar una entrada y solo después enviar el mensaje al stream de salida (por ejemplo instrucciones de uso).

Y otra cosa que no entendi es el uso de
Código:
while ((ch = getchar()) != EOF && ch != '\n')
         ;
en ese codigo, es decir, probe el codigo sin esa parte y como que el bucle hace un loop infinito y no me puedo ingresar la opcion con scanf("%d", &opcion) si ingreso una opcion invalida, pero no se por que pasa.
Porque la función scanf solo consume los caracteres que sean validos para la conversión en turno. Si el carácter a procesar no cumple se queda en la entrada estándar.

Dos ejemplos para explicarlo mejor (con la mentada llamada a scanf):

A) La entrada contiene los caracteres:
Código:
' ', ' ', ' ', '1', '2', '3', '\n'
Aquí los caracteres de espacio blanco se descartan, '1', '2' y '3' se utilizan para obtener el entero 123. Como el '\n' no es valido para la conversión (valor de tipo signed int) este se queda en el bufer de la entrada estándar.

B) La entrada contiene:
Código:
'J', '\n'
Aquí la función revisa el bufer encontrando el carácter 'J', como este no es valido se queda en el bufer y la función termina de inmediato. En la siguiente iteracion sucede lo mismo y ello ocasiona el bucle infinito que mencionas.

Para evitarlo se descarta el resto de la linea mediante el bucle.

Un saludo