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és18Date d'inscriptionmardi 10 juillet 2018StatutMembreDerniè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és3837Date d'inscriptiondimanche 12 décembre 2004StatutModérateurDernière intervention28 mars 2023123 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és3837Date d'inscriptiondimanche 12 décembre 2004StatutModérateurDernière intervention28 mars 2023123 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;
}
15 déc. 2018 à 15:09
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.
6 déc. 2018 à 19:35
Recommençer ?
pourquoi ?
5 nov. 2018 à 18:16
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).
Modifié le 5 nov. 2018 à 16:04
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:
term.hh:
term.cc: