Cómo enseñar a superar dificultades y, de paso, a escribir ciclos

A pesar de que se trata de un tema básico, este artículo está dirigido a profesionales experimentados. Su objetivo es mostrar los conceptos erróneos que suelen tener los principiantes en programación. Para los desarrolladores que ya están en práctica, estos problemas se han resuelto hace tiempo, olvidados o pasados por alto. El artículo puede ser útil si en algún momento necesitas ayudar a alguien con este tema. Se realizan paralelismos con material de varios libros de programación escritos por Schildt, Stroustrup y Okulov.

El tema sobre ciclos fue elegido porque es donde se filtra a muchas personas al iniciar en programación.

Este método está diseñado para estudiantes con dificultades. Generalmente, los estudiantes fuertes no se quedan atascados en este tema y no es necesario inventar métodos especiales para ellos. Un objetivo secundario del artículo es trasladar este método de la categoría "funciona en todos los estudiantes, pero solo con un profesor" a la categoría "funciona para todos los estudiantes, todos los profesores". No pretendo una originalidad absoluta. Si ya aplicas un método similar para enseñar este tema, por favor cuéntame en qué se diferencia tu enfoque. Si decides aplicarlo, cuéntame cómo te fue al final. Si hay un método similar descrito en algún libro, por favor, indícame el título.


Este método lo he estado perfeccionando durante 4 años, trabajando individualmente con estudiantes de diferentes niveles. En total, alrededor de medio centenar de estudiantes y dos mil horas de clases. Al principio, los estudiantes se quedaban atascados en este tema y se iban. Con cada estudiante, el método y los materiales se ajustaban. En el último año, los estudiantes ya no se quedan atascados en este tema, así que decidí compartir mis hallazgos.

¿Por qué tantas letras? ¡Los ciclos son elementales!

Como mencioné anteriormente, para desarrolladores en práctica y para estudiantes fuertes, la complejidad del concepto de ciclos puede ser subestimada. Por ejemplo, se puede dar una larga conferencia, ver cabezas asintiendo y ojos inteligentes. Pero al intentar resolver algún problema, comienza el bloqueo y surgen problemas inexplicables. Después de la conferencia, los estudiantes probablemente solo tienen una comprensión parcial. La situación se complica porque los estudiantes no pueden expresar por sí mismos en qué consiste exactamente su error.
Una vez me di cuenta de que los estudiantes perciben mis ejemplos como jeroglíficos. Es decir, como fragmentos indivisibles de texto en los que hay que agregar alguna letra "mágica" para que funcione.
A veces notaba que los estudiantes creen que para resolver un problema específico se necesita alguna otra construcción que simplemente aún no les he explicado. Aunque para la solución solo era necesario modificar un poco el ejemplo.

Por lo tanto, llegué a la idea de que la atención principal debe enfocarse no en la sintaxis de las expresiones, sino en la idea de refactorizar el código repetitivo mediante bucles. Una vez que los alumnos dominan esta idea, cualquier sintaxis se adquiere con pequeños ejercicios.

¿A quién y por qué le enseño?

Dado que no hay exámenes de ingreso, en las clases pueden haber tanto estudiantes fuertes como muy débiles. Se puede leer más sobre mis estudiantes en el artículo Retrato de los oyentes de los cursos nocturnos
Me esforcé para que todos los que desean aprender programación puedan hacerlo.
Mis clases son individuales y el estudiante paga su dinero por cada una. Aparentemente, los estudiantes optimizarían sus costos y exigirían lo mínimo. Sin embargo, las personas asisten a clases presenciales con un docente no solo por el conocimiento en sí, sino por la confianza de haber comprendido, por la sensación de progreso y por la aprobación de un experto (el docente). Si los estudiantes no sienten que están progresando en su aprendizaje, se irán. En general, se pueden estructurar las clases de manera que los estudiantes sientan un progreso en la cantidad de construcciones familiares. Es decir, primero estudiamos a fondo while, luego for, después do while y así tenemos un curso de mil y una noches, donde durante dos meses estudiamos solo bucles, y al final hay un estudiante que escribió por dictado la biblioteca estándar. Sin embargo, para resolver problemas prácticos, se necesita no solo el conocimiento del material, sino también autonomía en su aplicación y en la búsqueda de nueva información. Por lo tanto, considero correcto en los cursos presenciales el principio de enseñar lo mínimo y fomentar el estudio autodidacta de matices y temas relacionados. En el tema sobre bucles, considero que el mínimo es la construcción while. Con eso se puede comprender el principio. Sabiendo el principio, se puede aprender for y do-while de forma autónoma.

Para lograr que los estudiantes más débiles dominen el material, no basta con describir la sintaxis. Es necesario ofrecer más tareas simples, pero variadas, y detallar los ejemplos de manera más extensa. Al final, la velocidad de aprendizaje está limitada por la capacidad del estudiante para transformar las expresiones y encontrar patrones. Para los estudiantes más inteligentes, la mayoría de las tareas serán aburridas. Al trabajar con ellos, no es necesario insistir en resolver el 100% de los problemas. Pueden ver mi material en mi GitHub. Aunque el repositorio se parece más a un grimorio de un hechicero; nadie, excepto yo, entenderá dónde está cada cosa, y si se falla en la revisión, uno puede volverse loco.

La metodología está orientada a la práctica.

La teoría se explica mediante la solución de problemas. En las clases de fundamentos de programación, donde se estudian bifurcaciones y ciclos, simplemente no se puede dar una conferencia útil sobre un solo tema durante una hora completa. Con 15-20 minutos es suficiente para explicar el concepto. Las principales dificultades surgen al realizar las tareas prácticas.
Los profesores principiantes pueden presentar operadores, bifurcaciones, ciclos y matrices en una sola lección. Sin embargo, los estudiantes se enfrentarán al problema de asimilar esta información.
No solo hay que contar el material, sino también asegurarse de que los oyentes lo hayan entendido.

El hecho de que un tema se haya asimilado se determina por cómo el estudiante se enfrenta al trabajo autónomo.
Si el estudiante pudo resolver un problema sobre el tema sin la ayuda del profesor, significa que ha dominado el tema. Para facilitar la autoevaluación, se describe una tabla con casos de prueba para cada tarea. Las tareas tienen un orden bien definido. No se recomienda saltarse tareas. Si la tarea actual es demasiado complicada, es inútil pasar a la siguiente; será aún más difícil. Para que el estudiante pueda afrontar la tarea complicada actual, se le explican algunos métodos a partir del primer problema. De hecho, todo el contenido del tema se reduce a técnicas para superar las dificultades. Los ciclos son, más bien, un efecto secundario.

La primera tarea siempre es un ejemplo. La segunda difiere ligeramente y se realiza 'por cuenta propia' inmediatamente después de la primera bajo la supervisión del profesor. Todas las tareas posteriores están dirigidas a llamar la atención sobre diferentes detalles que pueden causar confusiones.

La explicación del ejemplo es un diálogo en el que el estudiante necesita activar la retropropagación y la validación cruzada para asegurarse de haber comprendido la porción de material.

Seré banal y diré que el primer ejemplo sobre el tema es muy importante. Si hay material para un extenso trabajo autónomo, las omisiones del primer ejemplo pueden ser corregidas. Si no hay nada más que el ejemplo, el estudiante probablemente no dominará el tema.

¿While o for?

Una de las cuestiones controversiales es la elección de la estructura para el ejemplo: while o for. Una vez, un conocido mío, desarrollador práctico sin experiencia en enseñanza, me convenció durante una hora de que el ciclo for es el más fácil de entender. Sus argumentos se reducían a 'todo está claro y organizado'. Sin embargo, la verdadera causa de las dificultades para los auténticos principiantes radica en la idea del ciclo, no en su escritura. Si una persona no comprende esta idea, tendrá problemas con la sintaxis. Tan pronto como la idea es entendida, los problemas con la redacción del código desaparecen.

En mis materiales, el tema de los ciclos sigue al tema de las ramificaciones. La similitud externa entre if y while permite hacer una analogía directa: 'cuando la condición en el encabezado es verdadera, se ejecuta el cuerpo'. La particularidad del ciclo es que el cuerpo se ejecuta varias veces.

Mi segundo argumento es que while requiere menos formato que for. Menos formato significa menos errores tontos con comas y paréntesis omitidos. Los principiantes aún no han desarrollado suficiente atención y minuciosidad para evitar automáticamente los errores de sintaxis.
El tercer argumento es que en muchos buenos libros, while se explica primero.

Si el estudiante puede transformar expresiones fácilmente, se puede hablar de for de manera incidental. Luego el estudiante elegirá lo que más le guste. Sin embargo, si las transformaciones son problemáticas, es mejor no distraer la atención. Primero que el estudiante resuelva todo con while. Cuando haya asimilado el tema de los ciclos, se pueden reescribir las soluciones para trabajar la transformación de while a for.
Los ciclos con condición al final son bastante raros. No pierdo tiempo en ellos en absoluto. Si el estudiante ha dominado las ideas de identificar patrones y transformar expresiones, podrá entenderlo sin mi ayuda.

Al presentar el primer ejemplo a estudiantes avanzados, enfatizo que en el primer ejemplo es importante documentar no solo la solución, sino también toda la cadena de acciones que llevaron al resultado. Los estudiantes perezosos pueden despreciar la escritura y simplemente trasladar el algoritmo final. Hay que convencerlos de que en algún momento se encontrarán con un problema complejo. Para resolverlo, será necesario seguir los pasos como en este ejemplo. Por eso es crucial documentar todas las etapas. En los siguientes problemas, se podrá dejar solo la versión final de la solución.

La idea principal de la automatización es que delegamos al computador la realización del trabajo rutinario en lugar de hacerlo nosotros. Uno de los enfoques básicos es la escritura de bucles. Se utiliza cuando en el programa se escriben varias acciones idénticas y repetitivas de forma consecutiva.

Lo explícito es mejor que lo implícito

Puede parecer una buena idea en el primer ejercicio sobre bucles mostrar en pantalla la misma frase varias veces. Por ejemplo:

¡Hurra, funciona!
¡Hurra, funciona!
¡Hurra, funciona!
¡Hurra, funciona!
¡Hurra, funciona!
¡Hurra, funciona!
¡Hurra, funciona!
¡Hurra, funciona!

Esta opción es mala porque en la salida no se ve el valor del contador. Este es un problema para los principiantes. No deberíamos subestimarlo. Originalmente, esta tarea era la primera, y la tarea sobre la salida de una serie de números en orden ascendente era la segunda. Tenía que introducir términos adicionales como 'bucle N veces' y 'bucle de A a B', que en esencia son lo mismo. Para no crear entidades innecesarias, decidí mostrar solo el ejemplo de salida de una serie de números. A pocos les resulta fácil aprender a mantener un contador en la mente y modelar el comportamiento del programa mentalmente. Algunos estudiantes se encuentran por primera vez con la modelación 'en la mente' precisamente en el tema de bucles.
Después de cierta práctica, asigno la tarea de repetir un texto idéntico para que se resuelva de manera independiente. Si primero se muestra un contador visible y luego uno invisible, los estudiantes tienen menos problemas. A veces, es suficiente con la sugerencia 'no escribas el contador en la pantalla'.

¿Cómo se explica en otros lugares?

En la mayoría de los materiales de aprendizaje en internet, la sintaxis del ciclo se presenta como parte de una 'lección'. Por ejemplo, en developer.mozilla.org (en este momento), junto con el ciclo while se describen varias otras construcciones. Sin embargo, se dan exclusivamente las construcciones mismas en forma de plantillas. Los resultados de su ejecución se describen con palabras, y no hay ilustración. En mi opinión, esta forma de presentar el tema reduce a cero la utilidad de tales materiales. Un estudiante puede copiar el código y ejecutarlo por sí mismo, pero aún necesita un estándar para comparar. ¿Cómo puede saber que el ejemplo se ha reescrito correctamente si no tiene con qué comparar el resultado?
Cuando solo se proporciona una plantilla, sin un ejemplo, se vuelve aún más difícil para el estudiante. ¿Cómo puede saber que los fragmentos de código están colocados correctamente en la plantilla? Se puede intentar escribir de alguna manera, y luego ejecutarlo. Pero si no hay un estándar para comparar el resultado, entonces ejecutar tampoco ayudará.

En el curso de C++ en Intuit, la sintaxis del ciclo está enterrada en la tercera página de la lección 4 sobre el tema 'operadores'. Al explicar la sintaxis de los ciclos, se hace un especial énfasis en el término 'operador'. El término se presenta como un conjunto de hechos como 'símbolo; esto es un operador', '{} es un operador compuesto', 'el cuerpo del ciclo debe ser un operador'. No me gusta este enfoque porque parece ocultar importantes interrelaciones tras un solo término. El análisis del código fuente de un programa en términos a este nivel es necesario para los desarrolladores de compiladores para implementar la especificación del lenguaje, pero de ninguna manera para los estudiantes en una primera aproximación. Los principiantes en programación rara vez tienen la suficiente meticulosidad como para prestar tanta atención a los términos. Rara vez una persona recuerda y entiende nuevas palabras a la primera. Prácticamente nadie puede aplicar correctamente un término que acaba de aprender. Por eso, los estudiantes generan una cantidad de errores como 'escribí while(a<7);{, y el programa no funciona'.
En mi opinión, al principio es mejor enseñar la sintaxis de la construcción inmediatamente con los corchetes. La variante sin corchetes debe explicarse solo si el estudiante plantea una pregunta concreta '¿por qué aquí sin corchetes y funciona?'.

En el libro de Okulov «Fundamentos de la programación» de 2012, la introducción a los ciclos comienza con la plantilla for, luego se dan recomendaciones para su uso, y después se presenta inmediatamente una sección experimental de la clase. Entiendo que el libro fue escrito para esa minoría de alumnos muy talentosos que raramente vienen a mis clases.

En los libros populares siempre se incluye el resultado de fragmentos de código. Por ejemplo, en el libro de Schildt «Java 8. Guía completa» de 2015. Primero se presenta la plantilla, luego un ejemplo de programa y justo después el resultado de su ejecución.

Como ejemplo, consideremos el ciclo while, en el que se realiza una cuenta regresiva
comenzando desde 10, y se imprimen exactamente 10 líneas de ‘tictacs’:

//Продемонстрировать применение оператора цикла while
class While {
    public static void main(String args []) {
        int n = 10;
        while (n > 0) {
            System.out.println("такт " + n);
            n--;
        }
    }
}

Al ejecutarse, este programa muestra diez ‘tictacs’ de la siguiente manera:
táctica 10
táctica 9
táctica 8
táctica 7
táctica 6
táctica 5
táctica 4
táctica 3
táctica 2
táctica 1

El enfoque que describe la plantilla, el ejemplo de programa y el resultado de la ejecución también se utiliza en el libro «JavaScript para niños» y en el curso de js en w3schools.com. El formato de la página web incluso permite hacer este ejemplo interactivo.

En el libro de Stroustrup «Principios y práctica utilizando C++» de 2016, el autor va aún más lejos. Primero se explica qué resultado se debe obtener, y después se muestra el texto del programa. Además, como ejemplo, no se elige simplemente un programa al azar, sino que se ofrece una excursión por la historia. Esto ayuda a captar su atención: ‘Mira, esto no es solo un texto inútil. Ves algo significativo.’

Como ejemplo de iteración, consideremos el primer programa ejecutado en una máquina de programa almacenado (EDSAC). Fue escrito por David Wheeler en el laboratorio de computación de la Universidad de Cambridge (Cambridge University, Inglaterra) el 6 de mayo de 1949. Este programa calcula e imprime una simple lista de cuadrados.
0 0
1 1
2 4
3 9
4 16
...
98 9604
99 9801

Aquí, cada línea contiene un número, seguido del signo de tabulación (‘t’) y el cuadrado de ese número. La versión de este programa en C++ es la siguiente:

//Вычисляем и распечатываем таблицу квадратов чисел 0-99
int main()
{
    int i = 0; // Начинаем с нуля
    while(i < 100){
        cout << i << 't' << square(i) << 'n';
        ++i;
    }
}

Curiosamente, el patrón de sintaxis en este libro no se describe. Stroustrup, en la guía del instructor (la traducción) enfatiza que respeta la inteligencia de sus estudiantes. Tal vez la habilidad de identificar un patrón en varios ejemplos se considera una manifestación de esa inteligencia.

Como lo explico yo mismo

El enfoque de Stroustrup: describir el resultado, luego resolver el problema y, por último, un análisis independiente por parte del estudiante, parece ser el más reflexivo. Por eso decidí tomarlo como base, pero contar sobre un ejemplo menos histórico: el problema de generar un "índice". Este crea un ancla reconocible para poder decir más tarde "recuerda el problema del índice" y para que los estudiantes lo recuerden exactamente. En mi ejemplo intenté anticipar otros dos de los conceptos erróneos más comunes. A continuación, escribiré sobre ellos en más detalle.

En este ejercicio, nos familiarizamos con las técnicas para resolver problemas complejos. La solución inicial debe ser primitiva y sencilla. Luego se puede pensar en cómo mejorar esta solución.
Introducción
Capítulo 1
Capítulo 2
Capítulo 3
Capítulo 4
Capítulo 5
Capítulo 6
Capítulo 7
Conclusión

Según mis observaciones, el enfoque "plantilla-ejemplo-resultado" en diversas combinaciones conduce a que los estudiantes perciban el ciclo como un jeroglífico. Esto se manifiesta en que no entendían por qué escribir la condición, cómo elegir entre i++ e i-- y otras cosas que parecen obvias. Para evitar estos conceptos erróneos, el enfoque para hablar sobre ciclos debe enfatizar el sentido de repetir acciones idénticas y solo luego —su diseño mediante la construcción. Por lo tanto, antes de dar la sintaxis del ciclo, es necesario resolver el problema "de frente". La solución primitiva al problema del índice se ve así:

Console.WriteLine("Introducción");
Console.WriteLine("Capítulo 1");
Console.WriteLine("Capítulo 2");
Console.WriteLine("Capítulo 3");
Console.WriteLine("Capítulo 4");
Console.WriteLine("Capítulo 5");
Console.WriteLine("Capítulo 6");
Console.WriteLine("Capítulo 7");
Console.WriteLine("Conclusión");

¿Cómo se puede mejorar?
Sustituir las acciones repetitivas por un ciclo.
¿Qué acciones se repiten aquí de forma consecutiva y sin cambios?
En este fragmento no hay tales acciones. Sin embargo, los comandos para imprimir la palabra "Capítulo" con el número son muy similares entre sí.
Por lo tanto, el siguiente paso es buscar la diferencia entre los fragmentos. Solo en este ejercicio todo es obvio, luego no se repetirán solo comandos individuales, sino bloques de código de 5 líneas o más. La búsqueda tendrá que hacerse no solo en la lista de comandos, sino también en las estructuras de bifurcación o ciclo.
En el ejemplo, la diferencia entre los comandos está en el número después de la palabra "Capítulo".
Una vez que se haya encontrado la diferencia, es necesario entender la regularidad del cambio. ¿Es el fragmento diferente un número? ¿Aumenta o disminuye constantemente? ¿Cómo cambia el valor del número entre dos comandos uno al lado del otro?
En el ejemplo, el número después de la palabra 'Capítulo' aumenta en pasos de 1. Se ha encontrado una diferencia, se ha identificado un patrón. Ahora se puede reemplazar el fragmento variable por una variable.
Se debe declarar dicha variable antes de la primera de las partes que se repiten. Esta variable suele llamarse i o j, o de forma más extensa. Su valor inicial debe ser igual al primer valor que se muestra en pantalla. En el ejemplo, el primer valor es 1.
¿Qué valor inicial se debe tomar para mostrar la secuencia de números '100, 101, 102, 103, 104, 105'?
En esta secuencia, el primer número es 100.
Después de cada comando de salida, es necesario incrementar el valor de esta variable en 1. Esta unidad es el paso de cambio.
¿Cuál será el paso en la secuencia de números '100, 102, 104, 106'?
En esta secuencia, el paso es 2.
Después de reemplazar el fragmento variable por una variable, el código se verá así:

Console.WriteLine("Introducción");
int i;
i = 0;
Console.WriteLine("Capítulo " + i);
i = i + 1;
Console.WriteLine("Capítulo " + i);
i = i + 1;
Console.WriteLine("Capítulo " + i);
i = i + 1;
Console.WriteLine("Capítulo " + i);
i = i + 1;
Console.WriteLine("Capítulo " + i);
i = i + 1;
Console.WriteLine("Capítulo " + i);
i = i + 1;
Console.WriteLine("Capítulo " + i);
i = i + 1;
Console.WriteLine("Conclusión");

Después de aplicar la técnica 'expresar el patrón como una variable', el código tiene varios grupos de acciones idénticas que se ejecutan una tras otra. Ahora, las acciones repetidas se pueden reemplazar por un bucle.

La secuencia para resolver el problema, donde es necesario usar bucles, consta de las etapas:

  1. Resolver 'de manera directa' con múltiples comandos individuales.
  2. Encontrar un patrón.
  3. Expresar el patrón como una variable.
  4. Formatear en forma de bucle.

A continuación se introducen nuevos términos para que el estudiante no se encuentre en la situación de 'entiendo todo, pero no puedo expresarlo':
— contador: siempre es una variable que se necesita para rastrear la cantidad de pasos del bucle. Generalmente es un número entero, que se compara con un límite.
— paso del contador: descripción del patrón de cambio del contador.
— límite: número o variable con la que se compara el contador para que el algoritmo sea finito. El valor del contador cambia para acercarse al límite.
— cuerpo del bucle: conjunto de comandos que se repetirán. Cuando se dice 'comando escrito dentro del bucle', se refiere precisamente al cuerpo.
— iteración del bucle: ejecución única del cuerpo del bucle.
— condición del ciclo — expresión lógica de la que depende si se ejecutará otra iteración. (Aquí puede haber confusión con las estructuras de ramificación)
Es importante estar preparado para que al principio los estudiantes utilicen los términos incorrectamente. Esto se aplica tanto a los estudiantes fuertes como a los débiles. Establecer un lenguaje común es todo un arte. Ahora lo diré brevemente: hay que plantear la tarea 'destaca el fragmento de código con ' y usar estos términos correctamente en la conversación.
Después de la transformación con el ciclo, se obtiene el fragmento:

Console.WriteLine("Introducción");
int i = 0;
while (i < 7) {
    Console.WriteLine("Capítulo " + i);
    i = i + 1;
}
Console.WriteLine("Conclusión");

La principal confusión

Una confusión popular entre los estudiantes es que colocan dentro de la estructura del ciclo acciones que deben realizarse solo una vez. Por ejemplo, así:

;
int i = 0;
while (i < 7) {
    Console.WriteLine("Introducción")
    Console.WriteLine("Capítulo " + i);
    i = i + 1;
    Console.WriteLine("Conclusión");
}

Los alumnos se encuentran constantemente con este problema, tanto al principio como en tareas más complejas.
Consejo clave en este caso:

¿Cuántas veces se necesita repetir el comando: una vez o muchas?

Los comandos para mostrar las palabras 'Introducción' y 'Conclusión', así como la declaración e inicialización de la variable i, no son como otras acciones repetitivas. Se ejecutan solo una vez, por lo que deben estar fuera del cuerpo del ciclo.

El código debe contener las tres etapas de la solución, para que luego se puedan referir a ellas en caso de dificultades. Los dos primeros casos se pueden comentar para que no molesten.
La atención del estudiante debe centrarse en los siguientes hechos:
— En la condición del ciclo generalmente se compara el contador y el límite. El contador puede cambiar dentro del cuerpo del ciclo, pero el límite no. Para violar esta regla, se necesitan razones de peso.
— Los comandos para mostrar las palabras 'Introducción' y 'Conclusión' están fuera del cuerpo del ciclo. Debemos ejecutarlos 1 vez. 'Introducción' — antes de repetir las acciones, 'Conclusión' — después.
Al consolidar este tema, en el dominio de los próximos, así como al lidiar con dificultades, es útil incluso para los estudiantes fuertes plantear la pregunta: '¿Y esta acción cuántas veces hay que realizarla? ¿Una o muchas?'.

Desarrollo de habilidades adicionales

En el proceso de estudio de los ciclos, los estudiantes también practican la habilidad de diagnóstico y resolución de problemas. Para llevar a cabo el diagnóstico, el estudiante necesita imaginar el resultado deseado y compararlo con el resultado real. Las acciones para corregir dependen de la diferencia entre ellos.
Dado que los estudiantes en esta etapa todavía tienen una noción vaga del "resultado deseado", pueden orientarse en función de los datos de prueba. Por lo general, nadie en este punto entiende qué podría salir mal y cómo lidiar con ello. Por eso, hago que apunten en su cuaderno una descripción de los problemas típicos y varias maneras de resolverlos. La elección de la más adecuada es tarea del propio estudiante.
Se necesita el registro para preguntar: "¿se logró lo que se esperaba?", "¿Cuál de estas situaciones se ha dado ahora?", "¿Ayudó la solución aplicada?".

  1. La cantidad de acciones es 1 menos o más de lo esperado. Métodos de solución:
    — aumentar el valor inicial del contador en 1.
    — reemplazar el operador de comparación estricta () por uno no estricto (=).
    — cambiar el valor del límite en 1.
  2. Las acciones en el ciclo se ejecutan sin parar, infinitamente. Métodos de solución:
    — agregar un comando para modificar el contador, si falta.
    — corregir el comando para modificar el contador de modo que su valor se acerque al límite.
    — eliminar el comando de modificación del límite, si está en el cuerpo del ciclo.
  3. La cantidad de acciones en el ciclo es más de 1 menos o más de lo esperado. La acción en el ciclo no se ejecutó ni una vez. Primero, es necesario averiguar los valores reales de las variables inmediatamente antes del inicio del ciclo. Métodos de solución:
    — cambiar el valor inicial del límite
    — cambiar el valor inicial del contador

Generalmente, el problema 3 está relacionado con el uso de la variable incorrecta o con no reiniciar el contador.

Después de esta explicación, el estudiante aún puede tener diversos malentendidos sobre el funcionamiento de los ciclos.
Para disipar los más comunes, propongo tareas:

  1. En la que el límite, el valor inicial del contador o el paso del contador son introducidos por el usuario.
  2. En la que se necesita utilizar el valor del contador en alguna expresión aritmética. Preferiblemente, que el contador esté en el sub-expresion o en el denominador, de modo que la diferencia sea no lineal.
  3. En el que el valor del contador no se muestra en la pantalla durante el ciclo. Por ejemplo, mostrar una cantidad necesaria de fragmentos de texto idénticos o dibujar una figura usando gráficos tortuga.
  4. En el que primero se deben realizar unas acciones repetitivas y luego otras.
  5. En el que se deben realizar otras acciones antes y después de las repetitivas.

Para cada tarea, es necesario proporcionar datos de prueba y el resultado esperado.

Para entender cuán rápido se puede avanzar, es necesario leer las condiciones de estas tareas y preguntar: «¿en qué se diferencian del ejemplo?», «¿qué hay que cambiar en el ejemplo para resolverlas?». Si el estudiante responde de manera reflexiva, entonces debe resolver al menos una en la clase, y las demás en casa por su cuenta. Si la solución es exitosa, se puede comenzar con la explicación sobre las condiciones dentro de los ciclos.
Si hay dificultades con la resolución autónoma, se debe trabajar todo en clase. Para que la solución del problema no se asemeje a dibujar un búho, recomiendo primero resolver el problema de manera no universal. Es decir, de tal manera que la solución pase la primera prueba y no utilice la estructura del ciclo. Luego, se aplicarán transformaciones para lograr la universalidad de la solución.

Ciclos y bifurcaciones

En mi opinión, es útil tratar el tema «ciclos dentro de bifurcaciones» por separado. Así, luego se podrá ver la diferencia entre verificar la condición varias veces y hacerlo una sola vez.
Las tareas para fijar el conocimiento serán sobre la salida de números del A al B, que son introducidos por el usuario:
— siempre en orden ascendente.
— en orden ascendente o descendente dependiendo de los valores de A y B.

El tema «bifurcaciones dentro de ciclos» debe abordarse solo después de que el estudiante haya dominado las técnicas: «sustitución de patrones por variables» y "sustitución de acciones repetitivas por ciclos".
La principal razón para aplicar bifurcaciones dentro de ciclos son las anomalías en el patrón. En medio, se interrumpe dependiendo de los datos de entrada.
Para aquellos estudiantes que pueden buscar soluciones combinando técnicas simples, basta con decir «las bifurcaciones se pueden escribir dentro de los ciclos» y dar una tarea «como ejemplo» completamente para solución autónoma.
Tarea de ejemplo:

El usuario introduce un número X. Mostrar en columna los números del 0 al 9 y colocar el signo ‘+’ junto al número que es igual a X.

Si se ha introducido 00+
1
2
3
4
5
6
7
8
9

Si se ingresó 60
1
2
3
4
5
6+
7
8
9

Si se ingresó 90
1
2
3
4
5
6
7
8
9+

Si se ingresó 7770
1
2
3
4
5
6
7
8
9

Si la explicación breve no es suficiente para escribir con un ciclo, entonces se debe lograr una solución universal para la misma tarea sin ciclo.
Obtendrá una de dos opciones:
Deseado

string temp;
temp = Console.ReadLine();
int x;
x = int.Parse(temp);
if (x==0) {
    Console.WriteLine(0 + "+");
} else {
    Console.WriteLine(0);
}
if (x==1) {
    Console.WriteLine(1 + "+");
} else {
    Console.WriteLine(1);
}
if (x==2) {
    Console.WriteLine(2 + "+");
} else {
    Console.WriteLine(2);
}
if (x==3) {
    Console.WriteLine(3 + "+");
} else {
    Console.WriteLine(3);
}
if (x==4) {
    Console.WriteLine(4 + "+");
} else {
    Console.WriteLine(4);
}
if (x==5) {
    Console.WriteLine(5 + "+");
} else {
    Console.WriteLine(5);
}
if (x==6) {
    Console.WriteLine(6 + "+");
} else {
    Console.WriteLine(6);
}
if (x==7) {
    Console.WriteLine(7 + "+");
} else {
    Console.WriteLine(7);
}
if (x==8) {
    Console.WriteLine(8 + "+");
} else {
    Console.WriteLine(8);
}
if (x==9) {
    Console.WriteLine(9 + "+");
} else {
    Console.WriteLine(9);
}

Posible

string temp;
temp = Console.ReadLine();
int x;
x = int.Parse(temp);
if (x==0) {
    Console.WriteLine("0+n1n2n3n4n5n6n7n8n9");
}
if (x==1) {
    Console.WriteLine("0n1+n2n3n4n5n6n7n8n9");
}
if (x==2) {
    Console.WriteLine("0n1n2+n3n4n5n6n7n8n9");
}
if (x==3) {
    Console.WriteLine("0n1n2n3+n4n5n6n7n8n9");
}
if (x==4) {
    Console.WriteLine("0n1n2n3n4+n5n6n7n8n9");
}
if (x==5) {
    Console.WriteLine("0n1n2n3n4n5+n6n7n8n9");
}
if (x==6) {
    Console.WriteLine("0n1n2n3n4n5n6+n7n8n9");
}
if (x==7) {
    Console.WriteLine("0n1n2n3n4n5n6n7+n8n9");
}
if (x==8) {
    Console.WriteLine("0n1n2n3n4n5n6n7n8+n9");
}
if (x==9) {
    Console.WriteLine("0n1n2n3n4n5n6n7n8n9+");
}

Un problema similar lo doy con anticipación, durante el estudio del tema sobre ramificaciones.
Si el estudiante obtuvo una opción 'posible', debe explicarse que para el mismo problema puede haber múltiples soluciones. Sin embargo, estas difieren en su resistencia a los cambios de requisitos. Pregunte: "¿Cuántos lugares en el código necesitarían ser corregidos si tuviéramos que agregar otro número?" En la opción 'posible' sería necesario agregar otra ramificación y escribir el nuevo número en 10 lugares más. En la 'deseada' solo es suficiente añadir una ramificación.
Plantee la tarea de reproducir la opción 'deseada', luego encuentre el patrón en el código, realice el reemplazo de la variable y escriba el ciclo.
Si tiene una idea sobre cómo resolver este problema sin un ciclo de otra manera, por favor escríbalo en los comentarios.

Ciclos dentro de ciclos

En este tema, es importante prestar atención a lo siguiente:
— los contadores del ciclo interno y externo deben ser diferentes variables.
— el contador del ciclo interno debe reiniciarse muchas veces (es decir, en el cuerpo del ciclo externo).
En las tareas de salida de texto, no se puede escribir una letra en varias líneas y luego escribir la siguiente. Primero hay que mostrar todas las letras de la primera línea, luego todas las letras de la segunda, y así sucesivamente.

La explicación del tema sobre ciclos dentro de ciclos es mejor comenzar explicando la importancia de reiniciar el contador.
Tarea de ejemplo:

El usuario introduce dos números: R y T. Se deben mostrar dos líneas de caracteres "#". En la primera línea debe haber R caracteres, y en la segunda T caracteres. Si alguno de los números es negativo, se debe mostrar un mensaje de error.

R=5, T=11#####
###########

R=20, T=3####################
###

R=-1, T=6El valor de R debe ser no negativo.

R=6, T=-2El valor de T debe ser no negativo.

Es evidente que este problema también tiene al menos dos variantes de solución.
Deseado

string temp;
int R;
int T;
temp = Console.ReadLine();
R = int.Parse(temp);
temp = Console.ReadLine();
T = int.Parse(temp);
int i = 0;
while (i < R)
{
    Console.Write("#");
    i = i + 1;
}
Console.WriteLine();
i = 0;
while (i < T)
{
    Console.Write("#");
    i = i + 1;
}

Posible №1

string temp;
int R;
int T;
temp = Console.ReadLine();
R = int.Parse(temp);
temp = Console.ReadLine();
T = int.Parse(temp);
int i = 0;
while (i < R)
{
    Console.Write("#");
    i = i + 1;
}
Console.WriteLine();
int j = 0;
j = 0;
while (j < T)
{
    Console.Write("#");
    j = j + 1;
}

La diferencia es que en la solución "posible" se utilizó una segunda variable para mostrar la segunda línea. Es necesario insistir en el uso de la misma variable para ambos ciclos. Se puede argumentar que una solución con un solo contador para dos ciclos ilustrará el término "reinicio del contador". Comprender este término es necesario para resolver problemas posteriores. Como compromiso, se pueden mantener ambas soluciones del problema.

Un problema típico al utilizar una variable contador para dos ciclos se manifiesta así:
R=5, T=11#####
######

La cantidad de caracteres en la segunda línea no corresponde al valor de T. Si se necesita ayuda con este problema, se debe "plantar" en el resumen sobre los problemas típicos con los ciclos. Este es el síntoma №3. Se diagnostica si se añade la salida del valor del contador justo antes del segundo ciclo. Se corrige reiniciando. Pero es mejor no contar esto de inmediato. El estudiante debe intentar formular al menos una hipótesis.

Por supuesto, también hay otra variante de solución. Pero nunca la he visto en los estudiantes. En la etapa de estudio de los ciclos, hablar de ello distraerá la atención. Se puede volver a ello más tarde, al estudiar las funciones de manipulación de cadenas.
Posible №2

cadena temp;
int R;
int T;
temp = Console.ReadLine();
R = int.Parse(temp);
temp = Console.ReadLine();
T = int.Parse(temp);
Console.WriteLine(new String('#', R));
Console.WriteLine(new String('#', T));

La siguiente tarea obligatoria:

Imprima en pantalla los números del 0 al 9. Cada número debe estar en su propia línea. La cantidad de números en la línea (W) se introduce desde el teclado.

W=10
1
2
3
4
5
6
7
8
9

W=100000000000
1111111111
2222222222
3333333333
4444444444
5555555555
6666666666
7777777777
8888888888
9999999999

Si el estudiante ha dominado el método de reemplazo de variables, lo hará bastante rápido. El posible problema será de nuevo la inicialización de la variable. Si no logra hacer la conversión, significa que se ha apresurado y necesita resolver problemas más simples.

Gracias por su atención. Den me gusta, suscríbanse al canal.

P.D. Si encontró errores tipográficos o errores en el texto, por favor háganmelo saber. Puede hacerlo seleccionando parte del texto y presionando en Mac «⌘ + Enter», y en teclados clásicos «Ctrl / Enter», o a través de mensajes personales. Si estas opciones no están disponibles, escriba sobre los errores en los comentarios. ¡Gracias!

Solo los usuarios registrados pueden participar en la encuesta. Inicie sesión, por favor.

Encuesta para lectores sin karma

  • 20,0%Enseño profesionalmente, +12

  • 10,0%Enseño profesionalmente, -11

  • 70,0%No enseño, +17

  • 0,0%No enseño, -10

  • 0,0%Otro0

10 usuarios votaron. 5 usuarios se abstuvieron.

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster