Zbuduj silnik do gry w labirynt

9

Jest to kontynuacja pytania dotyczącego wydruku labiryntu . Jeśli podoba ci się to pytanie, dodaj więcej algorytmów generowania labiryntu;).

Aby wykonać to zadanie, musisz wdrożyć silnik gry dla jednego gracza, który musi znaleźć skarb w labiryncie i wydostać się z lochu.

Silnik rozpoczyna się od odczytania labiryntu ze standardowego wejścia, a następnie wiersza zawierającego .(kropkę) plik podany jako argument w wierszu poleceń. Następnie gracz @umieszcza się w losowej lokalizacji na mapie. Następnie silnik zaczyna współdziałać z odtwarzaczem poprzez standardowe io:

Polecenia od silnika do gracza :

  • continue: Gra nie jest skończona. Otoczenie jest drukowane, a następnie .. Gracz jest reprezentowany przez @postać. Nieobserwowalne komórki są reprezentowane przez ?.
  • finished: Gra zakończona. Liczba kroków jest drukowana i gra się zatrzymuje.

Polecenia od gracza do silnika :

  • north: Przesuwa gracza w górę.
  • south: Przenosi gracza w dół.
  • west: Przenieś gracza w lewo.
  • east: Przesuń odtwarzacz w prawo.

Wszelkie nieprawidłowe polecenia gracza (takie jak trafienie w ścianę) są ignorowane, ale nadal liczone. Możesz dowolnie definiować otoczenie.

  • Punkty za najkrótszy kod.
  • Punkty dla złożonego otoczenia (np. Drukuj duże obszary i zastępuj komórki, które nie są widoczne ?).
  • Brak punktów za kod, który nie przestrzega formatu io

Przykład :

W tym przykładzie otoczenie jest zdefiniowane jako komórka 3x3 z odtwarzaczem pośrodku.

$ cat maze
+-+-+
  |#|
|   |
+---+
$ python engine.py maze
 |#
 @ 
---
.
east
|#|
 @|
--+
.
north
+-+
|@|
  |
.
south
|#|
 @|
--+
.
west
 |#
 @ 
---
.
west
  |
|@ 
+--
.
north
+-+
 @|
|  
.
west
finished
7
Alexandru
źródło
@Alexandru: Czego używamy do generowania naszych labiryntów? Czy możemy używać algorytmów labiryntu innych ludzi (oczywiście z należytym uznaniem)? A może musimy wykonać pierwsze zadanie?
snmcdonald
@ snmcdonald: Naprawiono literówkę. Używaj labiryntów innych ludzi. Pamiętaj, że silnik odczytuje labirynt ze standardowego wejścia.
Alexandru
Ten blog zawiera doskonałe artykuły na temat generowania labiryntów przy użyciu różnych i mieszanych algorytmów weblog.jamisbuck.org Sprawdź algorytm rozwijającego się drzewa, w szczególności weblog.jamisbuck.org/2011/1/27/…
Dve
Jestem zdezorientowany, w jaki sposób zarówno labirynt, jak i interakcja użytkownika pochodzą ze standardowych danych wejściowych. Czy użytkownik powinien wpisać swój labirynt, a następnie go rozwiązać? W pewnym sensie pokonuje cel pokazania tylko części labiryntu ...
Keith Randall
Możesz zbudować aplikację (zadanie to pozostawia inne pytanie), aby oddzielić wejście labiryntu od wprowadzania poleceń.
Alexandru

Odpowiedzi:

7

C99, 771 znaków

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

Wymaga i korzysta z ncurses. Tylko jedna makroryzacja dla długości, a makra N i M mają zastąpić brakujące minimalne i maksymalne operatory, i nie sądzę, że jest o wiele więcej do zrobienia.

Zakłada labiryntu wejściowego nie przekracza 80 znaków szerokości, i że labirynt nazwa pliku jest przekazywana na polecenia linii, oraz że liczba parametrów jest na tyle niska, że początkowa wartość c jest rozkaz ruchu.

  • Różni się od standardu tym, że przyjmuje polecenia kierunku jednoznakowego jako pierwszą małą literę sugerowanych poleceń.

  • Czy pokazuje nieznane regiony jako „?”.

Bardziej czytelne z komentarzami:

#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 --- były kot moderator
źródło