Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,20 @@ co.eci.snake
### 1) Análisis de concurrencia

- Explica **cómo** el código usa hilos para dar autonomía a cada serpiente.

Respuesta:

Exíte una clase llamada SnakeRunner que implementa runnable, eso quiere decir que la función de la clase
es decir qué tarea debe hacer el hilo. Esta clase tiene 5 atributos: `snake`, `board`, `baseSleepMs`, `turboSleepMs` y `turboTicks`.

A continuación se mostrará lo que hace el hilo al iniciar:
1. Verifíca que el hilo no esté interrumpido.
2. Si no lo está entonces puede que la serpiente cambie de dirección en el tablero.
3. Si la serpiente choca contra un obstáculo, esta cambia de dirección de forma aleatoria.
4. Si la serpiente come un turbo entonces el tiempo en el que está dormido el hilo será menor por lo que la serpiente se mueve más rápido, pero con el tiempo vuelve a su velocidad normal.

Cabe resaltar que cada serpiente corre su método run() en paralelo con los demás.

- **Identifica** y documenta en **`el reporte de laboratorio`**:
- Posibles **condiciones de carrera**.
- **Colecciones** o estructuras **no seguras** en contexto concurrente.
Expand Down Expand Up @@ -148,3 +162,55 @@ Incluye compilación y ejecución de pruebas JUnit. Si tienes análisis estátic
Este laboratorio es una adaptación modernizada del ejercicio **SnakeRace** de ARSW. El enunciado de actividades se conserva para mantener los objetivos pedagógicos del curso.

**Base construida por el Ing. Javier Toquica.**




## REPORTE DE LABORATORIO
### 1) Análisis de concurrencia
**Cómo los hilos dan autonimía a cada serpiente**

Exíte una clase llamada SnakeRunner que implementa runnable, eso quiere decir que la función de la clase
es decir qué tarea debe hacer el hilo. Esta clase tiene 5 atributos: `snake`, `board`, `baseSleepMs`, `turboSleepMs` y `turboTicks`.

A continuación se mostrará lo que hace el hilo al iniciar:
1. Verifíca que el hilo no esté interrumpido.
2. Si no lo está entonces puede que la serpiente cambie de dirección en el tablero.
3. Si la serpiente choca contra un obstáculo, esta cambia de dirección de forma aleatoria.
4. Si la serpiente come un turbo entonces el tiempo en el que está dormido el hilo será menor por lo que la serpiente se mueve más rápido, pero con el tiempo vuelve a su velocidad normal.

Cabe resaltar que cada serpiente corre su método run() en paralelo con los demás.

**Condiciones carrera**

Hay tres candidatos posibles: `res`, `turboTicks` y `board.step(snake)`

- res: es una variable local dentro del hilo asi que cada hilo tiene un res diferente por lo que no sería una condición
carrera.
- turboTicks: en cada interación turboTicks está disminuyendo, así que esta si sería una variable mutable. El problema es que
la varaible no se comparte en cada hilo, es una variable "privada" de cada hilo.
- board.step(snake): puede ser una condición de carrera porque todas las serpientes, cada una manejada con un hilo, interactuan con un mismo tablero.

- La clase **snake**: La clase es accedida concurrentemente por múltiples threads sin sincronización.

**Colecciones o estructuras no seguras para hilos**

- HashSet: La clase Board usa esta colección para almacenar `obstáculos`, `ratones` y `turbos`.

¿Cuál es el inconveniente?

El problema es que HashSet no es una colección segura para hilos. Cuando varias serpientes interactua al mismo tiempo con estas colecciones, pueden ocurrir condiciones de carrera. En el caso de los ratones, si una serpiente se come un ratón, el ratón debe ser
eliminado del Hash y además se debe poner un nuevo ratón aleatoriamente en el tablero y se debe agregar a la colección. Si otra serpiente modifíca la colección al mismo tiempo, puede que halla un resultado incosistente.

- HashMap: la clase Board utiliza esta estructura de datos para guardar `teleports`.

HashMap tampoco es thread-safe. Si no se protegiera adecuadamente, accesos concurrentes podrían causar inconsistencias en los pares de teletransporte.


**Sincronización innecesaria**
![Captura de pantalla 2026-02-05 113609.png](src/img/Captura%20de%20pantalla%202026-02-05%20113609.png)

En la imagen podemos ver que estos métodos utilizan la palabra clave `synchronized`. Aunque estos métodos pueden ser llamados desde distintos hilos, no interactúan directamente con la lógica de
movimiento de las serpientes ni modifican el estado del tablero, por lo que su sincronización resulta innecesaria.


Binary file added src/img/Captura de pantalla 2026-02-05 113609.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/main/java/co/eci/snake/core/Board.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public Board(int width, int height) {
public int width() { return width; }
public int height() { return height; }

public synchronized Set<Position> mice() { return new HashSet<>(mice); }
public synchronized Set<Position> mice() {return new HashSet<>(mice); }
public synchronized Set<Position> obstacles() { return new HashSet<>(obstacles); }
public synchronized Set<Position> turbo() { return new HashSet<>(turbo); }
public synchronized Map<Position, Position> teleports() { return new HashMap<>(teleports); }
Expand Down
10 changes: 8 additions & 2 deletions src/main/java/co/eci/snake/core/Direction.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
package co.eci.snake.core;

public enum Direction { UP(0,-1), DOWN(0,1), LEFT(-1,0), RIGHT(1,0);
public final int dx, dy; Direction(int dx, int dy){ this.dx=dx; this.dy=dy; } }
public enum Direction {
UP(0,-1),
DOWN(0,1),
LEFT(-1,0),
RIGHT(1,0);
public final int dx, dy; Direction(int dx, int dy){
this.dx=dx; this.dy=dy; }
}