Monster-survie

Messages postés
1
Date d'inscription
lundi 29 octobre 2018
Dernière intervention
29 octobre 2018
- - Dernière réponse :  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.

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

Afficher la suite 
cptpingu
Messages postés
3830
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
19 novembre 2018
-
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
cptpingu
Messages postés
3830
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
19 novembre 2018
-
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).
eliaswendland
Messages postés
17
Date d'inscription
mardi 10 juillet 2018
Dernière intervention
6 décembre 2018
-
Très cool seulement quand on passe au deuxième niveau et qu'on atteint la sortie, le programme dit :
Recommençer ?
pourquoi ?
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.
Commenter la réponse de Fyre_ZX

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.