@Override
  public void run() { // on joue la rencontre (i.e. plusieurs manches)
    playMatch();

    // TODO la mise à jour des stats devrait aller ici
    // (soit calcul local, soit synchronisation avec le serveur)

    // on repart au menu principal
    clientCom.closeClient();
    clientCom.setGameHandler(null);
    mainWindow.clientCom = null;
    mainWindow.currentRound = null;
    mainWindow.clientPlayer = null;
    mainWindow.displayPanel(PanelName.MAIN_MENU);
  }
  @Override
  protected synchronized void resetRound() { // réinitialisation locale
    super.resetRound();

    // on attend d'avoir récupèré l'aire de jeu (attente passive)
    if (!newRoundReceived) {
      try {
        wait();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    // on force le moteur physique à utiliser l'aire de jeu reçue du serveur
    physicsEngine.setBoard(round.board);

    // on indique au serveur qu'on est prêt
    clientCom.sendAcknowledgment();
  }
  @Override
  protected synchronized void init() { // aspects réseau
    clientCom = mainWindow.clientCom;
    clientCom.setGameHandler(this);

    // initialisation standard
    super.init();

    // on récupère le numéro du seul joueur local, une fois pour toutes
    localPlayerId = -1;
    int i = 0;
    while (localPlayerId < 0 && i < round.players.length) {
      Player player = round.players[i];
      if (player.local) localPlayerId = i;
      i++;
    }

    // on récupère l'aire de jeu et on prévient le serveur qu'on est prêt
    resetRound();
  }
 /**
  * Envoie au serveur la dernière direction prise par le joueur.
  *
  * @param directions Directions renvoyées par le {@link KeyManager}.
  */
 private void sendDirection(Direction[] directions) {
   Direction direction = directions[localPlayerId];
   clientCom.sendCommand(direction);
 }
  @Override
  public void playRound() {
    int phyUpdateNbr = 0; // dernier nombre de màj physiques (stats)					
    int graphUpdateNbr = 0; // dernier nombre de màj graphiques (stats)
    long elapsedStatTime = 0; // temps écoulé depuis le dernier affichage des stats
    long elapsedPhysTime = 0; // temps écoulé depuis la dernière màj physique
    long elapsedGraphTime = 0; // temps écoulé depuis la dernière màj graphique
    long previousTime = System.currentTimeMillis(); // date de l'itération précédente
    long finalCount = 0; // décompte pour la toute fin de partie

    List<Integer> prevEliminated = new ArrayList<Integer>();
    newRoundReceived = false;

    while (running) {
      long currentTime = System.currentTimeMillis();
      long elapsedTime = currentTime - previousTime;
      previousTime = currentTime;

      elapsedPhysTime = elapsedPhysTime + elapsedTime;
      elapsedGraphTime = elapsedGraphTime + elapsedTime;
      elapsedStatTime = elapsedStatTime + elapsedTime;

      if (elapsedPhysTime / PHYS_DELAY >= 1) { // on envoie les commandes au serveur
        Direction[] directions = keyManager.retrieveDirections();
        sendDirection(
            directions); // TODO on pourrait tester si tout n'est pas NONE (auquel cas on
                         // n'enverrait rien)
        // on met à jour le moteur physique
        UpdateInterface updateData = clientCom.retrieveUpdate();
        if (updateData
            == null) { // TODO pas forcément une bonne idée de màj localement...ou alors faut
                       // désactiver tout ce qui est aléatoire
          //					physicsEngine.update(elapsedPhysTime, directions);
        } else {
          if (updateData instanceof Board) round.board = (Board) updateData;
          physicsEngine.forceUpdate(updateData);
          // if(updateData instanceof SmallUpdate)
          // {	SmallUpdate su = (SmallUpdate)updateData;
          //	PhysBoard b = (PhysBoard)physicsEngine.getBoard();
          ////	System.out.println(su.state+" vs. "+b.state);
          //	if(su.state==State.ENTRANCE)
          //		System.out.println();
          // }
          // System.out.println("["+elapsedTime+"]"+round.board.snakes[0].currentX+" ;
          // "+round.board.snakes[0].currentY);
          //				}
          // on met à jour les scores
          List<Integer> lastEliminated = physicsEngine.getEliminatedPlayers();
          if (!lastEliminated.isEmpty()) System.out.println();
          boolean finished = updatePoints(prevEliminated, lastEliminated);
          if (finished) finalCount = 1;
        }
        phyUpdateNbr++;
        elapsedPhysTime = 0;
      }

      if (elapsedGraphTime / GRAPH_DELAY >= 1) {
        graphicDisplay.update(round);
        graphUpdateNbr++;
        elapsedGraphTime = 0;
      }

      if (finalCount > 0) {
        finalCount = finalCount + elapsedTime;
        if (finalCount >= Constants.END_DURATION) running = false;
      }

      if (elapsedStatTime >= 1000) {
        if (showStats) System.out.println("UPS: " + phyUpdateNbr + " -- FPS: " + graphUpdateNbr);
        graphUpdateNbr = 0;
        phyUpdateNbr = 0;
        elapsedStatTime = 0;
      }
    }
  }