Thésée

De Centre de Ressources Numériques - Labomedia
Révision de 13 janvier 2015 à 19:47 par Serge (discussion | contributions)

(diff) ← Version précédente | Voir la version actuelle (diff) | Version suivante → (diff)
Aller à : navigation, rechercher

Thésée est une installation interactive qui consiste à faire apparaître une portion d'un labyrinthe généré de façon algorithmique sous les pieds du spectateur, le labyrinthe se découvre partiellement en fonction du mouvement du spectateur, l'invitant à un jeu de mémoire pour en trouver la sortie, clin d'oeil à la mythologie grecque et aux bâtisseurs de cathédrale qui ont parfois malicieusement, comme à Chartres, dessiné un labyrinthe au sol de l'édifice religieux.

Thesee.jpg

Code

Labyrinthe labyrinthe;
int largeurLabyrinthe = 20;
int hauteurLabyrinthe = 15;
int epaisseurMurs = 10;
int largeurCellule = 40;
int hauteurCellule = 40;
boolean solution, sortie;

void setup() {
  size(largeurLabyrinthe * (largeurCellule + epaisseurMurs) + epaisseurMurs, hauteurLabyrinthe * (hauteurCellule + epaisseurMurs) + epaisseurMurs);
  labyrinthe = new Labyrinthe(this, largeurLabyrinthe, hauteurLabyrinthe, epaisseurMurs, largeurCellule, hauteurCellule);
  solution = false;
  sortie = false;
  labyrinthe.creationLab();
} // Fin setup

void draw() {
  background(0);
  
  if (solution) {
    labyrinthe.afficherLabyrinthe();
  } // Fin if
  labyrinthe.position(mouseX, mouseY);
  if (sortie) {
    labyrinthe.afficherCheminSortie(mouseX, mouseY);
  } // Fin if
} // Fin draw

void keyPressed() {
  if (key == 'c') {
    solution = !solution;
  } // Fin if
  if (key == ' ') {
    sortie = !sortie;
  } // Fin if
  if (key == 's') {
    File repertoire = new File(sketchPath + "/data");
    String[] fichiers = repertoire.list();
    saveBytes("data/lab_" + fichiers.length + ".dat", labyrinthe.sauvegarder());
  } // Fin if
} // keyPressed

class Cellule {
  int compteur;
  int largeurCellule, hauteurCellule, epaisseurMur;
  boolean murNord;
  boolean murOuest;
  boolean murSud;
  boolean murEst;
  boolean chemin;
  int cheminSortie;

  Cellule(int _largeurCellule, int _hauteurCellule, int _epaisseurMur) {
    largeurCellule = _largeurCellule;
    hauteurCellule = _hauteurCellule;
    epaisseurMur = _epaisseurMur;
    compteur = 0;
    murNord = true;
    murOuest = true;
    murSud = true;
    murEst = true;
    chemin = false;
  } // Fin constructeur Cellule

  void compteurSet(int _compteur) {
    compteur = _compteur;
  } // Fin compteurSet

  int compteurGet() {
    return compteur;
  } // Fin compteurGet

  void afficher() { //int centreX, int centreY) {
    noStroke();999
    fill(255);
    if (murNord) {
      rect(0, 0, largeurCellule + 2 * epaisseurMur, epaisseurMur);
    } // Fin if
    if (murOuest) {
      rect(0, 0, epaisseurMur, hauteurCellule + 2 * epaisseurMur);
    } // Fin if
    if (murSud) {
      rect(0, hauteurCellule + epaisseurMur, largeurCellule + 2 * epaisseurMur, epaisseurMur);
    } // Fin if
    if (murEst) {
      rect(largeurCellule + epaisseurMur, 0, epaisseurMur, hauteurCellule + 2 * epaisseurMur);
    } // Fin if
  } // Fin afficher
  
  void afficherSortie() {
    noStroke();
    if (cheminSortie != 0) {
      fill(0, 255, 0);
      int masque = 15;
      for (int i = 0; i < 2; i++) {
        int val = (cheminSortie >> (4 * i)) & masque;
        switch(val) {
        case 1 :
          rect(epaisseurMur + 3 * largeurCellule / 8, 0, 2 * largeurCellule / 8, epaisseurMur + 5 * hauteurCellule / 8);
          break;
        case 2 :
          rect(0, epaisseurMur + 3 * hauteurCellule / 8, epaisseurMur + 5 * largeurCellule / 8 , 2 * hauteurCellule / 8);
          break;
        case 3 :
          rect(epaisseurMur + 3 * largeurCellule / 8, epaisseurMur + 3 * hauteurCellule / 8, 2 * largeurCellule / 8, epaisseurMur + 5 * hauteurCellule / 8);
          break;
        case 4 :
          rect(epaisseurMur + 3 * largeurCellule / 8, epaisseurMur + 3 * hauteurCellule / 8, epaisseurMur + 5 * largeurCellule / 8, 2 * hauteurCellule / 8);
          break;
        } // Fin switch
      } // Fin for999
    } // Fin if
  } // Fin afficherSortie
} // Fin Class Cellule

class Labyrinthe {
  int largeur;
  int hauteur;
  int epaisseurMur;
  int largeurCellule;
  int hauteurCellule;
  PVector sortie;
  Cellule[][] cellule;

  Labyrinthe(PApplet parent, int _largeur, int _hauteur, int _epaisseurMur, int _largeurCellule, int _hauteurCellule) {
    largeur = _largeur;
    hauteur = _hauteur;
    epaisseurMur = _epaisseurMur;
    largeurCellule = _largeurCellule;
    hauteurCellule = _hauteurCellule;
    cellule = new Cellule[largeur][hauteur];999
    for (int j = 0; j < hauteur; j++) { // Pacours des lignes
      for (int i = 0; i < largeur; i++) { // Parcours des colonnes
        cellule[i][j] = new Cellule(largeurCellule, hauteurCellule, epaisseurMur);
      } // Fin for
    } // Fin for
  } // Fin constructeur Labyrinthe

  void creationLab() {
    int[] parcours = new int[4];
    int indice;
    int x = 0;
    int y  = hauteur /2;
    boolean finProcessus = false;
    boolean sortieTrouvee = false;
    int compteur = 1;
    int xSortie = 0;
    int ySortie = 0;

    cellule[x][y].murOuest = false;
    cellule[x][y].chemin = true;
    while (!finProcessus) {
      cellule[x][y].compteur = compteur;
      if ((x == largeur - 1) && (!sortieTrouvee)) {
        cellule[x][y].murEst = false; // Arrivée à la façade Est du Labyrinthe
        cellule[x][y].chemin = true;
        sortieTrouvee = true;
        indice = 0; // Ne vérifie pas les cellules voisines donc saute directement à la recherche d'un cellule libre
        xSortie = x;
        ySortie = y;
        sortie = new PVector(x, y);
        println("Sortie " + x + " : " + y);
      } // Fin if
      else {
        indice = 0;
        if (y > 0) {
          if (cellule[x][y-1].compteur == 0) {
            parcours[indice] = 1;
            indice++;
          } // Fin if
        } // Fin if
        if (x > 0) {
          if (cellule[x-1][y].compteur == 0) {
            parcours[indice] = 2;
            indice++;
          } // Fin if
        } // Fin if
        if (y < (hauteur - 1)) {
          if (cellule[x][y+1].compteur == 0) {
            parcours[indice] = 3;
            indice++;
          } // Fin if
        } // Fin if
        if (x < (largeur - 1)) {
          if (cellule[x+1][y].compteur == 0) {
            parcours[indice] = 4;
            indice++;
          } // Fin if
        } // Fin if
      } // Fin else
      if (indice == 0) { // Arrive dans une impasse
        PVector nouvelleCelluleLibre = celluleLibre(); // Choix d'une nouvelle cellule libre adjacente
        if (nouvelleCelluleLibre.z == -1) {
          finProcessus = true;
        } // Fin if
        else {
          x = (int)nouvelleCelluleLibre.x;
          y = (int)nouvelleCelluleLibre.y;
          switch (int(nouvelleCelluleLibre.z)) { // Ouvertire des murs entre la cellule 
          case 1:
            cellule[x][y].murNord = false;
            cellule[x][y-1].murSud = false;
            compteur = cellule[x][y-1].compteur + 1;
            break;
          case 2 :
            cellule[x][y].murOuest = false;
            cellule[x-1][y].murEst = false;
            compteur = cellule[x-1][y].compteur + 1;
            break;
          case 3 :
            cellule[x][y].murSud = false;
            cellule[x][y+1].murNord = false;
            compteur = cellule[x][y+1].compteur + 1;
            break;
          case 4 :
            cellule[x][y].murEst = false;
            cellule[x+1][y].murOuest = false;
            compteur = cellule[x+1][y].compteur + 1;
            break;
          } // Fin switch
        } // Fin else
      } // Fin if
      else { // Choix d'une case adjacente
        int alea = int(random(indice)); // Choix aléatoire d'une direction
        //println(alea + " : " + parcours[alea]);
        compteur++;
        switch (parcours[alea]) {
        case 1 :
          cellule[x][y].murNord = false;
          y = y - 1;
          cellule[x][y].murSud = false;
          break;
        case 2 : 
          cellule[x][y].murOuest = false;
          x = x- 1;
          cellule[x][y].murEst = false;
          break;
        case 3 : 
          cellule[x][y].murSud = false;
          y = y + 1;
          cellule[x][y].murNord = false;
          break;
        case 4 : 
          cellule[x][y].murEst = false;
          x = x + 1;
          cellule[x][y].murOuest = false;
          break;
        } // Fin switch
      } // Fin else
    } // Fin while
    // Création du chemin de l'entrée à la sortie du labyrinthe
    while (cellule[xSortie][ySortie].compteur != 1) {
      if ((xSortie > 0) && !cellule[xSortie][ySortie].murOuest) {
        if (cellule[xSortie - 1][ySortie].compteur < cellule[xSortie][ySortie].compteur) {
          xSortie--;
          cellule[xSortie][ySortie].chemin = true;
          continue;
        } // Fin if
      } // Fin if
      if ((xSortie < largeur) && !cellule[xSortie][ySortie].murEst) {
        if (cellule[xSortie + 1][ySortie].compteur < cellule[xSortie][ySortie].compteur) {
          xSortie++;
          cellule[xSortie][ySortie].chemin = true;
          continue;
        } // Fin if
      } // Fin if
      if ((ySortie > 0) && !cellule[xSortie][ySortie].murNord) {
        if (cellule[xSortie][ySortie - 1].compteur < cellule[xSortie][ySortie].compteur) {
          ySortie--;
          cellule[xSortie][ySortie].chemin = true;
          continue;
        } // Fin if
      } // Fin if
      if ((ySortie < hauteur) && !cellule[xSortie][ySortie].murSud) {
        if (cellule[xSortie][ySortie + 1].compteur < cellule[xSortie][ySortie].compteur) {
          ySortie++;
          cellule[xSortie][ySortie].chemin = true;
          continue;
        } // Fin if
      } // Fin if
    } // Fin while
  } // Fin creationLab

  void position(float _posX, float _posY) { // Visualisation de l'espace environnant
    int caseX, caseY;
    caseX = int(_posX) / (largeurCellule + epaisseurMur);
    caseY = int(_posY) / (hauteurCellule + epaisseurMur);
    caseX = constrain(caseX, 0, largeur - 1);
    caseY = constrain(caseY, 0, hauteur - 1);
    //println(caseX + " : " + caseY);

    int i = caseY;
    do {
      pushMatrix();
      translate(caseX * (largeurCellule + epaisseurMur), i * (hauteurCellule + epaisseurMur));
      cellule[caseX][i].afficher();
      popMatrix();
      i--;
    } 
    while ( (i >= 0) && !cellule[caseX][i + 1].murNord);
    i = caseY;
    do {
      pushMatrix();
      translate(caseX * (largeurCellule + epaisseurMur), i * (hauteurCellule + epaisseurMur));
      cellule[caseX][i].afficher();
      popMatrix();
      i++;
    } 
    while ( (i < hauteur) && !cellule[caseX][i - 1].murSud);
    i = caseX;
    do {
      pushMatrix();
      translate(i * (largeurCellule + epaisseurMur), caseY * (hauteurCellule + epaisseurMur));
      cellule[i][caseY].afficher();
      popMatrix();
      i--;
    } 
    while ( (i >= 0) && !cellule[i + 1][caseY].murOuest);
    i = caseX;
    do {
      pushMatrix();
      translate(i * (largeurCellule + epaisseurMur), caseY * (hauteurCellule + epaisseurMur));
      cellule[i][caseY].afficher();
      popMatrix();
      i++;
    } 
    while ( (i < largeur) && !cellule[i - 1][caseY].murEst);
  } // position

  void afficherCheminSortie(int _posX, int _posY) {     // Création du chemin de sortie jusqu'au chemin principal
    int posX = int(_posX) / (largeurCellule + epaisseurMur);
    int posY = int(_posY) / (hauteurCellule + epaisseurMur);
    posX = constrain(posX, 0, largeur - 1);
    posY = constrain(posY, 0, hauteur - 1);
    // Remise à zéro des valeurs du chemin de sortie
    for (int i = 0; i < largeur; i++) {
      for (int j = 0; j < hauteur; j++) {
        cellule[i][j].cheminSortie = 0;
      } // Fin for
    } // Fin for
    // Trouver le chemin de la position actuelle jusqu'à une case du chemin entrée / sortie
    while (!cellule[posX][posY].chemin) {
      if ((posX > 0) && !cellule[posX][posY].murOuest) {
        if (cellule[posX - 1][posY].compteur < cellule[posX][posY].compteur) {
          cellule[posX][posY].cheminSortie = cellule[posX][posY].cheminSortie | (2 << 4);
          posX--;
          cellule[posX][posY].cheminSortie = cellule[posX][posY].cheminSortie | 4;
          continue;
        } // Fin if
      } // Fin if
      if ((posX < largeur) && !cellule[posX][posY].murEst) {
        if (cellule[posX + 1][posY].compteur < cellule[posX][posY].compteur) {
          cellule[posX][posY].cheminSortie = cellule[posX][posY].cheminSortie | (4 << 4);
          posX++;
          cellule[posX][posY].cheminSortie = cellule[posX][posY].cheminSortie | 2;
          continue;
        } // Fin if
      } // Fin if
      if ((posY > 0) && !cellule[posX][posY].murNord) {
        if (cellule[posX][posY - 1].compteur < cellule[posX][posY].compteur) {
          cellule[posX][posY].cheminSortie = cellule[posX][posY].cheminSortie | (1 << 4);
          posY--;
          cellule[posX][posY].cheminSortie = cellule[posX][posY].cheminSortie | 3;
          continue;
        } // Fin if
      } // Fin if
      if ((posY < hauteur) && !cellule[posX][posY].murSud) {
        if (cellule[posX][posY + 1].compteur < cellule[posX][posY].compteur) {
          cellule[posX][posY].cheminSortie = cellule[posX][posY].cheminSortie | (3 << 4);
          posY++;
          cellule[posX][posY].cheminSortie = cellule[posX][posY].cheminSortie | 1;
          continue;
        } // Fin if
      } // Fin if
    } // Fin while
    cellule[posX][posY].cheminSortie = cellule[posX][posY].cheminSortie << 4;
    int valeurCompteur = cellule[posX][posY].compteur;
    // Trouver le chemin de la sortie jusqu'à la case trouvée précédemment
    posX = (int)sortie.x;
    posY = (int)sortie.y;
    //println(posX + " : " + posY + " : " + valeurCompteur);
    while (cellule[posX][posY].compteur != valeurCompteur) {
      if ((posX > 0) && !cellule[posX][posY].murOuest) {
        if (cellule[posX - 1][posY].compteur < cellule[posX][posY].compteur) {
          cellule[posX][posY].cheminSortie = cellule[posX][posY].cheminSortie | (2 << 4);
          posX--;
          cellule[posX][posY].cheminSortie = cellule[posX][posY].cheminSortie | 4;
          continue;
        } // Fin if
      } // Fin if
      if ((posX < largeur) && !cellule[posX][posY].murEst) {
        if (cellule[posX + 1][posY].compteur < cellule[posX][posY].compteur) {
          cellule[posX][posY].cheminSortie = cellule[posX][posY].cheminSortie | (4 << 4);
          posX++;
          cellule[posX][posY].cheminSortie = cellule[posX][posY].cheminSortie | 2;
          continue;
        } // Fin if
      } // Fin if
      if ((posY > 0) && !cellule[posX][posY].murNord) {
        if (cellule[posX][posY - 1].compteur < cellule[posX][posY].compteur) {
          cellule[posX][posY].cheminSortie = cellule[posX][posY].cheminSortie | (1 << 4);
          posY--;
          cellule[posX][posY].cheminSortie = cellule[posX][posY].cheminSortie | 3;
          continue;
        } // Fin if
      } // Fin if
      if ((posY < hauteur) && !cellule[posX][posY].murSud) {
        if (cellule[posX][posY + 1].compteur < cellule[posX][posY].compteur) {
          cellule[posX][posY].cheminSortie = cellule[posX][posY].cheminSortie | (3 << 4);
          posY++;
          cellule[posX][posY].cheminSortie = cellule[posX][posY].cheminSortie | 1;
          continue;
        } // Fin if
      } // Fin if
    } // Fin while

      // Affichage du chemin
    for (int u = 0; u < largeur; u++) {
      for (int v = 0; v < hauteur; v++) {
        pushMatrix();
        translate(u * (largeurCellule + epaisseurMur), v * (hauteurCellule + epaisseurMur));
        cellule[u][v].afficherSortie();
        popMatrix();
      } // Fin for
    } // Fin for
  } // Fin afficherCheminSortie

  void afficherLabyrinthe() {
    //strokeWeight(0);
    noStroke();
    for (int j = 0; j < hauteur; j++) { // Parcours des lignes
      for (int i = 0; i < largeur; i++) { // Parcours des colonnes
        pushMatrix();
        translate(i * (largeurCellule + epaisseurMur), j * (hauteurCellule + epaisseurMur));
        cellule[i][j].afficher();
        if (cellule[i][j].chemin) {
          fill(255, 0, 0);
          ellipse(epaisseurMur + largeurCellule / 2, epaisseurMur + largeurCellule / 2, largeurCellule / 2, largeurCellule / 2);
        } // Fin if
        popMatrix();
        // text(cellule[i][j].compteur, i * (largeurCellule + epaisseurMur) + largeurCellule / 2, j * (hauteurCellule + epaisseurMur) + largeurCellule);
      } // Fin for
    } // Fin for
  }// Fin afficherLabyrinthe()

  PVector celluleLibre() {
    PVector[] tableau = new PVector[hauteur*largeur];
    int compt = 0;
    int verif;

    for (int j = 0; j < hauteur; j++) { // Parcours des lignes
      for (int i = 0; i < largeur; i++) { // Parcours des colonnes
        if (cellule[i][j].compteur == 0) {
          verif = 0;
          if (j > 0) {
            if (cellule[i][j-1].compteur != 0) {
              verif = 1;
            } // Fin if
          } // Fin if
          if (i > 0) {
            if (cellule[i-1][j].compteur != 0) {
              verif = 2;
            } // Fin if
          } // Fin if
          if (j < (hauteur - 1)) {
            if (cellule[i][j+1].compteur != 0) {
              verif = 3;
            } // Fin if
          } // Fin if
          if (i < (largeur - 1)) {
            if (cellule[i+1][j].compteur != 0) {
              verif = 4;
            } // Fin if
          } // Fin if
          if (verif > 0) {
            tableau[compt] = new PVector(i, j, verif);
            compt++;
          } // Fin if
        } // Fin if
      } // Fin for i
    } // Fin for j
    if (compt == 0) {
      return new PVector(-1, -1, -1);
    } // Fin if
    else {
      return tableau[int(random(compt))];
    } // Fin else
  } // Fin celluleLibre()

  byte[] sauvegarder() {
    byte[] tableau = new byte[4 * largeur * hauteur];
    int compteur = 0;
    for (int j = 0; j < hauteur; j++) {
      for (int i = 0; i < largeur; i ++) {
        tableau[compteur] = byte(cellule[i][j].murNord);
        compteur++;
        tableau[compteur] = byte(cellule[i][j].murOuest);
        compteur++;
        tableau[compteur] = byte(cellule[i][j].murSud);
        compteur++;
        tableau[compteur] = byte(cellule[i][j].murEst);
        compteur++;
      } // Fin for i
    } // Fin for j
    return tableau;
  } // Fin sauvegarder
} // Fin Class Labyrinthe

Liens

Algorithmes