Construa um motor para um jogo de labirinto

9

Este é um acompanhamento da questão Imprimir um labirinto . Se você gostou desta pergunta, adicione mais algoritmos de geração de labirinto;).

Para esta tarefa, você terá que implementar um mecanismo de jogo para um jogador que deve encontrar o tesouro em um labirinto e sair da masmorra.

O mecanismo inicia lendo o labirinto a partir da entrada padrão seguida por uma linha contendo um .(ponto) um arquivo fornecido como argumento na linha de comando. Em seguida, o jogador @é colocado em um local aleatório no mapa. Em seguida, o mecanismo começa a interagir com o jogador através do io padrão:

Comandos do mecanismo para o jogador :

  • continue: Jogo não concluído. Os arredores são impressos seguidos de a .. O jogador é representado pelo @personagem. As células não observáveis ​​são representadas por ?.
  • finished: Jogo terminado. O número de etapas é impresso e o jogo para.

Comandos do jogador para o mecanismo :

  • north: Move o jogador para cima.
  • south: Move o jogador para baixo.
  • west: Move o jogador para a esquerda.
  • east: Mova o jogador para a direita.

Qualquer comando inválido (como bater em uma parede) do jogador é ignorado, mas ainda conta. Você é livre para definir o ambiente ao seu gosto.

  • Pontos para o código mais curto.
  • Pontos para ambientes complexos (por exemplo, imprima grandes regiões e substitua células que não são visíveis ?).
  • Nenhum ponto para o código que não respeita o formato io

Exemplo :

Neste exemplo, o ambiente é definido como a célula 3x3 com o player no meio.

$ cat maze
+-+-+
  |#|
|   |
+---+
$ python engine.py maze
 |#
 @ 
---
.
east
|#|
 @|
--+
.
north
+-+
|@|
  |
.
south
|#|
 @|
--+
.
west
 |#
 @ 
---
.
west
  |
|@ 
+--
.
north
+-+
 @|
|  
.
west
finished
7
Alexandru
fonte
@Alexandru: O que estamos usando para gerar nossos labirintos? Podemos usar algoritmos de labirinto de outras pessoas (obviamente com o devido crédito)? Ou devemos concluir sua primeira tarefa?
31511 snmcdonald
@snmcdonald: erro de digitação corrigido. Use labirintos de outras pessoas. Lembre-se de que o mecanismo lê o labirinto a partir da entrada padrão.
Alexandru
Este blog possui excelentes artigos sobre geração de labirinto usando algoritmos diversos e mistos weblog.jamisbuck.org Confira o algoritmo de árvore em crescimento, em particular weblog.jamisbuck.org/2011/1/27/…
Dve
Estou confuso sobre como o labirinto e a interação do usuário vêm da entrada padrão. O usuário deveria digitar seu labirinto e resolvê-lo? Derrota meio o propósito de apenas mostrando uma parte do labirinto ...
Keith Randall
Você pode criar um aplicativo (essa tarefa é deixada para outra pergunta) sobre ele para separar a entrada do labirinto da entrada dos comandos.
Alexandru

Respostas:

7

C99, 771 caracteres

#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();}

Requer e utiliza ncurses. Apenas uma macroização para o comprimento, e as macros N e M devem substituir os operadores mínimo e máximo ausentes, e não acho que haja muito mais a fazer sobre isso.

Ele pressupõe que o labirinto de entrada não exceda 80 caracteres de largura e que o nome do arquivo a labirinto tenha sido passado na linha de comando e que o número de parâmetros seja baixo o suficiente para que o valor inicial de c não seja um comando de movimento.

  • Desvia do padrão, na medida em que recebe comandos de direção de caractere único como a primeira letra minúscula dos sugeridos.

  • Mostra regiões desconhecidas como '?'.

Mais legível com comentários:

#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 --- gatinho ex-moderador
fonte