TP5 - Correction

ppompeani_cars_mutex1.c

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void clear_screen() { fprintf(stdout, "\e[1;1H\e[2J"); }

void refresh() { fflush(stdout); }

void move_cursor(unsigned int y, unsigned int x) {
  fprintf(stdout, "\e[%d;%dH", y, x);
}

void print_n(char *s, unsigned int repeat) {
  while (repeat > 0) {
    fprintf(stdout, "%s", s);
    repeat--;
  }
}

const unsigned int ROAD_SIZE = 40;

pthread_mutex_t STDOUT_MUTEX;

void game_init() {
  srand(time(NULL));

  pthread_mutex_init(&STDOUT_MUTEX, NULL);

  clear_screen();

  move_cursor(1, 1);
  print_n("-", ROAD_SIZE);

  move_cursor(3, 1);
  print_n("- ", ROAD_SIZE / 2);

  move_cursor(5, 1);
  print_n("-", ROAD_SIZE);

  move_cursor(1, ROAD_SIZE + 1);

  refresh();
}

void game_close() {
  clear_screen();
  refresh();
}

void *car_thread(void *param) {
  int car = *((int *)param);

  int car_color = rand() % 6;

  int increment, x, y;
  char logo;

  if (car == 0) {
    increment = -1;
    x = ROAD_SIZE;
    y = 2;
    logo = '<';
  } else {
    increment = 1;
    x = 1;
    y = 4;
    logo = '>';
  }

  for (int i = 1; i < ROAD_SIZE; i++) {
    pthread_mutex_lock(&STDOUT_MUTEX);
    {
      // We reset old position
      move_cursor(y, x);
      fputc(' ', stdout);
      // We move to new position
      x += increment;
      move_cursor(y, x);
      fputc(logo, stdout);
      move_cursor(1, ROAD_SIZE + 1);
      refresh();
    }
    pthread_mutex_unlock(&STDOUT_MUTEX);
    usleep(50000 + rand() % 10000);
  }

  pthread_mutex_lock(&STDOUT_MUTEX);
  {
    move_cursor(y, x);
    fputc(' ', stdout);
    move_cursor(1, ROAD_SIZE + 1);
    refresh();
  }
  pthread_mutex_unlock(&STDOUT_MUTEX);

  return NULL;
}

int main(int argc, char **argv) {
  game_init();

  pthread_t last;

  char input;

  int car_arg;

  do {
    input = fgetc(stdin);
    switch (input) {
    case 'j':
      car_arg = 1;
      pthread_create(&last, NULL, car_thread, &car_arg);
      break;

    case 'k':
      car_arg = 0;
      pthread_create(&last, NULL, car_thread, &car_arg);
      break;
    }
  } while (input != 'q');

  pthread_join(last, NULL);

  game_close();
}

ppompeani_cars_mutex2.c

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>

void clear_screen() { fprintf(stdout, "\e[1;1H\e[2J"); }

void refresh() { fflush(stdout); }

void move_cursor(unsigned int y, unsigned int x) {
  fprintf(stdout, "\e[%d;%dH", y, x);
}

void print_n(char *s, unsigned int repeat) {
  while (repeat > 0) {
    fprintf(stdout, "%s", s);
    repeat--;
  }
}

// Amélioration Couleur
const unsigned int COLOR_RESET = 0, COLOR_RED = 1, COLOR_GREEN = 2,
                   COLOR_YELLOW = 3, COLOR_BLUE = 4, COLOR_PURPLE = 5,
                   COLOR_LIGHTBLUE = 6;

void color(int color) {
  if (color == COLOR_RESET) {
    fprintf(stdout, "\e[0m");
  } else {
    fprintf(stdout, "\e[3%cm", color + '0');
  }
}

unsigned int ROAD_SIZE, BLOCK_SIZE, LEFT_LIMIT, RIGHT_LIMIT;

pthread_mutex_t ROAD_MUTEX;

// Amélioration Input
struct termios OLD_TERMINAL_PARAMS;

void game_init() {
  BLOCK_SIZE = ROAD_SIZE / 10 + 2;
  LEFT_LIMIT = ROAD_SIZE / 2 - BLOCK_SIZE;
  RIGHT_LIMIT = ROAD_SIZE / 2 + BLOCK_SIZE;

  pthread_mutex_init(&ROAD_MUTEX, NULL);

  srand(time(NULL));

  clear_screen();

  // Première partie de la ligne 1
  move_cursor(1, 1);
  print_n("-", LEFT_LIMIT);

  // Deuxième partie de la ligne 1
  move_cursor(1, RIGHT_LIMIT);
  print_n("-", LEFT_LIMIT + 1);

  // Première partie de la ligne 2
  move_cursor(3, 1);
  print_n("- ", LEFT_LIMIT / 2 - 1);

  // Deuxième partie de la ligne 2
  move_cursor(3, LEFT_LIMIT + 2);
  print_n("-", BLOCK_SIZE * 2 - 3);

  // Troisième partie de la ligne 2
  move_cursor(3, RIGHT_LIMIT + 2);
  print_n("- ", LEFT_LIMIT / 2);

  // Ligne 3
  move_cursor(5, 1);
  print_n("-", ROAD_SIZE);

  move_cursor(1, LEFT_LIMIT);
  fprintf(stdout, "\\");

  move_cursor(1, RIGHT_LIMIT);
  fprintf(stdout, "/");

  move_cursor(2, LEFT_LIMIT + 1);
  fprintf(stdout, "\\");

  move_cursor(2, RIGHT_LIMIT - 1);
  fprintf(stdout, "/");

  // Amélioration Messages
  move_cursor(7, 1);
  fprintf(stdout, "Press j to spawn a car riding to the east");
  move_cursor(8, 1);
  fprintf(stdout, "Press k to spawn a car riding to the west");
  move_cursor(9, 1);
  fprintf(stdout, "Press q to quit");

  move_cursor(1, ROAD_SIZE + 1);

  // Amélioration Input
  struct termios new_terminal_params;
  // Store old params
  tcgetattr(STDIN_FILENO, &OLD_TERMINAL_PARAMS);
  // Copy params
  new_terminal_params = OLD_TERMINAL_PARAMS;
  // Change params
  // Remove ICANON flag (wait for enter) and ECHO flag (print stdin)
  new_terminal_params.c_lflag &= ~(ICANON | ECHO);
  // Apply params
  tcsetattr(STDIN_FILENO, TCSANOW, &new_terminal_params);

  refresh();
}

void game_close() {
  clear_screen();

  // Amélioration Input
  // Restore old params
  tcsetattr(STDIN_FILENO, TCSANOW, &OLD_TERMINAL_PARAMS);

  refresh();
}

// Amélioration Compteur
// Extra: une couleur différente à chaque fois que le compteur change
unsigned int CAR_COUNTER = 0;
void *counter_thread(void *param) {
  int counter_color = 0;
  int last_count = CAR_COUNTER;
  while (1) {
    if (CAR_COUNTER != last_count) {
      counter_color = (counter_color + 1) % 6;
      last_count = CAR_COUNTER;
      move_cursor(3, ROAD_SIZE + 2);
      color(counter_color);
      fprintf(stdout, "%d", CAR_COUNTER);
    }
    sleep(1);
  }
  return NULL;
}

void *car_thread(void *param) {
  int car = *((int *)param);

  unsigned int car_color = rand() % 6;

  unsigned int increment, x, y, base_sleep = 80000;
  char logo;

  if (car == 0) {
    increment = -1;
    x = ROAD_SIZE + 1;
    y = 2;
    logo = '<';
  } else {
    increment = 1;
    x = 0;
    y = 4;
    logo = '>';
  }

  // Amélioration Compteur
  CAR_COUNTER++;

  for (int i = 1; i < ROAD_SIZE; i++) {
    // We check if we can move
    if ((x == LEFT_LIMIT - 1 && y == 4) || (x == RIGHT_LIMIT + 1 && y == 2)) {
      move_cursor(11, 1);
      fprintf(stdout, "locking!");
      pthread_mutex_lock(&ROAD_MUTEX);
    }
    // We reset old position
    move_cursor(y, x);
    fputc(' ', stdout);
    // We move to new position
    if (car == 0) {
      if (x == RIGHT_LIMIT || x == RIGHT_LIMIT + 1) {
        y++;
        base_sleep = 110000;
      } else if (x == LEFT_LIMIT || x == LEFT_LIMIT + 1) {
        y--;
        base_sleep = 110000;
      } else {
        base_sleep = 80000;
      }
    }
    x += increment;
    move_cursor(y, x);
    // Amélioration Couleur
    color(car_color);
    fputc(logo, stdout);
    move_cursor(1, ROAD_SIZE + 1);
    refresh();
    // We release the lock if we're out of the critical part of the road
    if ((x == RIGHT_LIMIT + 1 && y == 4) || (x == LEFT_LIMIT - 1 && y == 2)) {
      move_cursor(11, 1);
      fprintf(stdout, "unlocking!");
      pthread_mutex_unlock(&ROAD_MUTEX);
    }
    usleep(base_sleep + rand() % 10000);
  }

  move_cursor(y, x);
  fputc(' ', stdout);
  move_cursor(1, ROAD_SIZE + 1);
  refresh();

  return NULL;
}

// Amélioration Messages
void *error_thread(void *param) {
  color(0);
  move_cursor(11, 1);
  fprintf(stdout, "Unrecognised input.");
  refresh();

  sleep(2);

  color(0);
  move_cursor(11, 1);
  fprintf(stdout, "                   ");
  refresh();
  return NULL;
}

int main(int argc, char **argv) {

  {
    char buf[10];
    printf("Quel taille doit faire la route ? (défaut 40, min 20) → ");
    fgets(buf, 10, stdin);
    int size = atoi(buf);
    if (size < 20) {
      ROAD_SIZE = 40;
    } else {
      ROAD_SIZE = size;
    }
  }

  game_init();

  pthread_t last, unused_thread_id;

  // Amélioration Compteur
  pthread_create(&unused_thread_id, NULL, counter_thread, NULL);

  char input;

  int car_arg;

  do {
    input = fgetc(stdin);
    switch (input) {
    case 'j':
    case 'k':
      if (input == 'j') {
        car_arg = 1;
      } else {
        car_arg = 0;
      }

      pthread_create(&last, NULL, car_thread, &car_arg);

      color(0);
      move_cursor(11, 1);
      fprintf(stdout, "                   ");
      refresh();
      break;
    case 'q':
      // Amélioration Messages
      color(0);
      move_cursor(11, 1);
      fprintf(stdout, "Quitting.          ");
      refresh();
      break;
    default:
      // Amélioration Messages
      pthread_create(&unused_thread_id, NULL, error_thread, NULL);
    }
  } while (input != 'q');

  pthread_join(last, NULL);

  game_close();
}

ppompeani_cars_sem.c

#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>

void clear_screen() { fprintf(stdout, "\e[1;1H\e[2J"); }

void refresh() { fflush(stdout); }

void move_cursor(unsigned int y, unsigned int x) {
  fprintf(stdout, "\e[%d;%dH", y, x);
}

void print_n(char *s, unsigned int repeat) {
  while (repeat > 0) {
    fprintf(stdout, "%s", s);
    repeat--;
  }
}

// Amélioration Couleur
const unsigned int COLOR_RESET = 0, COLOR_RED = 1, COLOR_GREEN = 2,
                   COLOR_YELLOW = 3, COLOR_BLUE = 4, COLOR_PURPLE = 5,
                   COLOR_LIGHTBLUE = 6;

void color(int color) {
  if (color == COLOR_RESET) {
    fprintf(stdout, "\e[0m");
  } else {
    fprintf(stdout, "\e[3%cm", color + '0');
  }
}

unsigned int ROAD_SIZE, BLOCK_SIZE, LEFT_LIMIT, RIGHT_LIMIT;

sem_t SEMS[2];

// Amélioration Input
struct termios OLD_TERMINAL_PARAMS;

void game_init() {
  BLOCK_SIZE = ROAD_SIZE / 10 + 2;
  LEFT_LIMIT = ROAD_SIZE / 2 - BLOCK_SIZE;
  RIGHT_LIMIT = ROAD_SIZE / 2 + BLOCK_SIZE;

  sem_init(&SEMS[0], 0, BLOCK_SIZE / 2);
  sem_init(&SEMS[1], 0, 0);

  srand(time(NULL));

  clear_screen();

  // Première partie de la ligne 1
  move_cursor(1, 1);
  print_n("-", LEFT_LIMIT);

  // Deuxième partie de la ligne 1
  move_cursor(1, RIGHT_LIMIT);
  print_n("-", LEFT_LIMIT + 1);

  // Première partie de la ligne 2
  move_cursor(3, 1);
  print_n("- ", LEFT_LIMIT / 2 - 1);

  // Deuxième partie de la ligne 2
  move_cursor(3, LEFT_LIMIT + 2);
  print_n("-", BLOCK_SIZE * 2 - 3);

  // Troisième partie de la ligne 2
  move_cursor(3, RIGHT_LIMIT + 2);
  print_n("- ", LEFT_LIMIT / 2);

  // Ligne 3
  move_cursor(5, 1);
  print_n("-", ROAD_SIZE);

  move_cursor(1, LEFT_LIMIT);
  fprintf(stdout, "\\");

  move_cursor(1, RIGHT_LIMIT);
  fprintf(stdout, "/");

  move_cursor(2, LEFT_LIMIT + 1);
  fprintf(stdout, "\\");

  move_cursor(2, RIGHT_LIMIT - 1);
  fprintf(stdout, "/");

  // Amélioration Messages
  move_cursor(7, 1);
  fprintf(stdout, "Press j to spawn a car riding to the east");
  move_cursor(8, 1);
  fprintf(stdout, "Press k to spawn a car riding to the west");
  move_cursor(9, 1);
  fprintf(stdout, "Press q to quit");

  move_cursor(1, ROAD_SIZE + 1);

  // Amélioration Input
  struct termios new_terminal_params;
  // Store old params
  tcgetattr(STDIN_FILENO, &OLD_TERMINAL_PARAMS);
  // Copy params
  new_terminal_params = OLD_TERMINAL_PARAMS;
  // Change params
  // Remove ICANON flag (wait for enter) and ECHO flag (print stdin)
  new_terminal_params.c_lflag &= ~(ICANON | ECHO);
  // Apply params
  tcsetattr(STDIN_FILENO, TCSANOW, &new_terminal_params);

  refresh();
}

void game_close() {
  clear_screen();

  // Amélioration Input
  // Restore old params
  tcsetattr(STDIN_FILENO, TCSANOW, &OLD_TERMINAL_PARAMS);

  refresh();
}

// Amélioration Compteur
// Extra: une couleur différente à chaque fois que le compteur change
unsigned int CAR_COUNTER = 0;
void *counter_thread(void *param) {
  int counter_color = 0;
  int last_count = CAR_COUNTER;
  while (1) {
    if (CAR_COUNTER != last_count) {
      counter_color = (counter_color + 1) % 6;
      last_count = CAR_COUNTER;
      move_cursor(3, ROAD_SIZE + 2);
      color(counter_color);
      fprintf(stdout, "%d", CAR_COUNTER);
    }
    sleep(1);
  }
  return NULL;
}

void *car_thread(void *param) {
  int car = *((int *)param);

  unsigned int car_color = rand() % 6;

  unsigned int increment, x, y, base_sleep = 80000;
  char logo;

  if (car == 0) {
    increment = -1;
    x = ROAD_SIZE + 1;
    y = 2;
    logo = '<';
  } else {
    increment = 1;
    x = 0;
    y = 4;
    logo = '>';
  }

  // Amélioration Compteur
  CAR_COUNTER++;

  for (int i = 1; i < ROAD_SIZE; i++) {
    // We check if we can move
    if ((x == LEFT_LIMIT - 1 && y == 4) || (x == RIGHT_LIMIT + 1 && y == 2)) {
      move_cursor(11, 1);
      fprintf(stdout, "locking!");
      sem_wait(&SEMS[car]);
    }
    // We reset old position
    move_cursor(y, x);
    fputc(' ', stdout);
    // We move to new position
    if (car == 0) {
      if (x == RIGHT_LIMIT || x == RIGHT_LIMIT + 1) {
        y++;
        base_sleep = 110000;
      } else if (x == LEFT_LIMIT || x == LEFT_LIMIT + 1) {
        y--;
        base_sleep = 110000;
      } else {
        base_sleep = 80000;
      }
    }
    x += increment;
    move_cursor(y, x);
    // Amélioration Couleur
    color(car_color);
    fputc(logo, stdout);
    move_cursor(1, ROAD_SIZE + 1);
    refresh();
    // We release the lock if we're out of the critical part of the road
    if ((x == RIGHT_LIMIT + 1 && y == 4) || (x == LEFT_LIMIT - 1 && y == 2)) {
      move_cursor(11, 1);
      fprintf(stdout, "unlocking!");
      sem_post(&SEMS[car]);
    }
    usleep(base_sleep + rand() % 10000);
  }

  move_cursor(y, x);
  fputc(' ', stdout);
  move_cursor(1, ROAD_SIZE + 1);
  refresh();

  return NULL;
}

// Amélioration Messages
void *error_thread(void *param) {
  color(0);
  move_cursor(11, 1);
  fprintf(stdout, "Unrecognised input.");
  refresh();

  sleep(2);

  color(0);
  move_cursor(11, 1);
  fprintf(stdout, "                   ");
  refresh();
  return NULL;
}

void *switchLanes(void *param) {
  int sem = 0;
  while (1) {
    sleep(2);

    move_cursor(12, 1);
    color(0);
    fprintf(stdout, "Switching sem: %d", sem);
    move_cursor(1, ROAD_SIZE + 1);
    refresh();

    for (int i = 0; i < BLOCK_SIZE / 2; i++) {
      sem_wait(&SEMS[sem]);
    }
    for (int i = 0; i < BLOCK_SIZE / 2; i++) {
      sem_post(&SEMS[1 - sem]);
    }
    sem = 1 - sem;
  }
  return NULL;
}

int main(int argc, char **argv) {

  {
    char buf[10];
    printf("Quel taille doit faire la route ? (défaut 40, min 20) → ");
    fgets(buf, 10, stdin);
    int size = atoi(buf);
    if (size < 20) {
      ROAD_SIZE = 40;
    } else {
      ROAD_SIZE = size;
    }
  }

  game_init();

  pthread_t last, unused_thread_id;

  // Amélioration Compteur
  pthread_create(&unused_thread_id, NULL, counter_thread, NULL);

  pthread_create(&unused_thread_id, NULL, switchLanes, NULL);

  char input;

  int car_arg;

  do {
    input = fgetc(stdin);
    switch (input) {
    case 'j':
    case 'k':
      if (input == 'j') {
        car_arg = 1;
      } else {
        car_arg = 0;
      }

      pthread_create(&last, NULL, car_thread, &car_arg);

      color(0);
      move_cursor(11, 1);
      fprintf(stdout, "                   ");
      refresh();
      break;
    case 'q':
      // Amélioration Messages
      color(0);
      move_cursor(11, 1);
      fprintf(stdout, "Quitting.          ");
      refresh();
      break;
    default:
      // Amélioration Messages
      pthread_create(&unused_thread_id, NULL, error_thread, NULL);
    }
  } while (input != 'q');

  pthread_join(last, NULL);

  game_close();
}

ppompeani_cars_sem_bonus.c

#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>

void clear_screen() { fprintf(stdout, "\e[1;1H\e[2J"); }

void refresh() { fflush(stdout); }

void move_cursor(unsigned int y, unsigned int x) {
  fprintf(stdout, "\e[%d;%dH", y, x);
}

void print_n(char *s, unsigned int repeat) {
  while (repeat > 0) {
    fprintf(stdout, "%s", s);
    repeat--;
  }
}

// Amélioration Couleur
const unsigned int COLOR_RESET = 0, COLOR_RED = 1, COLOR_GREEN = 2,
                   COLOR_YELLOW = 3, COLOR_BLUE = 4, COLOR_PURPLE = 5,
                   COLOR_LIGHTBLUE = 6;

void color(int color) {
  if (color == COLOR_RESET) {
    fprintf(stdout, "\e[0m");
  } else {
    fprintf(stdout, "\e[3%cm", color + '0');
  }
}

unsigned int ROAD_SIZE, BLOCK_SIZE, LEFT_LIMIT, RIGHT_LIMIT;

sem_t SEMS[2];
unsigned int nb_blocked_cars[2];

// Amélioration Input
struct termios OLD_TERMINAL_PARAMS;

void game_init() {
  BLOCK_SIZE = ROAD_SIZE / 10 + 2;
  LEFT_LIMIT = ROAD_SIZE / 2 - BLOCK_SIZE;
  RIGHT_LIMIT = ROAD_SIZE / 2 + BLOCK_SIZE;

  sem_init(&SEMS[0], 0, BLOCK_SIZE / 2);
  sem_init(&SEMS[1], 0, 0);

  srand(time(NULL));

  clear_screen();

  // Première partie de la ligne 1
  move_cursor(1, 1);
  print_n("-", LEFT_LIMIT);

  // Deuxième partie de la ligne 1
  move_cursor(1, RIGHT_LIMIT);
  print_n("-", LEFT_LIMIT + 1);

  // Première partie de la ligne 2
  move_cursor(3, 1);
  print_n("- ", LEFT_LIMIT / 2 - 1);

  // Deuxième partie de la ligne 2
  move_cursor(3, LEFT_LIMIT + 2);
  print_n("-", BLOCK_SIZE * 2 - 3);

  // Troisième partie de la ligne 2
  move_cursor(3, RIGHT_LIMIT + 2);
  print_n("- ", LEFT_LIMIT / 2);

  // Ligne 3
  move_cursor(5, 1);
  print_n("-", ROAD_SIZE);

  move_cursor(1, LEFT_LIMIT);
  fprintf(stdout, "\\");

  move_cursor(1, RIGHT_LIMIT);
  fprintf(stdout, "/");

  move_cursor(2, LEFT_LIMIT + 1);
  fprintf(stdout, "\\");

  move_cursor(2, RIGHT_LIMIT - 1);
  fprintf(stdout, "/");

  // Amélioration Messages
  move_cursor(7, 1);
  fprintf(stdout, "Press j to spawn a car riding to the east");
  move_cursor(8, 1);
  fprintf(stdout, "Press k to spawn a car riding to the west");
  move_cursor(9, 1);
  fprintf(stdout, "Press q to quit");

  move_cursor(1, ROAD_SIZE + 1);

  // Amélioration Input
  struct termios new_terminal_params;
  // Store old params
  tcgetattr(STDIN_FILENO, &OLD_TERMINAL_PARAMS);
  // Copy params
  new_terminal_params = OLD_TERMINAL_PARAMS;
  // Change params
  // Remove ICANON flag (wait for enter) and ECHO flag (print stdin)
  new_terminal_params.c_lflag &= ~(ICANON | ECHO);
  // Apply params
  tcsetattr(STDIN_FILENO, TCSANOW, &new_terminal_params);

  refresh();
}

void game_close() {
  clear_screen();

  // Amélioration Input
  // Restore old params
  tcsetattr(STDIN_FILENO, TCSANOW, &OLD_TERMINAL_PARAMS);

  refresh();
}

// Amélioration Compteur
// Extra: une couleur différente à chaque fois que le compteur change
unsigned int CAR_COUNTER = 0;
void *counter_thread(void *param) {
  int counter_color = 0;
  int last_count = CAR_COUNTER;
  while (1) {
    if (CAR_COUNTER != last_count) {
      counter_color = (counter_color + 1) % 6;
      last_count = CAR_COUNTER;
      move_cursor(3, ROAD_SIZE + 2);
      color(counter_color);
      fprintf(stdout, "%d", CAR_COUNTER);
    }
    sleep(1);
  }
  return NULL;
}

void *car_thread(void *param) {
  int car = *((int *)param);

  unsigned int car_color = rand() % 6;

  unsigned int increment, x, y, base_sleep = 80000;
  char logo;

  if (car == 0) {
    increment = -1;
    x = ROAD_SIZE + 1;
    y = 2;
    logo = '<';
  } else {
    increment = 1;
    x = 0;
    y = 4;
    logo = '>';
  }

  // Amélioration Compteur
  CAR_COUNTER++;

  int has_acquired = 0;

  for (int i = 1; i < ROAD_SIZE; i++) {
    // We check if we can move
    if (!has_acquired && ((x == LEFT_LIMIT - 1 - nb_blocked_cars[car] && y == 4) || (x == RIGHT_LIMIT + 1 + nb_blocked_cars[car] && y == 2))) {
      move_cursor(11, 1);
      fprintf(stdout, "locking!");
      has_acquired = 1;
      nb_blocked_cars[car]++;
      sem_wait(&SEMS[car]);
      nb_blocked_cars[car]--;
    }
    // We reset old position
    move_cursor(y, x);
    fputc(' ', stdout);
    // We move to new position
    if (car == 0) {
      if (x == RIGHT_LIMIT || x == RIGHT_LIMIT + 1) {
        y++;
        base_sleep = 110000;
      } else if (x == LEFT_LIMIT || x == LEFT_LIMIT + 1) {
        y--;
        base_sleep = 110000;
      } else {
        base_sleep = 80000;
      }
    }
    x += increment;
    move_cursor(y, x);
    // Amélioration Couleur
    color(car_color);
    fputc(logo, stdout);
    move_cursor(1, ROAD_SIZE + 1);
    refresh();
    // We release the lock if we're out of the critical part of the road
    if ((x == RIGHT_LIMIT + 1 && y == 4) || (x == LEFT_LIMIT - 1 && y == 2)) {
      move_cursor(11, 1);
      fprintf(stdout, "unlocking!");
      sem_post(&SEMS[car]);
    }
    usleep(base_sleep + rand() % 10000);
  }

  move_cursor(y, x);
  fputc(' ', stdout);
  move_cursor(1, ROAD_SIZE + 1);
  refresh();

  return NULL;
}

// Amélioration Messages
void *error_thread(void *param) {
  color(0);
  move_cursor(11, 1);
  fprintf(stdout, "Unrecognised input.");
  refresh();

  sleep(2);

  color(0);
  move_cursor(11, 1);
  fprintf(stdout, "                   ");
  refresh();
  return NULL;
}

void *switchLanes(void *param) {
  int sem = 0;
  while (1) {
    sleep(2);

    move_cursor(12, 1);
    color(0);
    fprintf(stdout, "Switching sem: %d", sem);
    move_cursor(1, ROAD_SIZE + 1);
    refresh();

    for (int i = 0; i < BLOCK_SIZE / 2; i++) {
      sem_wait(&SEMS[sem]);
    }
    for (int i = 0; i < BLOCK_SIZE / 2; i++) {
      sem_post(&SEMS[1 - sem]);
      usleep(140000);
    }
    sem = 1 - sem;
  }
  return NULL;
}

int main(int argc, char **argv) {

  {
    char buf[10];
    printf("Quel taille doit faire la route ? (défaut 40, min 20) → ");
    fgets(buf, 10, stdin);
    int size = atoi(buf);
    if (size < 20) {
      ROAD_SIZE = 40;
    } else {
      ROAD_SIZE = size;
    }
  }

  game_init();

  pthread_t last, unused_thread_id;

  // Amélioration Compteur
  pthread_create(&unused_thread_id, NULL, counter_thread, NULL);

  pthread_create(&unused_thread_id, NULL, switchLanes, NULL);

  char input;

  int car_arg;

  do {
    input = fgetc(stdin);
    switch (input) {
    case 'j':
    case 'k':
      if (input == 'j') {
        car_arg = 1;
      } else {
        car_arg = 0;
      }

      pthread_create(&last, NULL, car_thread, &car_arg);

      color(0);
      move_cursor(11, 1);
      fprintf(stdout, "                   ");
      refresh();
      break;
    case 'q':
      // Amélioration Messages
      color(0);
      move_cursor(11, 1);
      fprintf(stdout, "Quitting.          ");
      refresh();
      break;
    default:
      // Amélioration Messages
      pthread_create(&unused_thread_id, NULL, error_thread, NULL);
    }
  } while (input != 'q');

  pthread_join(last, NULL);

  game_close();
}