// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2012-2020 Association Prologin <association@prologin.org>

// This file contains all the API functions for the C++ language, and all the
// constants, enumerations and structures.
// This file was generated by stechec2-generator. DO NOT EDIT.

#pragma once

#include <string>
#include <vector>

/// Nombre de lignes dans la carte
#define HAUTEUR 40

/// Nombre de colonnes dans la carte
#define LARGEUR 40

/// Nombre de tours à jouer avant la fin de la partie
#define NB_TOURS 400

/// Taille de départ d'une troupe
#define TAILLE_DEPART 5

/// Taille minimale qu'une troupe peut avoir avant de se disperser
#define TAILLE_MIN 3

/// Nombre de troupes que chaque joueur controle
#define NB_TROUPES 2

/// Intervalle de distribution de pains par les papys
#define INTERVALLE_DISTRIB 5

/// Nombre de tunnels qu'un joueur peut creuser par tour
#define FREQ_TUNNEL 1

/// Nombre de déplacements que peut faire une troupe en un tour
#define PTS_ACTION 5

/// Nombre de points de mouvement requis pour incrémenter la taille
#define COUT_CROISSANCE 3

/// Coût en score de la pose de buisson
#define COUT_BUISSON 3

/// Round à la fin duquel les barrières s'ouvrent ou se ferment
#define ROUND_FERMETURE 99

/// Erreurs possibles après avoir effectué une action
typedef enum erreur
{
    OK, ///< L'action a été effectuée avec succès
    TROUPE_INVALIDE, ///< Mauvais identifiant de troupe
    HORS_TOUR, ///< Aucune action n'est possible hors de joueur_tour
    MOUVEMENTS_INSUFFISANTS, ///< Il ne reste plus assez de points de mouvements pour effectuer l'action demandée
    TROP_GRANDI, ///< La troupe a déjà trop grandi pendant le tour
    TROP_CREUSE, ///< Trop de trous ont déjà été creusés pendant le tour
    NON_CREUSABLE, ///< Il n'est pas possible de creuser à la position demandée
    NON_CONSTRUCTIBLE, ///< La zone demandée n'est pas constructible
    SCORE_INSUFFISANT, ///< Le joueur n'a pas assez de points pour construire un buisson
    POSITION_INVALIDE, ///< La position demandée est hors du parc
    DIRECTION_INVALIDE, ///< La direction spécifiée n'existe pas.
    PIGEON_INVALIDE, ///< Le pigeon spécifié n'existe pas.
} erreur;

/// Directions possibles
typedef enum direction
{
    NORD, ///< Sens positif pour les lignes
    SUD, ///< Sens négatif pour les lignes
    EST, ///< Sens positif pour les colonnes
    OUEST, ///< Sens négatif pour les colonnes
    HAUT, ///< Sens positif pour le niveau
    BAS, ///< Sens négatif pour le niveau
} direction;

/// Type de l'élément présent sur une case
typedef enum type_case
{
    GAZON, ///< Absence d'élément
    BUISSON, ///< Obstacle impossible à traverser
    BARRIERE, ///< Élément pouvant être ouvert ou fermé. Une barrière fermée est infranchissable alors qu'une barrière ouverte est analogue à une case vide
    NID, ///< Élément traversable permettant à la troupe de déposer son inventaire en échange de points
    PAPY, ///< Élément traversable générant de manière périodique des miches de pain
    TROU, ///< Interface entre le niveau principal est le niveau souterrain
    TUNNEL, ///< Bloc du souterrain ayant été creusé
    TERRE, ///< Bloc du souterrain n'ayant pas encore été creusé
} type_case;

/// État d'une barrière, soit ouvert, soit fermé, soit non-applicable
typedef enum etat_barriere
{
    OUVERTE, ///< La barrière est ouverte
    FERMEE, ///< La barrière est fermée
    PAS_DE_BARRIERE, ///< L'élément dont on requiert l'état n'est pas une barrière
} etat_barriere;

/// Joueur auquel appartient un nid
typedef enum etat_nid
{
    LIBRE, ///< Le nid n'a pas été attribué
    JOUEUR_0, ///< Joueur 0
    JOUEUR_1, ///< Joueur 1
    PAS_DE_NID, ///< L'élément dont on requiert l'état n'est pas un nid
} etat_nid;

/// Type de pigeon de debug
typedef enum pigeon_debug
{
    PAS_DE_PIGEON, ///< Aucun pigeon, enlève le pigeon présent
    PIGEON_BLEU, ///< Pigeon bleu
    PIGEON_JAUNE, ///< Pigeon jaune
    PIGEON_ROUGE, ///< Pigeon rouge
} pigeon_debug;

/// Types d'actions
typedef enum type_action
{
    ACTION_AVANCER, ///< Action ``avancer``
    ACTION_GRANDIR, ///< Action ``grandir``
    ACTION_CONSTRUIRE, ///< Action ``construire buisson``
    ACTION_CREUSER, ///< Action ``creuser tunnel``
} type_action;

/// Position dans la carte, donnée par trois coordonnées
typedef struct position
{
    int colonne; ///< Abscisse
    int ligne; ///< Ordonnée
    int niveau; ///< Niveau
} position;

/// Une troupe, composée de la maman canard et de ses canetons
typedef struct troupe
{
    position maman; ///< Position de la maman canard
    std::vector<position> canards; ///< Position des différents canards de la troupe, incluant la maman en première position
    int taille; ///< Taille de la troupe
    direction dir; ///< Direction de la troupe
    int inventaire; ///< Nombre de pains de la troupe
    int pts_action; ///< Nombre de points d'action de la troupe
    int id; ///< Identifiant de la troupe
} troupe;

/// Élément constituant le parc
typedef struct etat_case
{
    position pos; ///< Position de la case. Le niveau vaut nécessairement 0
    type_case contenu; ///< Type de la case
    bool est_constructible; ///< La case est constructible
    int nb_pains; ///< Nombre de pains contenus sur la case
} etat_case;

/// Action représentée dans l'historique
typedef struct action_hist
{
    type_action action_type; ///< Type de l'action
    int troupe_id; ///< Identifiant de la troupe
    direction action_dir; ///< Direction de l'action
    position action_pos; ///< Position de l'action
} action_hist;

/// La troupe avance d'une case vers une direction donnée
erreur avancer(int id, direction dir);

/// La troupe grandit
erreur grandir(int id);

/// Construit un buisson à la position donnée
erreur construire_buisson(position pos);

/// Creuse un tunnel à la position donnée
erreur creuser_tunnel(position pos);

/// Renvoie les informations concernant une case
etat_case info_case(position pos);

/// Renvoie les informations d'état d'une barrière
etat_barriere info_barriere(position pos);

/// Renvoie les informations d'état d'un nid
etat_nid info_nid(position pos);

/// Renvoie le nombre de tours restants avant qu'un papy dépose une miche de
/// pain. Retourne -1 si aucun papy ne se trouve à la position demandée
int papy_tours_restants(position pos);

/// Renvoie les troupes d'un joueur. Si le joueur est invalide, tous les champs
/// valent -1.
std::vector<troupe> troupes_joueur(int id_joueur);

/// Renvoie la position des pains récupérables
std::vector<position> pains();

/// Pose un pigeon de debug sur la case indiquée
erreur debug_poser_pigeon(position pos, pigeon_debug pigeon);

/// Renvoie la liste des actions effectuées par l'adversaire durant son tour,
/// dans l'ordre chronologique. Les actions de débug n'apparaissent pas dans
/// cette liste.
std::vector<action_hist> historique();

/// Renvoie le gain en score que le nombre de pains passé en entrée
/// rapporterait s'ils étaient tous déposés d'un coup dans un nid
int gain(int nb_pains);

/// Renvoie la taille de l'inventaire d'une troupe de taille donnée
int inventaire(int taille);

/// Trouve un plus court chemin ouvert entre deux positions. Renvoie une liste
/// vide si les deux positions sont égales ou si aucun chemin n'existe.
std::vector<direction> trouver_chemin(position depart, position arrivee);

/// Renvoie votre numéro de joueur.
int moi();

/// Renvoie le numéro du joueur adverse.
int adversaire();

/// Renvoie le score du joueur `id_joueur`. Renvoie -1 si le joueur est
/// invalide.
int score(int id_joueur);

/// Annule la dernière action. Renvoie faux quand il n'y a pas d'action à
/// annuler ce tour-ci
bool annuler();

/// Retourne le numéro du tour actuel.
int tour_actuel();

/// Affiche le contenu d'une valeur de type erreur
void afficher_erreur(erreur v);

/// Affiche le contenu d'une valeur de type direction
void afficher_direction(direction v);

/// Affiche le contenu d'une valeur de type type_case
void afficher_type_case(type_case v);

/// Affiche le contenu d'une valeur de type etat_barriere
void afficher_etat_barriere(etat_barriere v);

/// Affiche le contenu d'une valeur de type etat_nid
void afficher_etat_nid(etat_nid v);

/// Affiche le contenu d'une valeur de type pigeon_debug
void afficher_pigeon_debug(pigeon_debug v);

/// Affiche le contenu d'une valeur de type type_action
void afficher_type_action(type_action v);

/// Affiche le contenu d'une valeur de type position
void afficher_position(position v);

/// Affiche le contenu d'une valeur de type troupe
void afficher_troupe(troupe v);

/// Affiche le contenu d'une valeur de type etat_case
void afficher_etat_case(etat_case v);

/// Affiche le contenu d'une valeur de type action_hist
void afficher_action_hist(action_hist v);

// -----
// API ends here, you can stop reading now.
// The rest of the file is generated operators for the structs defined above.
// -----

namespace std
{
template <typename T>
struct hash<std::vector<T>>
{
    std::size_t operator()(const std::vector<T>& v) const
    {
        std::size_t res = v.size();
        for (const auto& e : v)
            res ^= std::hash<T>()(e) + 0x9e3779b9 + (res << 6) + (res >> 2);
        return res;
    }
};
} // namespace std

inline bool operator==(const position& a, const position& b)
{
    if (a.colonne != b.colonne)
        return false;
    if (a.ligne != b.ligne)
        return false;
    if (a.niveau != b.niveau)
        return false;
    return true;
}

inline bool operator!=(const position& a, const position& b)
{
    return !(a == b);
}

inline bool operator<(const position& a, const position& b)
{
    if (a.colonne < b.colonne)
        return true;
    if (a.colonne > b.colonne)
        return false;
    if (a.ligne < b.ligne)
        return true;
    if (a.ligne > b.ligne)
        return false;
    if (a.niveau < b.niveau)
        return true;
    if (a.niveau > b.niveau)
        return false;
    return false;
}

inline bool operator>(const position& a, const position& b)
{
    if (a.colonne > b.colonne)
        return true;
    if (a.colonne < b.colonne)
        return false;
    if (a.ligne > b.ligne)
        return true;
    if (a.ligne < b.ligne)
        return false;
    if (a.niveau > b.niveau)
        return true;
    if (a.niveau < b.niveau)
        return false;
    return false;
}

namespace std
{
template <>
struct hash<position>
{
    std::size_t operator()(const position& s) const
    {
        std::size_t res = 0;
        res ^= 0x9e3779b9 + (res << 6) + (res >> 2) + std::hash<int>()(s.colonne);
        res ^= 0x9e3779b9 + (res << 6) + (res >> 2) + std::hash<int>()(s.ligne);
        res ^= 0x9e3779b9 + (res << 6) + (res >> 2) + std::hash<int>()(s.niveau);
        return res;
    }
};
} // namespace std
inline bool operator==(const troupe& a, const troupe& b)
{
    if (a.maman != b.maman)
        return false;
    if (a.canards != b.canards)
        return false;
    if (a.taille != b.taille)
        return false;
    if (a.dir != b.dir)
        return false;
    if (a.inventaire != b.inventaire)
        return false;
    if (a.pts_action != b.pts_action)
        return false;
    if (a.id != b.id)
        return false;
    return true;
}

inline bool operator!=(const troupe& a, const troupe& b)
{
    return !(a == b);
}

inline bool operator<(const troupe& a, const troupe& b)
{
    if (a.maman < b.maman)
        return true;
    if (a.maman > b.maman)
        return false;
    if (a.canards < b.canards)
        return true;
    if (a.canards > b.canards)
        return false;
    if (a.taille < b.taille)
        return true;
    if (a.taille > b.taille)
        return false;
    if (a.dir < b.dir)
        return true;
    if (a.dir > b.dir)
        return false;
    if (a.inventaire < b.inventaire)
        return true;
    if (a.inventaire > b.inventaire)
        return false;
    if (a.pts_action < b.pts_action)
        return true;
    if (a.pts_action > b.pts_action)
        return false;
    if (a.id < b.id)
        return true;
    if (a.id > b.id)
        return false;
    return false;
}

inline bool operator>(const troupe& a, const troupe& b)
{
    if (a.maman > b.maman)
        return true;
    if (a.maman < b.maman)
        return false;
    if (a.canards > b.canards)
        return true;
    if (a.canards < b.canards)
        return false;
    if (a.taille > b.taille)
        return true;
    if (a.taille < b.taille)
        return false;
    if (a.dir > b.dir)
        return true;
    if (a.dir < b.dir)
        return false;
    if (a.inventaire > b.inventaire)
        return true;
    if (a.inventaire < b.inventaire)
        return false;
    if (a.pts_action > b.pts_action)
        return true;
    if (a.pts_action < b.pts_action)
        return false;
    if (a.id > b.id)
        return true;
    if (a.id < b.id)
        return false;
    return false;
}

namespace std
{
template <>
struct hash<troupe>
{
    std::size_t operator()(const troupe& s) const
    {
        std::size_t res = 0;
        res ^= 0x9e3779b9 + (res << 6) + (res >> 2) + std::hash<position>()(s.maman);
        res ^= 0x9e3779b9 + (res << 6) + (res >> 2) + std::hash<std::vector<position>>()(s.canards);
        res ^= 0x9e3779b9 + (res << 6) + (res >> 2) + std::hash<int>()(s.taille);
        res ^= 0x9e3779b9 + (res << 6) + (res >> 2) + std::hash<direction>()(s.dir);
        res ^= 0x9e3779b9 + (res << 6) + (res >> 2) + std::hash<int>()(s.inventaire);
        res ^= 0x9e3779b9 + (res << 6) + (res >> 2) + std::hash<int>()(s.pts_action);
        res ^= 0x9e3779b9 + (res << 6) + (res >> 2) + std::hash<int>()(s.id);
        return res;
    }
};
} // namespace std
inline bool operator==(const etat_case& a, const etat_case& b)
{
    if (a.pos != b.pos)
        return false;
    if (a.contenu != b.contenu)
        return false;
    if (a.est_constructible != b.est_constructible)
        return false;
    if (a.nb_pains != b.nb_pains)
        return false;
    return true;
}

inline bool operator!=(const etat_case& a, const etat_case& b)
{
    return !(a == b);
}

inline bool operator<(const etat_case& a, const etat_case& b)
{
    if (a.pos < b.pos)
        return true;
    if (a.pos > b.pos)
        return false;
    if (a.contenu < b.contenu)
        return true;
    if (a.contenu > b.contenu)
        return false;
    if (a.est_constructible < b.est_constructible)
        return true;
    if (a.est_constructible > b.est_constructible)
        return false;
    if (a.nb_pains < b.nb_pains)
        return true;
    if (a.nb_pains > b.nb_pains)
        return false;
    return false;
}

inline bool operator>(const etat_case& a, const etat_case& b)
{
    if (a.pos > b.pos)
        return true;
    if (a.pos < b.pos)
        return false;
    if (a.contenu > b.contenu)
        return true;
    if (a.contenu < b.contenu)
        return false;
    if (a.est_constructible > b.est_constructible)
        return true;
    if (a.est_constructible < b.est_constructible)
        return false;
    if (a.nb_pains > b.nb_pains)
        return true;
    if (a.nb_pains < b.nb_pains)
        return false;
    return false;
}

namespace std
{
template <>
struct hash<etat_case>
{
    std::size_t operator()(const etat_case& s) const
    {
        std::size_t res = 0;
        res ^= 0x9e3779b9 + (res << 6) + (res >> 2) + std::hash<position>()(s.pos);
        res ^= 0x9e3779b9 + (res << 6) + (res >> 2) + std::hash<type_case>()(s.contenu);
        res ^= 0x9e3779b9 + (res << 6) + (res >> 2) + std::hash<bool>()(s.est_constructible);
        res ^= 0x9e3779b9 + (res << 6) + (res >> 2) + std::hash<int>()(s.nb_pains);
        return res;
    }
};
} // namespace std
inline bool operator==(const action_hist& a, const action_hist& b)
{
    if (a.action_type != b.action_type)
        return false;
    if (a.troupe_id != b.troupe_id)
        return false;
    if (a.action_dir != b.action_dir)
        return false;
    if (a.action_pos != b.action_pos)
        return false;
    return true;
}

inline bool operator!=(const action_hist& a, const action_hist& b)
{
    return !(a == b);
}

inline bool operator<(const action_hist& a, const action_hist& b)
{
    if (a.action_type < b.action_type)
        return true;
    if (a.action_type > b.action_type)
        return false;
    if (a.troupe_id < b.troupe_id)
        return true;
    if (a.troupe_id > b.troupe_id)
        return false;
    if (a.action_dir < b.action_dir)
        return true;
    if (a.action_dir > b.action_dir)
        return false;
    if (a.action_pos < b.action_pos)
        return true;
    if (a.action_pos > b.action_pos)
        return false;
    return false;
}

inline bool operator>(const action_hist& a, const action_hist& b)
{
    if (a.action_type > b.action_type)
        return true;
    if (a.action_type < b.action_type)
        return false;
    if (a.troupe_id > b.troupe_id)
        return true;
    if (a.troupe_id < b.troupe_id)
        return false;
    if (a.action_dir > b.action_dir)
        return true;
    if (a.action_dir < b.action_dir)
        return false;
    if (a.action_pos > b.action_pos)
        return true;
    if (a.action_pos < b.action_pos)
        return false;
    return false;
}

namespace std
{
template <>
struct hash<action_hist>
{
    std::size_t operator()(const action_hist& s) const
    {
        std::size_t res = 0;
        res ^= 0x9e3779b9 + (res << 6) + (res >> 2) + std::hash<type_action>()(s.action_type);
        res ^= 0x9e3779b9 + (res << 6) + (res >> 2) + std::hash<int>()(s.troupe_id);
        res ^= 0x9e3779b9 + (res << 6) + (res >> 2) + std::hash<direction>()(s.action_dir);
        res ^= 0x9e3779b9 + (res << 6) + (res >> 2) + std::hash<position>()(s.action_pos);
        return res;
    }
};
} // namespace std

extern "C"
{
    void partie_init();
    void jouer_tour();
    void partie_fin();
}
