#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>

// ############################## Partie 1 ##############################

struct Personnage { char nom[80]; int pv; int atq; int def; };
typedef struct Personnage personnage;

// Exercice 1

personnage tori = { .nom = "Tori" , .pv = 10 , .atq = 15 , .def = 3 };
personnage uke = { .nom = "Uke" , .pv = 20 , .atq = 5 , .def = 10 };

// Exercice 2

void imprime_stats(personnage p)
{
  printf("Caractéristiques de %s : PV %d, attaque %d, défense %d.\n", p.nom, p.pv, p.atq, p.def);
}

// Exercice 3

void attaque(personnage *attaquant, personnage *defenseur, bool verbeux)
{
  assert(attaquant->pv > 0);
  assert(defenseur->pv > 0); // Pas nécessaire mais on va l'imposer quand même
  int degats = attaquant->atq - defenseur->def;
  if (degats < 1)
  {
    if (verbeux) printf("L'attaque de %s est plus faible que la défense de %s.\n", attaquant->nom, defenseur->nom);
    degats = 1;
  }
  defenseur->pv -= degats;
  printf("%s perd %d PV.\n", defenseur->nom, degats);
  if (defenseur->pv <= 0)
  {
    if (verbeux) printf("%s a perdu tous ses PV.\n", defenseur->nom);
    defenseur->pv = 0;
  }
}

// Exercice 4

void combat(personnage *p1, personnage *p2, bool verbeux)
{
  personnage *combattants[2];
  combattants[0] = p1;
  combattants[1] = p2;
  int phase = 0;
  while (p1->pv > 0 && p2->pv > 0)
  {
    attaque(combattants[phase%2], combattants[1-phase%2], verbeux);
    phase += 1;
  }
}

// Exercice 5

void initialise_personnage(personnage p[], int position, char *nom, int pv, int atq, int def)
{
  strcpy(p[position].nom, nom);
  p[position].pv = pv;
  p[position].atq = atq;
  p[position].def = def;
}

// Exercice 6

void imprime_stats_equipe(personnage *equipe, int taille)
{
  printf("Stats de l'équipe :\n\n");
  for (int i = 0 ; i < taille ; i += 1)
  {
    imprime_stats(equipe[i]);
    if (i == taille-1) printf("\n"); // Plus joli
  }
}

// Exercice 7

bool vaincue(personnage *e, int taille)
{
  for (int i = 0 ; i < taille ; i += 1)
  {
    if (e[i].pv > 0) return false;
  }
  return true;
}

void confrontation(personnage *e1, int taille1, personnage *e2, int taille2, bool verbeux)
{
  int phase = 0;
  while (!vaincue(e1, taille1) && !vaincue(e2, taille2))
  {
    if (phase < taille1)
    {
      if (e1[phase].pv > 0)
      {
        for (int i = 0 ; i < taille2 ; i += 1)
        {
          if (e2[i].pv > 0)
          {
            attaque(&e1[phase], &e2[i], verbeux);
            break;
          }
        }
      }
      phase += 1;
    }
    else
    {
      if (e2[phase-taille1].pv > 0)
      {
        for (int i = 0 ; i < taille1 ; i += 1)
        {
          if (e1[i].pv > 0)
          {
            attaque(&e2[phase-taille1], &e1[i], verbeux);
            break;
          }
        }
      }
      phase += 1;
      if (phase == taille1 + taille2) phase = 0;
    }
  }
}

int main1()
{
  // Première phase de tests
  combat(&tori, &uke, true);
  imprime_stats(tori);
  imprime_stats(uke);

  // Deuxième phase de tests
  personnage equipe[6];
  initialise_personnage(equipe, 0, "Tank", 60, 10, 25);
  initialise_personnage(equipe, 1, "Guerrier", 30, 30, 15);
  initialise_personnage(equipe, 2, "Paladin", 50, 20, 10);
  initialise_personnage(equipe, 3, "Berserk", 30, 40, 0);
  initialise_personnage(equipe, 4, "Healer inutile", 30, 5, 8);
  initialise_personnage(equipe, 5, "Magicien", 20, 30, 2);

  personnage boss[2];
  initialise_personnage(boss, 0, "Gros vilain pas beau", 100, 32, 18);
  initialise_personnage(boss, 1, "Sous-fifre inutile", 20, 10, 5);

  imprime_stats_equipe(equipe, 6);
  imprime_stats_equipe(boss, 2);

  confrontation(equipe, 6, boss, 2, true);

  imprime_stats_equipe(equipe, 6);
  imprime_stats_equipe(boss, 2);

  return 0;
}

// ############################## Partie 2 ##############################

struct day { int annee; int mois; int jour; int jdls; };
typedef struct day jour;

// Exercice 8

jour hui = { .annee=2022 , .mois=12 , .jour=4 , .jdls=7 };
jour naissance = { .annee=1988 , .mois=12 , .jour=19 };

// Exercice 9

char *mois[12] = { "janvier" , "février" , "mars" , "avril" , "mai" , "juin" , "juillet" , "août" , "septembre" , "octobre" , "novembre" , "décembre" };
char *jours_semaine[7] = { "lundi" , "mardi" , "mercredi" , "jeudi" , "vendredi" , "samedi" , "dimanche"};

void imprime_date(jour d, bool jdls) // jdls : non demandé, on imprime différemment
{
  printf("Le %d %s %d est un ", d.jour, mois[d.mois-1], d.annee);
  if (jdls)
  {
    printf("%s", jours_semaine[d.jdls-1]);
  }
  else printf("jour inconnu");
}

// Exercice 10

int nb_jours(int mois)
{
  if (mois == 2) return 28;
  if (mois == 4 || mois == 6 || mois == 9 || mois == 11) return 30;
  return 31;
}

// Exercice 11

bool bissextile(int x)
{
  return (x % 400 == 0) || (x % 4 == 0 && x % 100 != 0);
}

int difference_jours(jour j1, jour j2)
{
  int reponse = 0;
  if (j2.annee < j1.annee) return -difference_jours(j2, j1);
  if (j2.annee == j1.annee && j2.mois < j1.mois) return -difference_jours(j2, j1);
  if (j2.annee == j1.annee && j2.mois == j1.mois) return j2.jour - j1.jour;
  if (j2.annee > j1.annee)
  {
    for (int an = j1.annee+1 ; an < j2.annee ; an += 1) // les années complètes entre les deux si j2 est après, rien sinon
    {
      if (bissextile(an)) reponse += 366;
      else reponse += 365;
    }
    for (int mois = j1.mois+1 ; mois <= 12 ; mois += 1)
    {
      reponse += nb_jours(mois);
    }
    reponse += nb_jours(j1.mois)-j1.jour;
    if (bissextile(j1.annee) && j1.mois <= 2) reponse += 1; // Peut corriger la boucle aussi
    for (int mois = 1 ; mois < j2.mois ; mois += 1)
    {
      reponse += nb_jours(mois);
    }
    reponse += j2.jour;
    if (bissextile(j2.annee) && j2.mois > 2) reponse += 1; // Idem
  }
  else
  {
    reponse += nb_jours(j1.mois)-j1.jour;
    if (bissextile(j1.annee) && j1.mois <= 2 && j2.mois > 2) reponse += 1;
    for (int mois = j1.mois+1 ; mois < j2.mois ; mois += 1)
    {
      reponse += nb_jours(mois);
    }
    reponse += j2.jour;
  }
  return reponse;
}

// Exercice 12

void renseigne_jour(jour *d)
{
  int n = difference_jours(*d, hui) % 7;
  int autre_jour = hui.jdls - n;
  if (autre_jour <= 0) autre_jour += 7;
  d->jdls = autre_jour;
}

int main2()
{
  printf("%d\n", difference_jours(naissance, hui));
  renseigne_jour(&naissance);
  imprime_date(naissance, true);

  return 0;
}

// ############################## Fonction main ##############################

int main()
{
  int zero = main1();
  zero = main2();

  exit(0);
}
