#include "api.hh"
#include <iostream>
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <map>
using namespace std;

#define Map vector<vector<etat_case>> 


struct EPosition{  // Enhanced position
    int colonne;
    int ligne;
    int niveau;
    position mama_pos;

    bool operator<(const EPosition& other){
        int diffx = (colonne - mama_pos.colonne), diffy = (ligne - mama_pos.ligne);
        int dist_sq = diffx * diffx + diffy * diffy;

        int other_diffx = (other.colonne - other.mama_pos.colonne), other_diffy = (other.ligne - other.mama_pos.ligne);
        int other_dist_sq = other_diffx * other_diffx + other_diffy * other_diffy;
        return dist_sq < other_dist_sq;
    }
};


#pragma region Constantes
const int CONQUETE_NIDS = 0;
const int RECHERCHE_PAIN = 1;
const int NEST_SEARCH_TURN_LIMIT = 26;
const int OPTIMAL_LENGTH = 7;
const vector<pair<int, int>> DIR = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
#pragma endregion

#pragma region Variables
int player_id;
vector<position> nids(0);
vector<position> nids_obtenus(0);
int current_phase;
map<int, vector<direction>> paths;
map<direction, pair<int, int>> MDIR;
#pragma endregion



vector<position> sort_by_distance(vector<position>& pos, position& mama_pos){
    
    vector<EPosition> ep(pos.size());
    for(int i = 0; i < pos.size(); i++){
        ep.at(i) = {pos.at(i).colonne, pos.at(i).ligne, pos.at(i).niveau, mama_pos};
    }

    sort(ep.begin(), ep.end());

    vector<position> ret(pos.size());
    for(int i = 0; i < pos.size(); i++){
        ret.at(i) = {ep.at(i).colonne, ep.at(i).ligne, ep.at(i).niveau};
    }
    return ret;
}

// Fonction appelée au début de la partie.
void partie_init(void)
{
    player_id = moi();
    current_phase = CONQUETE_NIDS;
    MDIR[NORD] = make_pair(0, 1);
    MDIR[SUD] = make_pair(0, -1);
    MDIR[EST] = make_pair(1, 0);
    MDIR[OUEST] = make_pair(-1, 0);


    for(troupe tr : troupes_joueur(player_id)){
        paths[tr.id] = vector<direction>(0);
    }

    #pragma region Charge la carte
    for(int y = 0; y < HAUTEUR; y++){
        for(int x = 0; x < LARGEUR; x++){
            position pos = {y, x, 0};
            // ajoute au tableau si c'est un nid
            if(info_case(pos).contenu == NID){
                nids.push_back(pos);
            }
        }
    }
    #pragma endregion
}


int go2target(const troupe& tr, const vector<position>& target_list, int pts=PTS_ACTION){  // Renvoie les pts restants
    debug_poser_pigeon(tr.maman, PIGEON_JAUNE);
    vector<position> targets = target_list;
    int action_pt = pts;

    for(position target_pos : targets){
        vector<direction> path = trouver_chemin(tr.maman, target_pos);

        erreur can_continue = OK;
        

        while(can_continue == OK && path.size() > 0){
            can_continue = avancer(tr.id, path.at(0));
            path.erase(path.begin());
            action_pt--;
        }
        
    }

    if(action_pt > 0){
        for(int i = 0; i < 10; i++){
            position pig = {39, i, 0};
            debug_poser_pigeon(pig, PIGEON_ROUGE);
        }
    }

    return action_pt;
}


void jouer_tour(void)
{
    for(troupe tr : troupes_joueur(player_id)){
        int action_pts = PTS_ACTION;
        if(current_phase == CONQUETE_NIDS){
            vector<position> available_nest(0);

            nids_obtenus.clear();
            for(position nest_pos : nids){
                etat_nid etat = info_nid(nest_pos);
                if(etat == LIBRE){
                    available_nest.push_back(nest_pos);
                }
                if(etat == player_id){
                    nids_obtenus.push_back(nest_pos);
                }
            } 

            if(available_nest.size() > 0 && tour_actuel() < NEST_SEARCH_TURN_LIMIT){
                action_pts = go2target(tr, sort_by_distance(available_nest, tr.maman), action_pts);
            }else{
                current_phase = RECHERCHE_PAIN;
            }

        }
        if(current_phase == RECHERCHE_PAIN){
            if(tr.taille < OPTIMAL_LENGTH && action_pts > COUT_CROISSANCE - 1){
                grandir(tr.id);
                action_pts -= COUT_CROISSANCE;
            }
            if(tour_actuel() % 5 == 0 && action_pts > COUT_CROISSANCE - 1){
                grandir(tr.id);
                action_pts -= COUT_CROISSANCE;
            }
            
            if(tr.inventaire == inventaire(tr.taille)){
                action_pts = go2target(tr, sort_by_distance(nids_obtenus, tr.maman), action_pts);
            }

            vector<position> br = pains();
            action_pts = go2target(tr, sort_by_distance(br, tr.maman), action_pts);
        }

        if(action_pts > COUT_CROISSANCE - 1){
            for(int i = 0; i < 10; i++){
                position pig = {0, i, 0};
                debug_poser_pigeon(pig, PIGEON_BLEU);
            }
            grandir(tr.id);
	    action_pts -= COUT_CROISSANCE;
        }
    }
}

// Fonction appelée à la fin de la partie.
void partie_fin(void)
{
    // TODO
    
    
}
