• Documentación

Proyecto 1: Snek

Requisitos de Conocimiento

Para realizar este proyecto ustedes tienen que tener claros algunos conceptos, de lo contrario será bastante difícil e incómodo empezar a trabajar. Les recomendamos que antes de empezar estén totalmente seguros que dominan al 100% los siguientes puntos:

  • Operaciones aritméticas con signo y sin signo en C.
  • Type casting en C.
  • Control de flujo en C (switch, if, etc).
  • Funciones en C.
  • Entender qué son las estructuras (struct) en C.
  • Uso correcto de printf.
  • Uso correcto del heap (malloc, free, etc).
  • Uso correcto de archivos (fopen, fgetc, fclose, fseek, etc).

Si creen que no tienen claro alguno de estos temas al 100%, por favor no duden en ir a consultar los libros y material correspondiente del curso, por ejemplo K&R, es indispensable. En Lecturas Recomendadas pueden encontrar algunas lecturas que tocan los puntos antes mencionados y otras cosas que también les pueden servir, nunca está demás tener un poco más de información.

Lecturas Recomendadas

  • K&R: Capitulos del 1-6


Introducción

Bienvenidos al primer proyecto de CC3! En este proyecto ustedes van a ganar un poco más de experiencia programando en C, creando un juego de Snake (Culebrita) (para aquellos que todavía tuvieron un legendario Nokia 3410). Si no estan familiarizados con el juego, pueden probar una versión online aquí.

Todo el contenido visto hasta el primer parcial se va a usar en este proyecto, por lo que es importante que sepan que es lo que están haciendo y por qué lo están haciendo.

Preparación

Antes de comenzar asegúrense de que hayan leído y comprendido todas las instrucciones del proyecto de principio a fin. Si tienen alguna pregunta pueden consultar la sección de preguntas frecuentes para ver si ya ha sido resuelta, de lo contrario por favor diríjanse a Telegram y pregunten de forma directa o en general.

Para comenzar con el proyecto, primero tienen que tener todos los archivos base, estos se encuentran aquí. Tienen permitido trabajar en parejas o de forma individual, por lo que al aceptar la asignación les preguntará si desean crear un grupo nuevo o unirse a uno ya existente. Si crean un grupo nuevo, ingresen un nombre que represente al grupo y que no esté ya en los grupos existentes.

Si desean unirse a un grupo ya creado, tienen que buscar el nombre del grupo y pulsar el botón que dice join

Tienen que tener mucho cuidado al unirse a un grupo ya existente, ya que esto no se puede cambiar después, además lo consideraremos como PLAGIO si lo realizan de manera incorrecta, ya que al hacer esto pueden tener acceso al repositorio del otro miembro del grupo.

Ya sea que se unan o creen un nuevo grupo, al finalizar el proceso les creará automáticamente un repositorio con una extensión que termina con su nombre de grupo. Ya habiendo hecho todo eso, pueden ejecutar los siguientes comandos abriendo una terminal (CTRL + T):

git clone <link del repositorio>
NOTA: Tienen que reemplazar <link del repositorio> con el link del repositorio que se creó.

Resumen Conceptual de Snake

El juego de Snake es un juego de arcade clásico que consiste en controlar una serpiente que se mueve por una pantalla y que tiene que comer frutas para crecer. El objetivo del juego es crecer lo más grande posible sin chocar con las paredes o con la propia serpiente. El juego termina cuando la serpiente choca con una pared o con su propio cuerpo (o con otra serpiente en multijugador).

Snakes

A snake game can be represented by a grid of characters. The grid contains walls, fruits, and one or more snakes. An example of a game is shown below:

Un juego de Snake puede ser representado por una cuadrícula de caracteres. La cuadrícula contiene paredes, frutas, y una o más serpientes. Un ejemplo de un juego se muestra a continuación

##############
#            #
#    dv      #
#     v   #  #
#     v   #  #
#   s >>D #  #
#   v     #  #
# *A<  *  #  #
#            #
##############

La cuadrícula tiene los siguientes caracteres especiales:

  • # denota una pared.
  • (espacio) denota un espacio vacío.
  • * denota una fruta.
  • wasd denota la cola de una serpiente.
  • ^<v> denota el cuerpo de una serpiente.
  • WASD denota la cabeza de una serpiente.
  • x denota la cabeza de una serpiente que ha muerto.

Cada caracter de la serpiente le dice a ustedes qué dirección está tomando la serpiente en ese momento:

  • w, W, o ^ denota arriba
  • a, A, o < denota izquierda
  • s, S, o v denota abajo
  • d, D, o > denota derecha

En cada paso de tiempo, cada serpiente se mueve de acuerdo con las siguientes reglas:

  • Cada serpiente se mueve un paso en la dirección de su cabeza.
  • Si la cabeza choca con el cuerpo de una serpiente o con una pared, la serpiente muere y deja de moverse. Cuando una serpiente muere, la cabeza se reemplaza con una x.
  • Si la cabeza se mueve a una fruta, la serpiente come la fruta y crece en 1 unidad de longitud. Cada vez que se consume una fruta, se genera una nueva fruta en el tablero.

En el ejemplo de arriba, después de un paso de tiempo, el tablero se verá así:

##############
#         *  #
#     s      #
#     v   #  #
#     v   #  #
#   s >>>D#  #
#   v     #  #
# A<<  *  #  #
#            #
##############

Después de otro paso de tiempo, el tablero se verá así:

##############
#         *  #
#     s      #
#     v   #  #
#     v   #  #
#     >>>x#  #
#   s     #  #
#A<<<  *  #  #
#            #
##############

Se garantiza que las serpientes tengan una longitud inicial de 3, y que no se superpongan en el tablero.

Enumerando las serpientes

Cada serpiente en el tablero está numerada dependiendo de la posición de su cola, en el orden en que las colas aparecen en el archivo (de arriba hacia abajo, luego de izquierda a derecha). Por ejemplo, consideren el siguiente tablero con cuatro serpientes:

#############
#  s  d>>D  #
#  v   A<a  #
#  S    W   #
#       ^   #
#       w   #
#############

La serpiente 0 es la serpiente con cola s, la serpiente 1 tiene cola d, la serpiente 2 tiene cola a y la serpiente 3 tiene cola w.

Una vez que las serpientes están numeradas desde sus posiciones iniciales, el numerado de las serpientes no cambia durante todo el juego.

Tablero

Un tablero de juego es una cuadrícula de caracteres, no necesariamente rectangular. Aquí hay un ejemplo de un tablero no rectangular:

##############
#            #######
#####             ##
#   #             ##
#####             ######
#                 ##   #
#                 ######
#                 ##
#                  #
#      #####       #
########   #########

Tengan en cuenta que cada fila puede tener un número diferente de caracteres, pero comenzará y terminará con una pared (#). También pueden asumir que el tablero es un espacio cerrado, por lo que las serpientes no pueden viajar infinitamente lejos en ninguna dirección.

Estructura del Proyecto

.
├── LICENSE
├── Makefile
├── README.md
├── src
│   ├── asserts.c
│   ├── asserts.h
│   ├── custom_tests.c
│   ├── interactive_snake.c
│   ├── snake.c
│   ├── snake_utils.c
│   ├── snake_utils.h
│   ├── state.c
│   ├── state.h
│   └── unit_tests.c
├── tests
└── tools

Los únicos archivos que pueden modificar son:

  • snake.c: Este el archivo que contiene la funcion main para correr su juego.
  • state.c: Este el archivo donde estara toda la logica del juego.
  • custom_tests.c: Este el archivo que tendra sus pruebas.

Ustedes NO pueden crear otros archivos ni crear archivos de cabecera .h. Si necesitan agregar funciones de ayuda, por favor colóquenlas en los archivos C correspondientes (state.c, snake.c). Si ustedes no siguen estas instrucciones, obtendrán 0 como nota aunque su proyecto corra perfectamente en su computadora.

Otros archivos que necesitan consultar detenidamente para entender el proyecto:

  • snake_utils.h: Este archivo contiene funciones de ayuda para el proyecto.
  • snake_utils.c: Este archivo contiene las implementaciones de las funciones de ayuda para el proyecto.
  • state.h: Este archivo contiene la definición de la estructura state y snake y las funciones que se pueden utilizar para manipularla.
  • asserts.c: Este archivo contiene las funciones de ayuda para realizar las pruebas unitarias.
  • asserts.h: Este archivo contiene las definiciones de las funciones de ayuda para realizar las pruebas unitarias.

Archivos que no es necesario que los revisen, pero si son curiosos:

  • unit_tests.c: Este archivo contiene las pruebas unitarias que se corren con el comando make run-unit-tests.
  • interactive_snake.c: Este archivo contiene el código para correr el juego en modo interactivo.

Estructuras del Juego en C

El juego de serpientes en C va a estar representado por dos estructuras de datos: game_state_t y snake_t.

La estructura game_state_t

Un juego de serpientes se almacena en memoria en una estructura de datos game_state_t. La estructura contiene los siguientes campos:

  • unsigned int num_rows: El número de filas en el tablero de juego.
  • char ** board: El tablero de juego en memoria. Cada elemento del arreglo board es un puntero a un arreglo de caracteres que contiene una fila del tablero.
  • unsigned int num_snakes: El número de serpientes en el tablero.
  • snake_t *snakes: Un arreglo de estructuras snake_t.

La estructura snake_t

La estructura snake_t contiene los siguientes campos:

  • unsigned int tail_row: La fila de la cola de la serpiente.
  • unsigned int tail_col: La columna de la cola de la serpiente.
  • unsigned int head_row: La fila de la cabeza de la serpiente.
  • unsigned int head_col: La columna de la cabeza de la serpiente.
  • bool live: true si la serpiente está viva, y false si la serpiente está muerta.

Por favor no modifiquen las definiciones de las estructuras provistas. Ustedes solo necesitan modificar state.c, snake.c y custom_tests.c en este proyecto.

Tarea 1: create_default_state

Implement the create_default_state function in state.c. This function should create a default snake game in memory with the following starting state (which you can hardcode), and return a pointer to the newly created game_state_t struct.

Implementar la función create_default_state en state.c. Esta función debe crear un juego de serpientes predeterminado en memoria con el siguiente estado inicial (que puede quemar), y devolver un puntero a la nueva estructura game_state_t creada.

####################
#                  #
# d>D    *         #
#                  #
#                  #
#                  #
#                  #
#                  #
#                  #
#                  #
#                  #
#                  #
#                  #
#                  #
#                  #
#                  #
#                  #
####################

Consejos

  • El tablero tiene 18 filas, y cada fila tiene 20 columnas. La fruta está en la fila 2, columna 9 (indexada desde cero). La cola está en la fila 2, columna 2, y la cabeza está en la fila 2, columna 4.
  • ¿En qué parte de la memoria (código, estática, pila, heap) deben almacenar el nuevo juego?
  • strcpy puede ser útil.

Pruebas Unitarias

Pueden correr make run-unit-tests para verificar su implementación para cada tarea. Tengan en cuenta que las pruebas unitarias no son exhaustivas, y pasarlas no garantiza que su implementación esté completamente correcta. Sin embargo, deberían ser útiles para ayudarlos a comenzar a depurar.

Si su implementación no funciona, es hora de comenzar a depurar. Pueden agregar declaraciones printf en su código para imprimir variables durante la ejecución del código, y luego ejecutar make run-unit-tests nuevamente para ver la salida de sus declaraciones de impresión.

Tambien, pueden usar make debug-unit-tests para comenzar CGDB. En CGDB, pueden establecer un punto de interrupción en su propio código (sugerencia: consulten la tarjeta de referencia de GDB para saber cómo establecer un punto de interrupción en un archivo diferente). Luego, escriba run o r para iniciar el programa, y se detendrá en su punto de interrupción.

Consejo: Si ven "Segmentation fault (core dumped)", esto significa que su programa se bloqueó. Una forma de comenzar a depurar es comenzar CGDB, ejecutar el programa sin puntos de interrupción y luego escribir backtrace o bt para ver en qué línea de código el programa se bloqueó.

Tarea 2: free_state

Implementar la función free_state en state.c. Esta función debe liberar toda la memoria asignada para el estado dado, incluidas todas las estructuras de serpiente y todos los contenidos de map->board. ¿Se recuerdan del ejemplo que vimos en clase? ...

Pruebas Unitarias

Para probar si liberamos correctamente la memoria para el estado del juego, ejecuten make valgrind-test-free-state para verificar si hay fugas de memoria. Si no hay fugas, entonces ha pasado la prueba unitaria para esta tarea.

Tarea 3: print_board

Implementar la función print_board en state.c. Esta función debe imprimir el tablero de juego dado en el puntero de archivo dado.

Consejos

  • fprintf les ayudará a imprimir caracteres y / o cadenas en un puntero de archivo dado.

Pruebas Unitarias

Corran make run-unit-tests y make debug-unit-tests para probar y depurar, como antes.

Si su función se ejecuta con éxito (no se bloquea ni se termina), pero no imprime la salida correcta, el tablero que imprimió estará en unit-test-out.snk. Un tablero impreso correctamente debe coincidir con el tablero predeterminado de la tarea 1.

Tarea 4: update_state

Implementar la función update_state en state.c. Esta función debe mover las serpientes un paso de tiempo de acuerdo con las reglas del juego.

Son libres de implementar esta función como quieran, pero si lo desean, pueden trabajar a través de esta tarea implementando las funciones auxiliares que les hemos proporcionado. Las funciones auxiliares no se califican; para esta tarea, solo verificaremos que update_state esté correcto.

Tarea 4.1: Funciones Auxiliares

Les hemos proporcionado las siguientes definiciones de funciones auxiliares que pueden implementar. Estas funciones son completamente independientes de cualquier tablero de juego o serpiente; solo toman un solo carácter y devuelven información sobre ese carácter.

  • bool is_tail(char c): Devuelve verdadero si c es parte de la cola de la serpiente. La cola de la serpiente consta de estos caracteres: wasd. Devuelve falso de lo contrario.
  • bool is_head(char c): Devuelve verdadero si c es parte de la cabeza de la serpiente. La cabeza de la serpiente consta de estos caracteres: WASDx. Devuelve falso de lo contrario.
  • bool is_snake(char c): Devuelve verdadero si c es parte de la serpiente. La serpiente consta de estos caracteres: wasd^<v>WASDx. Devuelve falso de lo contrario.
  • char body_to_tail(char c): Convierte un carácter en el cuerpo de la serpiente (^<v>) en el carácter que representa la cola de la serpiente (wasd). La salida puede ser indefinida para caracteres que no son el cuerpo de una serpiente.
  • char head_to_body(char c): Convierte un carácter en la cabeza de la serpiente (WASD) en el carácter que representa el cuerpo de la serpiente (^<v>). La salida puede ser indefinida para caracteres que no son la cabeza de una serpiente.
  • unsigned int get_next_row(unsigned int cur_row, char c): Devuelve cur_row + 1 si c es v o s o S. Devuelve cur_row - 1 si c es ^ o w o W. Devuelve cur_row de lo contrario.
  • unsigned int get_next_col(unsigned int cur_col, char c): Devuelve cur_col + 1 si c es > o d o D. Devuelve cur_col - 1 si c es < o a o A. Devuelve cur_col de lo contrario.

Pruebas unitarias no se proporcionan para estas funciones auxiliares, por lo que tendrán que escribir sus propias pruebas en custom_tests.c para asegurarse de que estas estén funcionando como se espera. ¡Asegúrense de que estas pruebas prueben exhaustivamente sus funciones auxiliares!

Cuando escriban una prueba unitaria, la función de prueba debe devolver falso si la prueba falla y verdadero si la prueba pasa. Pueden usar printf para imprimir declaraciones de depuración. Algunas de las funciones auxiliares de aserción en asserts.h pueden ser útiles.

Una vez que hayan escrito sus propias pruebas unitarias, pueden ejecutarlas con make run-custom-tests y make debug-custom-tests.

Tarea 4.2: next_square

Implementar la función auxiliar next_square en state.c. Esta función devuelve el carácter en la celda en la que se está moviendo la serpiente dada. Esta función no debe modificar nada en el juego almacenado en memoria.

Como ejemplo, consideren el siguiente tablero:

##############
#            #
#            #
#            #
#   d>D*     #
#            #
#       s    #
#       v    #
#       S    #
##############

Asumiendo que state es un puntero a este estado del juego, entonces next_square(state, 0) debería devolver *, porque la cabeza de la serpiente 0 se está moviendo a una celda con _ en ella. De manera similar, next_square(state, 1) debería devolver # para la serpiente 1.

Las funciones auxiliares que escribieron anteriormente pueden ser útiles para esta función (y el resto de esta tarea también). También echen un vistazo a get_board_at y set_board_at, que son funciones auxiliares que escribimos para ustedes.

Utilicen make run-unit-tests y make debug-unit-tests para ejecutar las pruebas unitarias proporcionadas. También pueden usar p print_board(state, stdout) para imprimir todo su tablero mientras depuran en cgdb.

Tarea 4.3: update_head

Implementar la función update_head en state.c. Esta función actualizará la cabeza de la serpiente.

Recuerden que necesitarán actualizar la cabeza tanto en el tablero de juego como en la estructura de serpiente. En el tablero de juego, agreguen un carácter donde la serpiente se está moviendo. En la estructura de serpiente, actualicen la fila y la columna de la cabeza.

Como ejemplo, consideren el siguiente tablero:

##############
#   d>D      #
#        *   #
#        W   #
#        ^   #
#        ^   #
#        w   #
#            #
#            #
##############

Asumiendo que state es un puntero a este estado del juego, entonces update_head(state, 0) moverá la cabeza de la serpiente 0, dejando todas las otras serpientes sin cambios. En la estructura de serpiente correspondiente a la serpiente 0, el valor head_col debería actualizarse de 6 a 7, y el valor head_row debería mantenerse sin cambios en 1. El nuevo tablero se verá así:

##############
#   d>>D     #
#        *   #
#        W   #
#        ^   #
#        ^   #
#        w   #
#            #
#            #
##############

Noten que esta función ignora la comida, las paredes y los cuerpos de las serpientes cuando mueve la cabeza.

Usen make run-unit-tests y make debug-unit-tests para ejecutar las pruebas unitarias proporcionadas. También pueden usar p print_board(state, stdout) para imprimir todo su tablero mientras depuran en cgdb.

Tarea 4.4: update_tail

Implementar la función update_tail en state.c. Esta función actualizará la cola de la serpiente.

Recurden que necesitarán actualizar la cola tanto en el tablero de juego como en la estructura de serpiente. En el tablero de juego, borren el carácter actual de la cola, y cambien la nueva cola de un carácter de cuerpo (^<v>) a un carácter de cola (wasd). En la estructura de serpiente, actualicen la fila y la columna de la cola.

Como ejemplo, consideren el siguiente tablero:

##############
#   d>D      #
#        *   #
#        W   #
#        ^   #
#        ^   #
#        w   #
#            #
#            #
##############

Asumiendo que state es un puntero a este estado del juego, entonces update_tail(state, 1) moverá la cola de la serpiente 1, dejando todas las otras serpientes sin cambios. En la estructura de serpiente correspondiente a la serpiente 1, el valor tail_row debería actualizarse de 6 a 5, y el valor tail_col debería mantenerse sin cambios en 9. El nuevo tablero se verá así:

##############
#   d>D      #
#        *   #
#        W   #
#        ^   #
#        w   #
#            #
#            #
#            #
##############

Usen make run-unit-tests y make debug-unit-tests para ejecutar las pruebas unitarias proporcionadas. También pueden usar p print_board(state, stdout) para imprimir todo su tablero mientras depuran en cgdb.

Tarea 4.5: update_state

Usen las funciones auxiliares que crearon para implementar update_state en state.c.

Como recordatorio, las reglas para mover una serpiente son las siguientes:

  • Cada serpiente se mueve un paso en la dirección de su cabeza.
  • Si la cabeza choca con el cuerpo de una serpiente o con una pared, la serpiente muere y deja de moverse. Cuando una serpiente muere, la cabeza se reemplaza con una x.
  • Si la cabeza se mueve a una fruta, la serpiente come la fruta y crece en 1 unidad de longitud. (Pueden implementar crecer en 1 unidad actualizando la cabeza sin actualizar la cola.) Cada vez que se consume una fruta, se genera una nueva fruta en el tablero.

El argumento int (*add_food)(game_state_t *state) es un puntero a función, lo que significa que add_food es un puntero al código de memoria. El código al que add_food apunta es una función que toma game_state_t *state como argumento y devuelve un int. Pueden llamar a esta función con add_food(x), reemplazando x con su argumento, para agregar una fruta al tablero.

Usen make run-unit-tests y make debug-unit-tests para ejecutar las pruebas unitarias proporcionadas. También pueden usar p print_board(state, stdout) para imprimir todo su tablero mientras depuran en cgdb.

Tarea 5: load_board

Implementar la función load_board en state.c. Esta función leerá un tablero de juego de un archivo en memoria.

Recuerden que cada fila del tablero de juego puede tener una cantidad diferente de columnas. Su implementación debe ser eficiente en memoria y no debe asignar más memoria de la necesaria para almacenar el tablero. Por ejemplo, si una fila tiene 3 caracteres de largo, no deberían asignar 100 bytes de espacio para esa fila. Recomendamos encarecidamente no usar getline ya que no es eficiente en memoria y probablemente fallará las pruebas del autograder.

La tarea 5 y 6 combinadas crearán una estructura game_state_t en memoria con todos sus campos configurados. En esta tarea, configuren num_snakes a 0 y el arreglo snakes a NULL, ya que estos serán inicializados en la tarea 6.

Usen make run-unit-tests y make debug-unit-tests para ejecutar las pruebas unitarias proporcionadas. También pueden usar p print_board(state, stdout) para imprimir todo su tablero mientras depuran en cgdb.

Tarea 6: initialize_snake

Implementen la función initialize_snake en state.c. Esta función tomará un tablero de juego y creará el arreglo de estructuras snake_t.

Son libres de implementar esta función como quieran, pero si quieren, pueden trabajar en esta tarea implementando la función auxiliar que les proporcionamos.

Tarea 6.1: find_head

Implementar la función find_head en state.c. Dada una estructura snake_t con la fila y columna de la cola rellenadas, esta función rastrea a través del tablero para encontrar la fila y columna de la cabeza, y rellena la fila y columna de la cabeza en la estructura.

Como ejemplo, consideren el siguiente tablero:

##############
#            #
#        *   #
#            #
#   d>v      #
#     v      #
#  W  v      #
#  ^<<<      #
#            #
##############

Asumiendo que state es un puntero a este estado del juego, entonces find_head(state, 0) llenará los campos head_row y head_col de la estructura de serpiente 0 con 6 y 3, respectivamente.

Usen make run-unit-tests y make debug-unit-tests para ejecutar las pruebas unitarias proporcionadas. También pueden usar p print_board(state, stdout) para imprimir todo su tablero mientras depuran en cgdb.

Tarea 6.2: initialize_snake

Usando find_head, implementen la función initialize_snake en state.c. Pueden asumir que el estado pasado a esta función es el resultado de llamar a load_board, pero no pueden asumir que el arreglo snakes esté definido. Esto significa que los campos relacionados con el tablero ya están llenos, y solo necesitan llenar num_snakes y crear el arreglo snakes.

Pueden asumir que todas las serpientes en el tablero comienzan vivas.

Usen make run-unit-tests y make debug-unit-tests para ejecutar las pruebas unitarias proporcionadas. También pueden usar p print_board(state, stdout) para imprimir todo su tablero mientras depuran en cgdb.

Tarea 7: main

Usando las funciones que implementaron en todas las tareas anteriores, llenen los espacios en blanco en snake.c. Cada vez que se ejecute el programa snake.c, el tablero se actualizará en un paso de tiempo.

To test your full implementation, run make run-integration-tests.

Prueben su implementación completa ejecutando make run-integration-tests.

To debug your implementation, run cgdb --args ./snake -i tests/TESTNAME-in.snk -o tests/TESTNAME-out.snk. To check for memory leaks or out-of-bounds reads/writes, you can run valgrind ./snake -i tests/TESTNAME-in.snk -o tests/TESTNAME-out.snk. Replace TESTNAME with one of the test names in the tests folder:

Para depurar su implementación, ejecuten cgdb --args ./snake -i tests/TESTNAME-in.snk -o tests/TESTNAME-out.snk. Para verificar fugas de memoria o lecturas / escrituras fuera de los límites, pueden ejecutar valgrind ./snake -i tests/TESTNAME-in.snk -o tests/TESTNAME-out.snk. Reemplacen TESTNAME con uno de los nombres de prueba en la carpeta tests:

  • 01-simple
  • 02-direction
  • 03-tail
  • 04-food
  • 05-wall
  • 06-small
  • 07-medium
  • 08-multisnake
  • 09-everything
  • 10-filled
  • 11-manyclose
  • 12-corner
  • 13-sus
  • 14-orochi
  • 15-hydra
  • 16-huge
  • 17-wide
  • 18-tall
  • 19-101-127
  • 20-long-line
  • 21-bigL

Tambien pueden correr make run-nonexistent-input-file-test para asegurarse que su programa salga con el código de error -1 si el archivo de entrada no existe.

Solo por diversión: Juegen snake

Ahora pueden jugar un juego con el código que escribieron ejecutando make interactive-snake seguido de ./interactive-snake. ¡Usen las teclas wasd para controlar su serpiente!

Para acelerar o ralentizar el juego, pueden ejecutar ./interactive-snake -d 0.5 (reemplazando 0.5 con el número de segundos entre pasos de tiempo). Durante el juego, también pueden presionar ] para moverse más rápido y [ para moverse más lentamente.

Entrega y Calificación

Por favor subir el link de su repositorio al GES (AMBOS miembros del grupo, si están trabajando en pareja). Siempre es necesario que suban su repositorio al GES, incluso si no completaron todos los ejercicios, de lo contrario la nota será de 0 puntos.

La calificación de este proyecto será de 0 a 100 puntos, donde 100 puntos es la calificación máxima. La calificación se basará en la cantidad de ejercicios completados. Si tienen alguna duda sobre la calificación, por favor envíen un correo a los auxiliares.