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


using System.Runtime.CompilerServices;

namespace Champion {
    // Erreurs possibles après avoir effectué une action
    public 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.
    }

    // Directions possibles
    public 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
    }

    // Type de l'élément présent sur une case
    public enum TypeCase {
        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é
    }

    // État d'une barrière, soit ouvert, soit fermé, soit non-applicable
    public enum EtatBarriere {
        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
    }

    // Joueur auquel appartient un nid
    public enum EtatNid {
        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
    }

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

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

    // Position dans la carte, donnée par trois coordonnées
    class Position {
        public Position() {}
        public int Colonne; //< Abscisse
        public int Ligne; //< Ordonnée
        public int Niveau; //< Niveau
    }

    // Une troupe, composée de la maman canard et de ses canetons
    class Troupe {
        public Troupe() {}
        public Position Maman; //< Position de la maman canard
        public Position[] Canards; //< Position des différents canards de la troupe, incluant la maman en première position
        public int Taille; //< Taille de la troupe
        public Direction Dir; //< Direction de la troupe
        public int Inventaire; //< Nombre de pains de la troupe
        public int PtsAction; //< Nombre de points d'action de la troupe
        public int Id; //< Identifiant de la troupe
    }

    // Élément constituant le parc
    class EtatCase {
        public EtatCase() {}
        public Position Pos; //< Position de la case. Le niveau vaut nécessairement 0
        public TypeCase Contenu; //< Type de la case
        public bool EstConstructible; //< La case est constructible
        public int NbPains; //< Nombre de pains contenus sur la case
    }

    // Action représentée dans l'historique
    class ActionHist {
        public ActionHist() {}
        public TypeAction ActionType; //< Type de l'action
        public int TroupeId; //< Identifiant de la troupe
        public Direction ActionDir; //< Direction de l'action
        public Position ActionPos; //< Position de l'action
    }

    class Api {

        // Nombre de lignes dans la carte
        public const int HAUTEUR = 40;

        // Nombre de colonnes dans la carte
        public const int LARGEUR = 40;

        // Nombre de tours à jouer avant la fin de la partie
        public const int NB_TOURS = 400;

        // Taille de départ d'une troupe
        public const int TAILLE_DEPART = 5;

        // Taille minimale qu'une troupe peut avoir avant de se disperser
        public const int TAILLE_MIN = 3;

        // Nombre de troupes que chaque joueur controle
        public const int NB_TROUPES = 2;

        // Intervalle de distribution de pains par les papys
        public const int INTERVALLE_DISTRIB = 5;

        // Nombre de tunnels qu'un joueur peut creuser par tour
        public const int FREQ_TUNNEL = 1;

        // Nombre de déplacements que peut faire une troupe en un tour
        public const int PTS_ACTION = 5;

        // Nombre de points de mouvement requis pour incrémenter la taille
        public const int COUT_CROISSANCE = 3;

        // Coût en score de la pose de buisson
        public const int COUT_BUISSON = 3;

        // Round à la fin duquel les barrières s'ouvrent ou se ferment
        public const int ROUND_FERMETURE = 99;

        // La troupe avance d'une case vers une direction donnée
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern Erreur Avancer(int id, Direction dir);

        // La troupe grandit
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern Erreur Grandir(int id);

        // Construit un buisson à la position donnée
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern Erreur ConstruireBuisson(Position pos);

        // Creuse un tunnel à la position donnée
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern Erreur CreuserTunnel(Position pos);

        // Renvoie les informations concernant une case
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern EtatCase InfoCase(Position pos);

        // Renvoie les informations d'état d'une barrière
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern EtatBarriere InfoBarriere(Position pos);

        // Renvoie les informations d'état d'un nid
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern EtatNid InfoNid(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
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern int PapyToursRestants(Position pos);

        // Renvoie les troupes d'un joueur. Si le joueur est invalide, tous les champs
// valent -1.
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern Troupe[] TroupesJoueur(int id_joueur);

        // Renvoie la position des pains récupérables
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern Position[] Pains();

        // Pose un pigeon de debug sur la case indiquée
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern Erreur DebugPoserPigeon(Position pos, PigeonDebug 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.
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern ActionHist[] 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
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern int Gain(int nb_pains);

        // Renvoie la taille de l'inventaire d'une troupe de taille donnée
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern 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.
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern Direction[] TrouverChemin(Position depart, Position arrivee);

        // Renvoie votre numéro de joueur.
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern int Moi();

        // Renvoie le numéro du joueur adverse.
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern int Adversaire();

        // Renvoie le score du joueur `id_joueur`. Renvoie -1 si le joueur est
// invalide.
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern int Score(int id_joueur);

        // Annule la dernière action. Renvoie faux quand il n'y a pas d'action à
// annuler ce tour-ci
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern bool Annuler();

        // Retourne le numéro du tour actuel.
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern int TourActuel();

        // Affiche le contenu d'une valeur de type erreur
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern void AfficherErreur(Erreur v);

        // Affiche le contenu d'une valeur de type direction
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern void AfficherDirection(Direction v);

        // Affiche le contenu d'une valeur de type type_case
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern void AfficherTypeCase(TypeCase v);

        // Affiche le contenu d'une valeur de type etat_barriere
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern void AfficherEtatBarriere(EtatBarriere v);

        // Affiche le contenu d'une valeur de type etat_nid
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern void AfficherEtatNid(EtatNid v);

        // Affiche le contenu d'une valeur de type pigeon_debug
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern void AfficherPigeonDebug(PigeonDebug v);

        // Affiche le contenu d'une valeur de type type_action
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern void AfficherTypeAction(TypeAction v);

        // Affiche le contenu d'une valeur de type position
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern void AfficherPosition(Position v);

        // Affiche le contenu d'une valeur de type troupe
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern void AfficherTroupe(Troupe v);

        // Affiche le contenu d'une valeur de type etat_case
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern void AfficherEtatCase(EtatCase v);

        // Affiche le contenu d'une valeur de type action_hist
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern void AfficherActionHist(ActionHist v);
    }
}
