Monster-survie

Fyre_ZX Messages postés 1 Date d'inscription lundi 29 octobre 2018 Statut Membre Dernière intervention 29 octobre 2018 - 29 oct. 2018 à 23:58
 Layl - 15 déc. 2018 à 15:09
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/102823-monster-survie

Très bien, pour un premier jeu c'est top:
Clair, bien commenté.
Quelques redondances dans le code, effectivement, les tests à rallonge qui peuvent probablement être concaténés à l'aide de fonctions ou bien d'une jump-table, mais ça a le mérite d'être clair et c'est aussi affaire de préférence.

Au niveau des conventions de nommage ( .h, .hh, .hpp ... ) , je ne m'inquieterais pas trop car en fait on s'en fout complètement ! Tant que tu ne mélanges pas explicitement une interface C par dessus une implémentation C++ tu n'as pas à te poser la question, et encore c'est juste histoire de s'y retrouver.

Îl n'est pas nécessaire de distribuer les objets intermédiaires (.o) ils ne servent que pour la compilation chez toi.

Tu te sers du language C++ comme d'un C glorifié en profitant de la STD, certains te diront que ce n'est pas bien mais ça n'a jamais blessé personne ;)
Celà dit, tant qu'à faire, autant se familiariser avec la POO ( Programmation Orientée Objet ), qui a ses avantages pour construire des systèmes complexes en leur donnant du sens, bien que ce ne soit pas du tout indispensable.
eliaswendland Messages postés 18 Date d'inscription mardi 10 juillet 2018 Statut Membre Dernière intervention 4 juin 2021
6 déc. 2018 à 19:35
Très cool seulement quand on passe au deuxième niveau et qu'on atteint la sortie, le programme dit :
Recommençer ?
pourquoi ?
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
5 nov. 2018 à 18:16
En passant, pourrais-tu nettoyer ta source ? (virer l'exécutable, les fichiers temporaires *.o, etc... qui prennent plus de place que ton code).

Merci.

(PS: pour du C++, préfère Code::Block par exemple, parce que Dev-C++ c'est très très vieux, avec un compilo qui a 10 à 15 ans de retard sur l'actuel, je ne suis même pas sûr que tu puisses compiler la version que je te propose).
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
Modifié le 5 nov. 2018 à 16:04
Pas mal de petits soucis avec ton code. Beaucoup de répétition, un tableau pas utile du tout (on peut faire sans), pas compatible partout (ne fonctionne que sous Windows). Un mélange C et C++ bizarre. Utilisation d'un "using namespace std" (beurk), voir: http://0217021.free.fr/portfolio/axel.berardino/articles/bon-usage-using-namespace, utilisation d'un .h pour du C++ (on utilise plutôt du .hh), utilisation d'un vieux "rand" pas très efficace, etc...
3 ou 4 fonctions qui font strictement et exactement la même chose (pour donner une valeur aléatoire). Une seule fonction aurait suffit.

Voici une version "propre":

main.cc:
#include <iostream>
#include <random>
#include "term.hh"

namespace
{
  const int MAP_WIDTH = 21;
  const int MAP_HEIGHT = 21;
  const int NB_MONSTERS = 4;
  const int NB_POWER = 3;

  struct Coord
  {
    int x;
    int y;
  };

  enum State{VICTORY, DEFEAT, GAME_CONTINUE };

  std::random_device _rd;
  std::mt19937 _mt(_rd());

  int rand(int max)
  {
    std::uniform_real_distribution<double> dist(0.0, max);
    return dist(_mt);
  }

  void printMap(Coord& player, Coord exit, Coord monsters[NB_MONSTERS], int nbPower, int score)
  {
    std::cout <<
      "* => ton personnage\n"
      "# => la sortie\n"
      "$ => les monstres\n"
      "Z => haut\n"
      "S => bas\n"
      "Q => gauche\n"
      "D => droite\n"
      "R => pouvoir\n"
      "Il te reste " << nbPower << " pouvoir(s)\n"
      "Ton score est de: " << score << " point(s)\n";

    for (int y = 0; y < MAP_HEIGHT; ++y)
    {
      for (int x = 0; x < MAP_WIDTH; ++x)
      {
        bool monster_printed = false;
        for (int k = 0; k < NB_MONSTERS; ++k)
        {
          if (monsters[k].x == x && monsters[k].y == y)
          {
            std::cout << '$';
            monster_printed = true;
          }
        }

        if (!monster_printed)
        {
          if (player.x == x && player.y == y)
            std::cout << '*';
          else if (exit.x == x && exit.y == y)
            std::cout << '#';
          else if (0 == x && 0 == y)
            std::cout << '0';
          else if (MAP_WIDTH - 1 == x && 0 == y)
            std::cout << '0';
          else if (0 == x && MAP_HEIGHT -1 == y)
            std::cout << '0';
          else if (MAP_WIDTH - 1 == x && MAP_HEIGHT -1 == y)
            std::cout << '0';
          else
            std::cout << '-';
        }
      }
      std::cout << std::endl;
    }
  }

  void placeMonsters(Coord monsters[NB_MONSTERS])
  {
    for (int i = 0; i < NB_MONSTERS; ++i)
    {
      monsters[i].x = rand(MAP_WIDTH);
      monsters[i].y = rand(MAP_HEIGHT);
    }
  }

  void initGame(Coord& player, Coord& exit, Coord monsters[NB_MONSTERS])
  {
    player.x = rand(MAP_WIDTH);
    player.y = rand(MAP_HEIGHT);
    exit.x = rand(MAP_WIDTH);
    exit.y = rand(MAP_HEIGHT);
    placeMonsters(monsters);
  }

  void moveMonsters(const Coord& player, Coord monsters[NB_MONSTERS])
  {
    for (int i = 0; i < NB_MONSTERS; ++i)
    {
      if (player.x < monsters[i].x)
        --monsters[i].x;
      else if (player.x > monsters[i].x)
        ++monsters[i].x;
      else if (player.y < monsters[i].y)
        --monsters[i].y;
      else if (player.y > monsters[i].y)
        ++monsters[i].y;
    }
  }

  State checkGameState(const Coord& player, const Coord& exit, Coord monsters[NB_MONSTERS], int& score)
  {
    if (player.x == exit.x && player.y == exit.y)
    {
      score += 50;
      return VICTORY;
    }

    for (int i = 0; i < NB_MONSTERS; ++i)
    {
      if (player.x == monsters[i].x && player.y == monsters[i].y)
      {
        score -= 40;
        return DEFEAT;
      }
    }

    return GAME_CONTINUE;
  }

  State play(char action, Coord& player, const Coord& exit, Coord monsters[NB_MONSTERS], int& nbPower, int& score)
  {
    switch (action)
    {
      case 'z':
        if (player.y > 0)
          --player.y;
        break;
      case 's':
        if (player.y < MAP_HEIGHT - 1)
          ++player.y;
        break;
      case 'q':
        if (player.x > 0)
          --player.x;
        break;
      case 'd':
        if (player.x < MAP_WIDTH - 1)
          ++player.x;
        break;
      case 'r':
        if (nbPower > 0)
        {
          --nbPower;
          score -= 10;
          placeMonsters(monsters);
        }
        break;
    }

    if (action == 'z' || action == 's' || action == 'q' || action == 'd')
      moveMonsters(player, monsters);

    return checkGameState(player, exit, monsters, score);
  }
} // namespace

int main()
{
  int score = 0;
  bool stop = false;

  while (!stop)
  {
    Coord player;
    Coord exit;
    Coord monsters[NB_MONSTERS];
    State state = GAME_CONTINUE;
    int nbPower = NB_POWER;

    initGame(player, exit, monsters);
    while (state == GAME_CONTINUE)
    {
      clear();
      printMap(player, exit, monsters, nbPower, score);
      const char action = getch();
      state = play(action, player, exit, monsters, nbPower, score);
    }

    switch (state)
    {
      case VICTORY:
        std::cout << "Vous avez atteint la sortie!" << std::endl;
        break;
      case DEFEAT:
        std::cout << "Vous avez été touché par un monstre!" << std::endl;
        break;
      default:
        ; // Should never happen
    }
    std::cout << "Votre score: " << score  << "\nRejouer ?[Y/N]" << std::endl;

    const char choice = getch();
    if (choice != 'y' && choice != 'Y')
      stop = true;
  };

  return 0;
}


term.hh:
#ifndef TERM_HH_
# define TERM_HH_

#ifdef _WIN32
# include <conio.h>
# include <windows.h>
#else
char getch(void);
char getche(void);
#endif

void clear();

#endif /* !TERM_HH_ */


term.cc:
#include <iostream>
#ifndef _WIN32
#include <termios.h>
#include <stdio.h>

static struct termios old, newt;

/* Initialize new terminal i/o settings */
void initTermios(int echo)
{
  tcgetattr(0, &old); /* grab old terminal i/o settings */
  newt = old; /* make new settings same as old settings */
  newt.c_lflag &= ~ICANON; /* disable buffered i/o */
  if (echo) {
    newt.c_lflag |= ECHO; /* set echo mode */
  } else {
    newt.c_lflag &= ~ECHO; /* set no echo mode */
  }
  tcsetattr(0, TCSANOW, &newt); /* use these new terminal i/o settings now */
}

/* Restore old terminal i/o settings */
void resetTermios(void)
{
  tcsetattr(0, TCSANOW, &old);
}

/* Read 1 character - echo defines echo mode */
char getch_(int echo)
{
  char ch;
  initTermios(echo);
  ch = getchar();
  resetTermios();
  return ch;
}

/* Read 1 character without echo */
char getch(void)
{
  return getch_(0);
}

/* Read 1 character with echo */
char getche(void)
{
  return getch_(1);
}

/* Clear screen */
void clear()
{
#ifdef _WIN32
  system("CLS");
#else
  system("clear");
#endif
}

#endif
Rejoignez-nous