Construisez un moteur pour un jeu de labyrinthe

9

Il s'agit d'un suivi de la question Imprimer un labyrinthe . Si vous aimez cette question, veuillez ajouter d'autres algorithmes de génération de labyrinthe;).

Pour cette tâche, vous devrez implémenter un moteur de jeu pour un joueur qui doit trouver le trésor dans un labyrinthe et sortir du donjon.

Le moteur commence par lire le labyrinthe à partir de l'entrée standard, suivi d'une ligne contenant un .(point) un fichier donné comme argument dans la ligne de commande. Ensuite, le joueur @est placé dans un endroit aléatoire sur la carte. Ensuite, le moteur commence à interagir avec le joueur via io standard:

Commandes du moteur au joueur :

  • continue: Jeu non terminé. L'environnement est imprimé suivi d'un .. Le joueur est représenté par un @personnage. Les cellules non observables sont représentées par ?.
  • finished: Jeu terminé. Le nombre d'étapes est imprimé et le jeu s'arrête.

Commandes du joueur au moteur :

  • north: Déplace le joueur vers le haut.
  • south: Déplace le joueur vers le bas.
  • west: Déplacer le joueur vers la gauche.
  • east: Déplacer le joueur vers la droite.

Toute commande invalide (comme frapper un mur) du joueur est ignorée, mais toujours comptée. Vous êtes libre de définir l'environnement à votre guise.

  • Points pour le code le plus court.
  • Points pour un environnement complexe (par exemple imprimer de grandes régions et remplacer les cellules qui ne sont pas visibles par ?).
  • Aucun point pour le code qui ne respecte pas le format io

exemple :

Dans cet exemple, l'environnement est défini comme la cellule 3x3 avec le joueur au milieu.

$ cat maze
+-+-+
  |#|
|   |
+---+
$ python engine.py maze
 |#
 @ 
---
.
east
|#|
 @|
--+
.
north
+-+
|@|
  |
.
south
|#|
 @|
--+
.
west
 |#
 @ 
---
.
west
  |
|@ 
+--
.
north
+-+
 @|
|  
.
west
finished
7
Alexandru
la source
@Alexandru: Qu'utilisons-nous pour générer nos labyrinthes? Pouvons-nous utiliser les algorithmes de labyrinthe d'autres peuples (évidemment avec le mérite)? Ou devons-nous terminer votre première mission?
snmcdonald
@snmcdonald: Correction d'une faute de frappe. Utilisez les dédales des autres. N'oubliez pas que le moteur lit le labyrinthe à partir de l'entrée standard.
Alexandru
Ce blog contient d'excellents articles sur la génération de labyrinthes à l'aide d'algorithmes divers et mixtes weblog.jamisbuck.org Découvrez l'algorithme d'arbre en croissance en particulier weblog.jamisbuck.org/2011/1/27/…
Dve
Je suis confus quant à la façon dont le labyrinthe et l'interaction avec l'utilisateur proviennent d'une entrée standard. L'utilisateur est-il censé taper son labyrinthe puis le résoudre? Kinda défait le but de ne montrer qu'une partie du labyrinthe ...
Keith Randall
Vous pouvez créer une application (cette tâche est laissée pour une autre question) par-dessus pour séparer l'entrée du labyrinthe de l'entrée des commandes.
Alexandru

Réponses:

7

C99, 771 caractères

#include <ncurses.h>
#include <string.h>
#define MIN(A,B) (A<B?A:B)
#define MAX(A,B) (A>B?A:B)
#define T(C,X,Y) case C:if((m[x+X][y+Y]==' ')||(m[x+X][y+Y]=='#'))x+=X,y+=Y;s++;break;
char m[24][81],M[24][81];int i,j,I=0,J,x,y,s=0;
int main(int c,char**v){FILE*f=fopen(v[1],"r");
for(I=0;fgets(m[I],80,f);I++)J=MAX(J,strlen(m[I]));
J--;f=fopen("/dev/random","r");do{x=fgetc(f)%I;y=fgetc(f)%J;}
while(m[x][y]!=' ');initscr();curs_set(0);do{
switch(c){T('e',0,1)T('n',-1,0)T('s',1,0)T('w',0,-1)}
for(i=MAX(0,x-1);i<MIN(x+2,I);i++)for(j=MAX(0,y-1);j<MIN(y+2,J);j++)M[i][j]=1;
for(i=0;i<I;i++)for(j=0;j<J;j++)mvaddch(i,j,M[i][j]?m[i][j]:'?');
mvaddch(x,y,'@');refresh();}while((m[x][y]!='#')&&(c=getch())!='q');
if(m[x][y]=='#')mvprintw(I,0,"Finished in %d steps!",s),getch();endwin();}

Nécessite et utilise ncurses. Une seule macroisation pour la longueur, et les macros N et M doivent remplacer les opérateurs minimum et maximum manquants, et je ne pense pas qu'il y ait beaucoup plus à faire à ce sujet.

Il suppose que le labyrinthe d'entrée ne dépasse pas 80 caractères de large, et que le nom de fichier du labyrinthe a été passé sur la ligne de commande, et que le nombre de paramètres est suffisamment faible pour que la valeur initiale de c ne soit pas une commande de mouvement.

  • S'écarte de la norme en ce qu'il prend les commandes de direction de caractère unique comme première lettre minuscule de celles suggérées.

  • Affiche les régions inconnues sous la forme «?».

Plus lisible avec des commentaires:

#include <ncurses.h>
#include <string.h>

#define MIN(A,B) (A<B?A:B)/*unsafe,but short*/
#define MAX(A,B) (A>B?A:B)/*unsafe,but short*/
// #define MAX(A,B) ((_A=A)>(_B=B)?_A:_B) /* safe but verbose */
#define T(C,X,Y) case C:if((m[x+X][y+Y]==' ')||(m[x+X][y+Y]=='#'))x+=X,y+=Y;s++;break;
char m[24][81],M[24][81];/* [m]ap and [M]ask; NB:mask intialized by default */
int i,j, /* loop indicies over the map */
  I=0,J, /* limits of the map */
  x,y,   /* player position */
  s=0;   /* steps taken */
int main(int c,char**v){
  FILE*f=fopen(v[1],"r"); /* fragile, assumes that the argument is present */
  /* Read the input file */
  for(I=0;fgets(m[I],80,f);I++)J=MAX(J,strlen(m[I])); /* Read in the map */ 
  J--;
  /* note that I leak a file handle here */
  f=fopen("/dev/random","r");
  /* Find a open starting square */
  do{ 
    x=fgetc(f)%I; /* Poor numeric properties, but good enough for code golf */
    y=fgetc(f)%J;
  } while(m[x][y]!=' ');
  /* setup curses */
  initscr(); /* start curses */
  //  raw();     /* WARNING! intercepts C-c, C-s, C-z, etc...
  //          * but shorter than cbreak() 
  //          */
  curs_set(0); /* make the cursor invisible */
  /* main loop */
  do {
    switch(c){
      T('e',0,1)
      T('n',-1,0)
      T('s',1,0)
      T('w',0,-1)
    }
    /* Update the mask */
    for(i=MAX(0,x-1);i<MIN(x+2,I);i++)
      for(j=MAX(0,y-1);j<MIN(y+2,J);j++)
    M[i][j]=1;
    /* draw the maze as masked */
    for(i=0;i<I;i++)
      for(j=0;j<J;j++)
    mvaddch(i,j,M[i][j]?m[i][j]:'?');
    /* draw the player figure */
    mvaddch(x,y,'@');
    refresh(); /* Refresh the display */
  } while((m[x][y]!='#')&&(c=getch())!='q');
  if(m[x][y]=='#')mvprintw(I,0,"Finished in %d steps!",s),getch();
  endwin();
}
dmckee --- chaton ex-modérateur
la source