From e1643f2de4e930d02534a7aa920552a82ba763b2 Mon Sep 17 00:00:00 2001 From: jpconsuegra Date: Sun, 11 Feb 2024 11:36:47 -0500 Subject: [PATCH] Add Lecture 03 (+Code) --- .../2024/03-arrays-and-for/code/Program.cs | 293 ++++++++++++++++++ .../2024/03-arrays-and-for/code/src.csproj | 10 + .../2024/03-arrays-and-for/code/words.txt | 30 ++ .../2024/03-arrays-and-for/lecture-03.md | 202 ++++++++++++ 4 files changed, 535 insertions(+) create mode 100755 conferences/2024/03-arrays-and-for/code/Program.cs create mode 100755 conferences/2024/03-arrays-and-for/code/src.csproj create mode 100755 conferences/2024/03-arrays-and-for/code/words.txt create mode 100644 conferences/2024/03-arrays-and-for/lecture-03.md diff --git a/conferences/2024/03-arrays-and-for/code/Program.cs b/conferences/2024/03-arrays-and-for/code/Program.cs new file mode 100755 index 0000000..c115b75 --- /dev/null +++ b/conferences/2024/03-arrays-and-for/code/Program.cs @@ -0,0 +1,293 @@ +using System.IO; +using System; + +class Program +{ + static void Main() + { + Console.Title = "☠️ Ahorcado v1.0"; + + while (true) + { + Console.Clear(); + PrintMenu(); + + ConsoleKey key = Console.ReadKey(true).Key; + + switch (key) + { + case ConsoleKey.N: + case ConsoleKey.Enter: + NewGame(); + break; + case ConsoleKey.P: + ShowWords(); + break; + case ConsoleKey.S: + case ConsoleKey.Escape: + return; + default: + break; + } + } + } + + static void PrintMenu() + { + Console.ForegroundColor = ConsoleColor.Cyan; + Console.WriteLine("Bienvenido al Ahorcado ☠️"); + Console.WriteLine(); + Console.ForegroundColor = ConsoleColor.White; + Console.WriteLine("Presione una tecla para continuar..."); + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine("[N]uevo juego"); + Console.WriteLine("[P]alabras"); + Console.WriteLine("[S]alir"); + Console.WriteLine(); + Console.ForegroundColor = ConsoleColor.Gray; + + } + + static void NewGame() + { + string word = GetRandomWord(); + bool[] marks = InitializeMarks(word); + + int lives = 5; + int hints = 3; + + while (true) + { + Console.Clear(); + + PrintInfo(lives, hints); + PrintWord(word, marks); + + Console.WriteLine("\n ... Presione una tecla para jugar, [?] para hint, ESCAPE para salir ..."); + + ConsoleKeyInfo key = Console.ReadKey(true); + + if (key.Key == ConsoleKey.Escape) + { + return; + } + + if (key.KeyChar == '?') + { + if (hints > 0) + { + GiveHint(word, marks); + hints -= 1; + } + } + + else + { + if (!Reveal(word, marks, key.KeyChar)) + { + lives -= 1; + } + } + + if (Complete(marks)) + { + Win(word); + break; + } + + if (lives == 0) + { + GameOver(word); + break; + } + } + } + + static void Win(string word) + { + Console.Clear(); + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine("🥳 Has ganado!"); + PrintFinalWord(word); + } + + static void GameOver(string word) + { + Console.Clear(); + Console.ForegroundColor = ConsoleColor.DarkRed; + Console.WriteLine("☠️ Has perdido!"); + Console.ForegroundColor = ConsoleColor.White; + PrintFinalWord(word); + } + static void PrintFinalWord(string word) + { + Console.ForegroundColor = ConsoleColor.White; + Console.Write("La palabra era "); + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine(word); + Console.ForegroundColor = ConsoleColor.Gray; + Console.WriteLine("\n ... Presiona ENTER para volver al menú ..."); + Console.ReadLine(); + } + + static string GetRandomWord() + { + string[] words = LoadWords(); + Random r = new Random(); + return words[r.Next(words.Length)]; + } + + static string[] LoadWords() + { + StreamReader reader = new StreamReader("words.txt"); + string[] words = new string[30]; + + for (int i = 0; i < words.Length; i++) + { + words[i] = reader.ReadLine()!; + } + + return words; + } + + static bool[] InitializeMarks(string word) + { + bool[] marks = new bool[word.Length]; + + for (int i = 0; i < word.Length; i++) + { + if (word[i] == ' ') + { + marks[i] = true; + } + else + { + marks[i] = false; + } + } + + return marks; + } + + static void PrintInfo(int lives, int hints) + { + for (int i = 0; i < lives; i++) + { + Console.Write("❤️ "); + } + + Console.Write(" "); + + for (int i = 0; i < hints; i++) + { + Console.Write("❔"); + } + + Console.WriteLine("\n"); + } + + static void PrintWord(string word, bool[] marks) + { + Console.ForegroundColor = ConsoleColor.White; + + for (int i = 0; i < marks.Length; i++) + { + if (marks[i]) + { + Console.Write(word[i]); + } + else + { + Console.Write('*'); + } + } + + Console.WriteLine(); + Console.ForegroundColor = ConsoleColor.Gray; + } + + static void GiveHint(string word, bool[] marks) + { + Random r = new Random(); + + while (true) + { + // Buscamos una posición aleatoria en la palabra + int pos = r.Next(word.Length); + + // Si ya está marcada, probamos de nuevo + if (marks[pos]) + { + continue; + } + + // De lo contrario, la marcamos y salimos + marks[pos] = true; + break; + } + } + + static bool Reveal(string word, bool[] marks, char c) + { + bool found = false; + + for (int i = 0; i < word.Length; i++) + { + // Por cada letra, si la letra no está marcada ya, y coincide con el caracter c + // entonces la marcamos + if (!marks[i] && word[i] == c) + { + marks[i] = true; + found = true; + } + } + + // Esto será true si y solo si alguna letra nueva fue marcada + return found; + } + + static bool Complete(bool[] marks) + { + for (int i = 0; i < marks.Length; i++) + { + // Si al menos una letra no está marcada, ya se sabe que no está terminado el juego. + if (!marks[i]) + { + return false; + } + } + + // Si llegamos aquí, es porque todas las letras estaban marcadas, verdad? + return true; + } + + static void ShowWords() + { + Console.Clear(); + Console.ForegroundColor = ConsoleColor.Cyan; + string[] words = LoadWords(); + + foreach (string word in words) + { + Console.WriteLine(word); + } + + Console.ForegroundColor = ConsoleColor.Gray; + Console.WriteLine("\n ... Presione ENTER para volver al menú ..."); + Console.ReadLine(); + } +} + +// EJERCICIOS +// ========== + +// 1 - Modifique GiveHint para en vez de revelar una sola letra, revele todas las posiciones con esa letra aleatoria +// Hint: reutilice los métodos que ya están implementados. + +// 2 - Modifique la aplicación para que al terminar una partida: +// 2.1 - Pregunte si quieres continuar jugando y escoja una nueva palabra siguiendo con las mismas vidas y hints. Adicione una nueva vida (hasta 5) cada vez que ganes. +// 2.2 - Vaya acumulando una puntuación que será igual a Vidas * Longitud cada vez que ganes. Al perder (o decidir no seguir jugando), te diga la puntuación final. +// 2.3 - Garantice que aunque las palabras salgan aleatoriamente, nunca salga la misma dos veces en una partida (el juego termina al salir todas). + +// 3 - Modifique el método LoadWords para que cargue todas las palabras que hay en el archivo words.txt sin necesidad de definir explícitamente la cantidad. +// Hint: Puede necesitar leer el archivo más de una vez. \ No newline at end of file diff --git a/conferences/2024/03-arrays-and-for/code/src.csproj b/conferences/2024/03-arrays-and-for/code/src.csproj new file mode 100755 index 0000000..40c60dd --- /dev/null +++ b/conferences/2024/03-arrays-and-for/code/src.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/conferences/2024/03-arrays-and-for/code/words.txt b/conferences/2024/03-arrays-and-for/code/words.txt new file mode 100755 index 0000000..080be88 --- /dev/null +++ b/conferences/2024/03-arrays-and-for/code/words.txt @@ -0,0 +1,30 @@ +algoritmo +array +artificial +asignacion +axioma +ciclo +clase +complejo +computadora +contradiccion +deduccion +hipotesis +induccion +inteligencia +linux +matriz +memoria +metodo +microprocesador +modus ponens +polinomio +recursividad +referencia +robot +shakespeare +tautologia +teorema +tipo +turing +variable \ No newline at end of file diff --git a/conferences/2024/03-arrays-and-for/lecture-03.md b/conferences/2024/03-arrays-and-for/lecture-03.md new file mode 100644 index 0000000..ea21cb3 --- /dev/null +++ b/conferences/2024/03-arrays-and-for/lecture-03.md @@ -0,0 +1,202 @@ +# Conferencia #3 + +## Arrays + +¿Por qué son necesarios? + +Agrupar determinada cantidad de elementos en una colección, +de forma que el procesamiento sobre cada valor se puede +escribir en función de un índice, y no necesariamente +de uno en uno. + +> Por ejemplo, saber cuáles de los nombres de mis amigos son palíndromos. +> + La cantidad de nombres lo sé en compilación: No va a cambiar de ejecución en ejecución. +> + Sin embargo, no quiero escribir manualmente el llamado a cada uno, así que los guardo en un array y con un ciclo (``for`` hago los llamados, y los ``Console.WriteLine()``. + +Ahora, en el momento que se escribe el programa, hay casos en los que ni siquiera se sabe cuántos valores se quieren analizar. + +> Por ejemplo, los números primos en un intervalo. +Como el tope del intervalo no se conoce en compilación, +sino que depende de la ejecución, entonces el programa no puede saber cuanta memoria necesita reservar. + +Hasta ahora estuvieron esquivando esa limitación. + Cómo??? +> * Contando solamente. +> * Dando los resultados poco a poco + (``Console.WriteLine``). +> * Usando ``strings`` para guardar información. +> - Son arrays de ``char``. +> - Pero inmutables: las operaciones + sobre ``string`` devuelven un nuevo ``string``. + **NO MODIFICAN EL STRING QUE SE TENÍA**. + +### Sintaxis de *C#*: +- Array de tipo T: + ```csharp + T[] // <- de esta forma se habla del tipo, como mismo int, string, etc. + ``` + Ejemplos: + ```csharp + int[] numbers; + bool[] selected; + string[] names; + ``` + + > Seguridad de tipos: + > - Solo se pueden guardar en el array objetos de determinado tipo. + > - Pero gracias a eso, el compilador nos puede ayudar chequeando que las operaciones que realicemos sobre los elementos del array sean válidas. + > - En cualquier caso, si se quiere un array que guarde todo tipo de objetos, se puede declarar un array de ``objects``. + > * Todo valor es ``object``, así que se puede guardar correctamente en el array. + + > ¿Qué se puede hacer con un tipo??? + > - Usarlo como tipo de variable. + > - Como tipo de parámetro, valor de retorno, etc. + +- Crear una instancia / objeto: + + A partir de valores constantes: + ``` + new T[] { n0, n1, ..., nl} + ``` + > En la asignación a una variable se puede omitir + el ``new T[]`` + + Ejemplo: + ```csharp + int[] numbers = new int[] {1, 2, 3}; + ``` + + > Con esa sintaxis no es suficiente: si el + compilador puede inferir el tamaño del array en + compilación es porque la cantidad de elementos se + sabe desde el momento en que se escribió el + código, por lo que entonces bastaría con declarar + una variable para cada elemento. + + + Reservando espacio dinámicamente (a partir de un entero ``n``): + ```csharp + new T[n] + ``` + > En ambos casos el tamaño del array se mantiene fijo + desde su creación. + > - **CONSECUENCIA:** SI NO QUEDA ESPACIO PARA UN NUEVO + ELEMENTO HAY QUE CREAR UNA COPIA DE MAYOR TAMAÑO. + +- Operaciones básicas sobre arrays. + + ``(...).Length:`` para saber la capacidad máxima de elementos. + * Decimos máxima porque "cuánto espacio está siendo utilizado" es una consideración que hace el programador del problema. + + ``(...)[i]``: indexar, acceder a la posición ``i`` del array. + * Para guardar un valor si está a la izquierda de una asignación. + * O para recuperar el valor en otro caso. + * Qué valores son válidos para `i`?? + - ``0 <= i < a.Length`` + - ``a[0]``: primer elemento. + - ``a[a.Length - 1]``: último elemento. + +### Consideraciones importantes: + +- Qué ocurre al crear un array??? + + Se reserva espacio para cada posible elemento. + + Cada uno se inicializa en el valor por defecto del tipo. + * numéricos en 0. + * strings en ``null``. + * bools en ``false``. + +- Qué ocurre al asignar un array a una variable??? + ```csharp + int[] a = {1, 2, 3, 4, 5}; + ``` + + Si las variables son cajitas, cuán grande tengo que + hacer la caja para guardar un array? `100`??? `1000`??? + todo lo que pueda??? + - No puede ser en función del tamaño del array: porque puede cambiar el array que almacena. + + Los arrays son tipos por referencia (como muchos otros, + por ejemplo: `Stopwatch`, `DateTime`, `string`, etc). + + Las referencias tienen un tamaño fijo: en las cajitas se guarda un papel que tiene anotada la dirección del estante en el que está guardado el objeto. + + Y por tanto, la asignación: + ```csharp + int[] b = a; + ``` + causa que tanto ``a`` como ``b`` guarden una dirección al mismo objeto (al mismo array). + + Qué consecuencia tiene esto??? Qué pasa con uno si se + modifica el otro??? + - Se modifican ambos, porque ambos referencian al mismo objeto. + + Y qué pasa ahora si se añade: + ```csharp + int[] c = b; + c = {6, 7, 8, 9, 10}; + ``` + * Se modifican ``a`` y ``b``??? + - NO! + * Si modifico ``c`` cambia el array al + que apuntan ``a`` y ``b``??? + - NO! + - O sea, "guardar 11 en la 1ra posición de c" + causa que: + ``a -> {11, 2, 3, 4, 5}``, + ``b -> {11, 2, 3, 4, 5}``, + ``c -> {11, 7, 8, 9, 10}`` ??? + - NO! + + > **OJO:** La sintaxis para "guardar 11 en la 1ra posición de c" es ``c[0] = 11``. + +- Y qué pasa cuando un array se pasa como parámetro??? + + Tras retornar se mantiene modificado?? + - Sí! + + Puedo cambiar el que me pasaron a una nueva referencia?? + - Con los mecanismos que conocen actualmente NO. +- Pueden crearse arrays de arrays??? + + Sí!!! + + ``T[]`` es un tipo ``T'``, así que un array de ``T'`` + sería ``T'[]``, concretamente ``T[][]``. + + Y cuánto espacio se reserva entonces en la creación + entonces??? Se reservaría el espacio de los subarrays?? + * No!!! + * El tamaño de los subarrays no tiene si quiera que + ser el mismo. + * Incluso pueden cambiar sin cambiar el array que lo + contiene (como mismo pasa con entero, etc). + * El espacio que se almacena es el de la referencia ;-) + + Y con qué valor se inicializa??? + * ``null``, como todos los objetos por referencia. + +## Ciclos "For" + +Otra sintaxis que provee C# para repetir un conjunto de instrucciones ("hacer un ciclo"). +Está diseñado para que quede indicado, explícitamente, cual es el valor que irá cambiando (y cómo lo hará) a lo largo de las iteraciones, el cual servirá para evaluar las instrucciones y determinar cuándo el ciclo debe terminar. + +Son especialmente útiles para "iterar" sobre los valores que almacena un array. + +### Sintaxis de **for**. + +```csharp +for(; ; ) { + ; +} +``` + +- ``, `` y `` son opcionales. +- `` es una expresión que avalúa a `bool`. +- ``, `` son instrucciones (ejemplo: asignación, incremento, decremento, llamado a métodos, instanciación de objetos). +- `for( ; ; ) { //... }` es equivalente a `while( true ) { //... }` + +#### Ejemplo + +```csharp +int names = { "Juan", "Pablo", "Consuegra", "Ayala" }; +for (int i = 0; i < names.Length; i++) { + Console.WriteLine(names[i]); +} +``` + +En general, el ciclo `for` es equivalente al siguiente ciclo `while` (aunque las instrucciones de control de flujo como `continue` tiene un comportamiento diferente): + +```csharp +; +while () { + ; + ; +} +``` + +- El comportamiento de **break** y **return** es el mismo que con los ciclos `while`. +- El **continue** pasa por hacer `` y luego es que evalúa ``. \ No newline at end of file