/*
 * ALGORITHME GLOUTON
 * 
 * DE NOMBREUSES HEURISTIQUES POUR GUIDER LA CONSTRUCTION DANS UN PREMIER TEMPS
 * 
 * PUIS DES MOYENS D'ATTAQUER LORSQUE LA CONSTRUCTION CESSE D'ETRE RENTABLE
 * 
 * AMELIORATION ET REPARATION OCCASIONNELLES DE TUYAUX JUGES IMPORTANTS
 * 
 * UTILISE ESSENTIELLEMENT PLEIN DE DIJKSTRAS AVEC DIVERSES PONDERATIONS ET DIVERS ARETES POUR FABRIQUER DES CARTES DE CONTROLE POUR CHAQUE JOUEUR
 * UTILISE LES INFLUENCES DES BASES, LA DIRECTIONS DU PLAMA, ETC...
 * 
 * L'ALEATOIRE JOUE UN ROLE MINEUR : EN MOYENNE LES ACTIONS EFFECTUEES SONT LES MEMES, SEUL L'ORDRE CHANGE
 * */

#include <algorithm>
#include <cstdlib>
#include <iostream>

#include "prologin.hh"
#include "pathfinding.hh"
#include "duel.hh"

using namespace std;

bool first;

// INITIER RANDOM
void partie_init()
{
    first = false;
    size_t res = 0;
    vector<position> pulsars= liste_pulsars();
    for (const auto& pos : pulsars) {
        res ^= 0x9e3779b9 + (res << 6) + (res >> 2) + hash<position>()(pos);
    }
    res ^= 0x9e3779b9 + (res << 6) + (res >> 2) + moi();
    srand(res);
}

// ON DIRIGE L'ASPIRATION VERS LES BASES LES PLUS UTILISEES
void aspirateurManager() {
    vector<position> bases = ma_base();
    vector<vector<int>> poids = dijkstra(poidsUniforme(liste_pulsars(), 0), toutChemins, reseauEtTrous);
    sort(begin(bases), end(bases), 
         [&](position a, position b) {
             position c = departTuyau(a);
             position d = departTuyau(b);
             return poids[c.x][c.y] < poids[d.x][d.y];
        });
    
    auto bourreau = bases.begin(); 
    auto victime = bases.rbegin();
    while (bourreau != bases.end() 
        && puissance_aspiration(*bourreau) == LIMITE_ASPIRATION)
        ++bourreau;
    while (victime != bases.rend() 
           && puissance_aspiration(*victime) == 0 
           && !(*victime == *bourreau))
        ++victime;
    
    if (bourreau != bases.end() 
        && victime != bases.rend()
        && !(*victime == *bourreau))
        deplacer_aspiration(*victime, *bourreau);
}

// PERIME - NON UTILISE
void construireTuyaux() {
    while (points_action() >= COUT_CONSTRUCTION) {
        
        vector<vector<int>> poids = dijkstra(poidsUniforme(ma_base(), 0), toutChemins, reseauEtTrous);
        vector<position> adjacent;
        for (int x = 0; x < TAILLE_TERRAIN; ++x)
            for (int y = 0; y < TAILLE_TERRAIN; ++y)
                if (poids[x][y] == 1 && type_case(makePos(x,y)) == VIDE)
                    adjacent.push_back(makePos(x,y));
        vector<Pulsar> pulsars = pulsarsLibres();
        
        if (adjacent.empty() || pulsars.empty())
            break;
        
        double meilleurScore = 0.0;
        position meilleurPotentiel;
        for (const auto& potentiel: adjacent) {
            double score = 0.0;
            for (const auto& pulsar: pulsars) {
                int d = d1(potentiel, pulsar.site);
                score += pulsar.puissanceMoyenne()/(d*d);
            }
            if (score > meilleurScore) {
                meilleurScore = score;
                meilleurPotentiel = potentiel;
            }
        }
        
        if (est_debris(meilleurPotentiel))
            deblayer(meilleurPotentiel);
        construire(meilleurPotentiel);
    }
}

// ITERER DES ACTIONS ELEMENTAIRES TANT AUE POSSIBLE, DE CONSTRUCTION DE DEFENSE
void installerTuyaux() {
    while (points_action() >= COUT_CONSTRUCTION) {
        int avant = points_action();
        choisirItineraire();
        if (points_action() == avant)
            return;
    }
}

void attaquer() {
    while (points_action() >= COUT_DESTRUCTION) {
        int avant = points_action();
        shoot();
        if (points_action() == avant)
            return;
    }
}

// UN PEU ALEATOIRE, PARCE QUE VOILA
void jouer_tour()
{
    if (!first || rand()%4 == 0) {
        first = shoot();
    }
    installerTuyaux();
    aspirateurManager();
    if (rand()%2 == 0) {
        attaquer();
        renforcer();
    } else {
        renforcer();
        attaquer();
    }
}

void partie_fin()
{ }

