/// This file has been generated, if you wish to
/// modify it in a permanent way, please refer
/// to the script file : gen/generator_cxx.rb

#include "prologin.hh"
#include <queue>
using namespace std;

int t[25][25] = {};
position delta[4] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
vector<int> contenaire[4];
int reste[4] = {0};
position p1[4];
position p2[4];
position ps[4];
vector<position> v[5];



struct lp
{
    int pa;
    position pos;
    bool operator<(const lp& b) const {
        return b.pa < pa;
}
};

int type(position a)
{
    if (type_case(a) == LIBRE)
        return 0;
    return 1;
}

bool good(position a, position b)
{
    return (0 <= a.ligne + b.ligne &&
            25 > a.ligne + b.ligne &&
            0 <= a.colonne + b.colonne &&
            25 > a.colonne + b.colonne &&
            t[a.ligne + b.ligne][a.colonne + b.colonne] == 0);
}

bool good2(position a, position b)
{
    return (0 <= a.ligne + b.ligne &&
            25 > a.ligne + b.ligne &&
            0 <= a.colonne + b.colonne &&
            25 > a.colonne + b.colonne &&
            t[a.ligne + b.ligne][a.colonne + b.colonne] == 4);
}


position add(position a, position b)
{
    return {a.ligne + b.ligne, a.colonne + b.colonne};
}
position poursuite(position a, int i)
{
    while(good(a, delta[i]))
        a = add(a, delta[i]);
    return a;
}

direction convertisseur(int i)
{
    if(i == 0)
        return EST;
    if(i == 1)
        return SUD;
    if(i == 2)
        return OUEST;
    return NORD;
}


bool djikstra(position a, position b, int bound, int manchot)
{
    int k[25][25] = {};
    priority_queue<lp> ko;
    ko.push({0, a});
    lp dechet[25][25];
    contenaire[manchot].clear();
    vector<int>inverse;
    while(!ko.empty())
    {
        lp r = ko.top();
        ko.pop();
        for(int i = 0; i < 4; i++)
        {
            if(good(r.pos, delta[i]) && k[r.pos.ligne + delta[i].ligne][r.pos.colonne + delta[i].colonne] == false && r.pa + 1 <= bound)
            {
                ko.push({r.pa + 1, add(r.pos, delta[i])});
                k[r.pos.ligne + delta[i].ligne][r.pos.colonne + delta[i].colonne] = true;
                dechet[r.pos.ligne + delta[i].ligne][r.pos.colonne + delta[i].colonne] = {i, r.pos};
            }
        }
        for(int i = 0; i < 4; i++)
        {
            position sol = poursuite(r.pos, i);
            if(k[sol.ligne][sol.colonne] == false && r.pa + 3 <= bound)
            {
                ko.push({r.pa + 3, sol});
                k[sol.ligne][sol.colonne] = true;
                dechet[sol.ligne][sol.colonne] = {i + 4, r.pos};
            }
        }
        if(r.pos == b)
        {
            position temp = b;
            while(a != temp)
            {
                inverse.push_back(dechet[temp.ligne][temp.colonne].pa);
                temp = dechet[temp.ligne][temp.colonne].pos;
            }
            for(int i = int(inverse.size()) - 1; i >= 0; i--)
                contenaire[manchot].push_back(inverse[i]);
            return true;
        }
    }
    return false;
}

int moveto(int i)
{
    int mi = 10;
    if (int(contenaire[i].size()) <= 8)
    {
        mi = 1;
        for(int k = 0; k < int(contenaire[i].size()); k++)
        {
            if(contenaire[i][k] == 0)
                deplacer(i, EST);
            if(contenaire[i][k] == 1)
                deplacer(i, SUD);
            if(contenaire[i][k] == 2)
                deplacer(i, OUEST);
            if(contenaire[i][k] == 3)
                deplacer(i, NORD);
            if(contenaire[i][k] == 4)
                glisser(i, EST);
            if(contenaire[i][k] == 5)
                glisser(i, SUD);
            if(contenaire[i][k] == 6)
                glisser(i, OUEST);
            if(contenaire[i][k] == 7)
                glisser(i, NORD);
        }
    }
    else
        for(int k = 0; k < 8; k++)
        {
            if(contenaire[i][k] == 0)
                deplacer(i, EST);
            if(contenaire[i][k] == 1)
                deplacer(i, SUD);
            if(contenaire[i][k] == 2)
                deplacer(i, OUEST);
            if(contenaire[i][k] == 3)
                deplacer(i, NORD);
            if(contenaire[i][k] == 4)
                glisser(i, EST);
            if(contenaire[i][k] == 5)
                glisser(i, SUD);
            if(contenaire[i][k] == 6)
                glisser(i, OUEST);
            if(contenaire[i][k] == 7)
                glisser(i, NORD);
        }

    vector<int> contenaireBis;
    for(int k = 8; k < int(contenaire[i].size()); k++)
        contenaireBis.push_back(contenaire[i][k]);
    contenaire[i] = contenaireBis;

    for(int k = 0; k < 25; k++)
        for(int j = 0; j < 25; j++)
            t[k][j] = type({k, j});
    for(int k = 0; k < 4; k++)
    {
        p1[k] = position_agent(moi(), k);
        p2[k] = position_agent(adversaire(), k);
        t[p1[k].ligne][p1[k].colonne] = 3;
        t[p2[k].ligne][p2[k].colonne] = 4;
    }
    return mi;
}

int defense(int i)
{
    for(int k = 0; k < 4; k++)
        if(good2(p1[i], delta[k]))
            pousser(i, convertisseur(k));
    return (reste[i] + 1) % 4;
}

/// Fonction appelée au début de la partie.
void partie_init()
{
  // fonction a completer
}

/// Fonction appelée à chaque tour.
void jouer_tour()
{
    int tour = tour_actuel();
    for(int i = 0; i < 25; i++)
        for(int j = 0; j < 25; j++)
            t[i][j] = type({i, j});
    for(int i = 0; i < 4; i++)
    {
        p1[i] = position_agent(moi(), i);
        p2[i] = position_agent(adversaire(), i);
        t[p1[i].ligne][p1[i].colonne] = 3;
        t[p2[i].ligne][p2[i].colonne] = 4;
        if(reste[i] == 10)
            reste[i] = moveto(i);
        else if(reste[i] != 0 && p1[i] == position_agent(moi(), i))
            reste[i] = defense(i);
        else if(p1[i] != position_agent(moi(), i))
            reste[i] = 0;
    }
    vector<alien_info> s = liste_aliens();
    for(int j = 0; j < 5; j++)
    {
        v[j].clear();
        for(int i = 0; i < int(s.size()); i++)
            if(s[i].tour_invasion + j - 5 <= tour && s[i].tour_invasion + s[i].duree_invasion >= tour + 3 + j)
                v[j].push_back(s[i].pos);
    }
    for(int i = 0; i < 4; i++)
    {
        for(int j = 0; j < int(v[1].size()); j++)
        {
            if(djikstra(p1[i], v[1][j], 8, i) && reste[i] == 0)
            {
                reste[i] = moveto(i);
                break;
            }
        }
    }
    for(int k = 0; k < 5; k++)
    {
        for(int i = 0; i < 4; i++)
        {
            for(int j = 0; j < int(v[k].size()); j++)
            {
                if(djikstra(p1[i], v[k][j], 8*k, i) && reste[i] == 0)
                {
                    moveto(i);
                    reste[i]+= 10;
                    break;
                }
            }
        }
    }
}

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





















