#include <LiquidCrystal_I2C.h>
#include <avr/pgmspace.h> // Nécessaire pour PROGMEM

// === Déclarations et constantes ===
const int SEUIL_ACTION_BAS = 15;
const int SEUIL_ACTION_HAUT = 1000;

// Dimensions
const int NB_ZONES = 3; // 3x3 zones
const int MAX_BUISSONS = 10; // 20 buissons par zone
const int LCD_COLONNES = 20;
const int LCD_LIGNES = 4;

// === Définition des graphismes personnalisés ===
byte persoGraphique[] = {B01110, B01010, B00100, B01110, B00100, B00100, B01010, B11011};
byte buissonGraphique[] = {B00000, B01110, B11111, B11111, B11111, B01110, B00000, B00000};
byte clefGraphique[] = {B00110, B00100, B00110, B00100, B00100, B01110, B01010, B01110};

// === Structures ===
struct Coordonnees {
    int colonne;
    int ligne;
};

struct Zone {
    Coordonnees positionPerso;
    Coordonnees positionClef;
    Coordonnees positionBuissons[MAX_BUISSONS];
    int nbBuissons;
    bool clefPresente;
};

struct Perso {
    Coordonnees position;
    int vitesse;
    unsigned long compteurVitesse;
};

// === Variables globales ===
LiquidCrystal_I2C lcd(0x27, LCD_COLONNES, LCD_LIGNES);
Zone zones[NB_ZONES][NB_ZONES];
Perso perso = {{0, 0}, 100, 0};

int zoneActuelleX = 1;
int zoneActuelleY = 1;
int J1, J2;

// === Prototypes de fonctions ===
void initialiserZones();
void initialiserLCD();
void changerZone(int nouvelleZoneX, int nouvelleZoneY, const char* direction = "");
void afficherPersonnage();
void effacerCase(int colonne, int ligne);
void ramasserObjets();
void deplacementJoystick();
void gererCollisionBuissons();
void deplacerPerso(int dx, int dy);
void effetEffacementProgressif();
void effetClignotement();

// === Configuration initiale ===
void setup() {
    initialiserZones();
    initialiserLCD();
}

void loop() {
    if (millis() > perso.compteurVitesse + perso.vitesse) {
        deplacementJoystick();
        ramasserObjets();
        afficherPersonnage();
        perso.compteurVitesse = millis(); // Mise à jour après les actions
    }
}
// Exemple de motif générique en forme de forêt (max 20 buissons)
const byte MOTIF_FORET[10][2] = {
      {0, 1}, {1, 1}, {2, 1}, {3, 1}, {4, 1},
    {15, 1}, {16, 1}, {17, 1}, {18, 1}, {19, 1}
   /* 
    , {2, 2}, {2, 3}, {2, 4 },
     {3, 1}, {3, 2}, {3, 3}, {3, 4},
     {0, 1}, {0, 2}, {0, 3},{0, 0},
    */ 
};
const byte MOTIF_FORET_DEUX[10][2] = {
    {0, 1}, {1, 1}, {2, 1}, {3, 1}, {4, 1},
    {15, 1}, {16, 1}, {17, 1}, {18, 1}, {19, 1}
    /*
    {5, 0}
    
    , {2, 3}, {2, 4 },
     {3, 1}, {3, 2}, {3, 3}, {3, 4},
     {0, 1}, {0, 2}, {0, 3},{0, 0},
    */ 
};
const byte MOTIF_FORET_TROIS[10][2] = {
    {0, 1}, {1, 1}, {2, 1}, {3, 1}, {4, 1},
    {15, 1}, {16, 1}, {17, 1}, {18, 1}, {19, 1}
   /* 
    , {2, 2}, {2, 3}, {2, 4 },
     {3, 1}, {3, 2}, {3, 3}, {3, 4},
     {0, 1}, {0, 2}, {0, 3},{0, 0},
    */ 
};

// Fonction pour initialiser les zones avec le motif décalé
void initialiserZones() {
    for (int i = 0; i < NB_ZONES; i++) {
        for (int j = 0; j < NB_ZONES; j++) {
            zones[i][j].nbBuissons = MAX_BUISSONS;
            zones[i][j].clefPresente = true;

        
            // zone à gauche
            if (i == 0 && j == 1) { // Zone à gauche de centre
                for (int k = 0; k < MAX_BUISSONS; k++) {
                    if (k < 10) { // Ajustement pour éviter de dépasser MAX_BUISSONS
                        zones[i][j].positionBuissons[k] = {MOTIF_FORET[k][0], MOTIF_FORET[k][1]};
                    }
                }
            }
           // zone centrale
            else if (i == 1 && j == 1) { // Centre de la grille (modifiable selon vos besoins)
                for (int k = 0; k < MAX_BUISSONS; k++) {
                    if (k < 10) { // Ajustement pour éviter de dépasser MAX_BUISSONS
                        zones[i][j].positionBuissons[k] = {MOTIF_FORET_DEUX[k][0], MOTIF_FORET_DEUX[k][1]};
                    }
                }
            }
                 // zone à droite
            else if (i == 2 && j == 1) { // Zone à gauche de centre
                for (int k = 0; k < MAX_BUISSONS; k++) {
                    if (k < 10) { // Ajustement pour éviter de dépasser MAX_BUISSONS
                        zones[i][j].positionBuissons[k] = {MOTIF_FORET_TROIS[k][0], MOTIF_FORET_TROIS[k][1]};
                    }
                }
            }
        }
    }
}


/*
// === Initialisation des zones ===
void initialiserZones() {
    for (int i = 0; i < NB_ZONES; i++) {
        for (int j = 0; j < NB_ZONES; j++) {
            zones[i][j].nbBuissons = MAX_BUISSONS;
            zones[i][j].clefPresente = true;
            zones[i][j].positionClef = {random(0, LCD_COLONNES), random(0, LCD_LIGNES)};

            int index = 0;

            // Choix du motif en fonction de (i + j) % 2
            if ((i + j) % 2 == 0) {
                // Motif 1 : Une ligne horizontale au centre
                int centreY = LCD_LIGNES / 2;
                for (int x = 0; x < MAX_BUISSONS && x < LCD_COLONNES; x++) {
                    zones[i][j].positionBuissons[index++] = {x, centreY};
                }
            } else {
                // Motif 2 : Un carré autour du centre
                int centreX = LCD_COLONNES / 2;
                int centreY = LCD_LIGNES / 2;
                for (int dx = -1; dx <= 1; dx++) {
                    for (int dy = -1; dy <= 1; dy++) {
                        if (index < MAX_BUISSONS) {
                            zones[i][j].positionBuissons[index++] = {centreX + dx, centreY + dy};
                        }
                    }
                }
            }
        }
    }
}
*/
/*Ligne diagonale :
for (int k = 0; k < MAX_BUISSONS; k++) {
    zones[i][j].positionBuissons[k] = {k, k}; // Diagonale simple
}
*/
/* Carré autour du centre :
for (int dx = -1; dx <= 1; dx++) {
    for (int dy = -1; dy <= 1; dy++) {
        if (index < MAX_BUISSONS) {
            zones[i][j].positionBuissons[index++] = {centreX + dx, centreY + dy};
        }
    }
}
*/
/*
            // Horizontal de la croix
            for (int x = centreX - 2; x <= centreX + 2; x++) {
                if (index < MAX_BUISSONS) {
                    zones[i][j].positionBuissons[index++] = {x, centreY};
                }
            }

            // Vertical de la croix
            for (int y = centreY - 2; y <= centreY + 2; y++) {
                if (index < MAX_BUISSONS) {
                    zones[i][j].positionBuissons[index++] = {centreX, y};
                }
            }
            */
 

// === Initialisation de l'afficheur LCD ===
void initialiserLCD() {
    lcd.init();
    lcd.backlight();
    lcd.createChar(0, persoGraphique);
    lcd.createChar(1, buissonGraphique);
    lcd.createChar(4, clefGraphique);
    changerZone(1, 1);
}

// === Gestion des zones et transitions ===
void changerZone(int nouvelleZoneX, int nouvelleZoneY, const char* direction) {
    if (nouvelleZoneX < 0 || nouvelleZoneX >= NB_ZONES || nouvelleZoneY < 0 || nouvelleZoneY >= NB_ZONES) {
        return; // Hors limites
    }

    zones[zoneActuelleX][zoneActuelleY].positionPerso = perso.position; // Sauvegarde
    zoneActuelleX = nouvelleZoneX;
    zoneActuelleY = nouvelleZoneY;

    // Réinitialisation du personnage
    if (strcmp(direction, "droite") == 0) {
        perso.position = {0, perso.position.ligne};
    } else if (strcmp(direction, "gauche") == 0) {
        perso.position = {LCD_COLONNES - 1, perso.position.ligne};
    } else if (strcmp(direction, "haut") == 0) {
        perso.position = {perso.position.colonne, LCD_LIGNES - 1};
    } else if (strcmp(direction, "bas") == 0) {
        perso.position = {perso.position.colonne, 0};
    }

    effetClignotement();
    effetEffacementProgressif();

    Zone &zone = zones[zoneActuelleX][zoneActuelleY];
    if (zone.clefPresente) {
        lcd.setCursor(zone.positionClef.colonne, zone.positionClef.ligne);
        lcd.write(4);
    }
    for (int i = 0; i < zone.nbBuissons; i++) {
        lcd.setCursor(zone.positionBuissons[i].colonne, zone.positionBuissons[i].ligne);
        lcd.write(1);
    }
    afficherPersonnage();
}

// === Affichage et gestion des objets ===
void effacerCase(int colonne, int ligne) {
    lcd.setCursor(colonne, ligne);
    lcd.print(" ");
}

void afficherPersonnage() {
    lcd.setCursor(perso.position.colonne, perso.position.ligne);
    lcd.write(0);
}

void ramasserObjets() {
    Zone &zone = zones[zoneActuelleX][zoneActuelleY];
    if (perso.position.colonne == zone.positionClef.colonne &&
        perso.position.ligne == zone.positionClef.ligne &&
        zone.clefPresente) {
        zone.clefPresente = false;
        effacerCase(zone.positionClef.colonne, zone.positionClef.ligne);
    }
}

void gererCollisionBuissons() {
    Zone &zone = zones[zoneActuelleX][zoneActuelleY];
    for (int i = 0; i < zone.nbBuissons; i++) {
        if (perso.position.colonne == zone.positionBuissons[i].colonne &&
            perso.position.ligne == zone.positionBuissons[i].ligne) {
            return; // Collision détectée
        }
    }
}

void deplacerPerso(int dx, int dy) {
    int nouvelleColonne = perso.position.colonne + dx;
    int nouvelleLigne = perso.position.ligne + dy;

    Zone &zone = zones[zoneActuelleX][zoneActuelleY];
    for (int i = 0; i < zone.nbBuissons; i++) {
        if (nouvelleColonne == zone.positionBuissons[i].colonne &&
            nouvelleLigne == zone.positionBuissons[i].ligne) {
            return; // Collision
        }
    }

    if (nouvelleColonne >= 0 && nouvelleColonne < LCD_COLONNES &&
        nouvelleLigne >= 0 && nouvelleLigne < LCD_LIGNES) {
        effacerCase(perso.position.colonne, perso.position.ligne);
        perso.position.colonne = nouvelleColonne;
        perso.position.ligne = nouvelleLigne;
        afficherPersonnage();
    }
}

// === Effets visuels ===
void effetEffacementProgressif() {
    for (int ligne = 0; ligne < LCD_LIGNES; ligne++) {
        lcd.setCursor(0, ligne);
        lcd.print("                    ");
        delay(50);
    }
    delay(100);
}

void effetClignotement() {
    for (int i = 0; i < 3; i++) {
        lcd.noBacklight();
        delay(100);
        lcd.backlight();
        delay(100);
    }
}

// === Déplacement du personnage ===
void deplacementJoystick() {
    J1 = analogRead(0);
    J2 = analogRead(1);

    if (J1 < SEUIL_ACTION_BAS) {
        if (perso.position.ligne < LCD_LIGNES - 1) {
            deplacerPerso(0, 1);
        } else if (zoneActuelleY < NB_ZONES - 1) {
            changerZone(zoneActuelleX, zoneActuelleY + 1, "bas");
        }
    }
    if (J1 > SEUIL_ACTION_HAUT) {
        if (perso.position.ligne > 0) {
            deplacerPerso(0, -1);
        } else if (zoneActuelleY > 0) {
            changerZone(zoneActuelleX, zoneActuelleY - 1, "haut");
        }
    }
    if (J2 < SEUIL_ACTION_BAS) {
        if (perso.position.colonne < LCD_COLONNES - 1) {
            deplacerPerso(1, 0);
        } else if (zoneActuelleX < NB_ZONES - 1) {
            changerZone(zoneActuelleX + 1, zoneActuelleY, "droite");
        }
    }
    if (J2 > SEUIL_ACTION_HAUT) {
        if (perso.position.colonne > 0) {
            deplacerPerso(-1, 0);
        } else if (zoneActuelleX > 0) {
            changerZone(zoneActuelleX - 1, zoneActuelleY, "gauche");
        }
    }
}