Построить движок для игры-лабиринта

9

Это продолжение вопроса « Распечатать лабиринт» . Если вам нравится этот вопрос, пожалуйста, добавьте больше алгоритмов генерации лабиринтов;).

Для этого задания вам нужно будет внедрить игровой движок для одного игрока, который должен найти клад в лабиринте и выбраться из темницы.

Движок запускается с чтения лабиринта из стандартного ввода, за которым следует строка, содержащая .(точка) файл, заданный в качестве аргумента в командной строке. Далее игрок @размещается в случайном месте на карте. Затем движок начинает взаимодействовать с игроком через стандартный io:

Команды от двигателя к игроку :

  • continue: Игра не закончена. Окружение напечатано, а затем .. Игрок представлен @персонажем. Ненаблюдаемые клетки представлены ?.
  • finished: Игра окончена. Количество шагов печатается и игра останавливается.

Команды от игрока к двигателю :

  • north: Перемещает игрока вверх.
  • south: Перемещает игрока вниз.
  • west: Переместить игрока влево.
  • east: Переместить игрока вправо.

Любая неверная команда (например, удар по стене) от игрока игнорируется, но все равно считается. Вы можете сами определять обстановку по своему вкусу.

  • Очки за самый короткий код.
  • Точки для сложной среды (например, печать больших областей и замена ячеек, которые не видны ?).
  • Нет баллов за код, который не соответствует формату io

Пример :

В этом примере окружение определяется как ячейка 3х3 с игроком посередине.

$ cat maze
+-+-+
  |#|
|   |
+---+
$ python engine.py maze
 |#
 @ 
---
.
east
|#|
 @|
--+
.
north
+-+
|@|
  |
.
south
|#|
 @|
--+
.
west
 |#
 @ 
---
.
west
  |
|@ 
+--
.
north
+-+
 @|
|  
.
west
finished
7
Александр
источник
@Alexandru: Что мы используем для создания наших лабиринтов? Можем ли мы использовать алгоритмы лабиринтов других людей (очевидно, с должным уважением)? Или мы должны выполнить ваше первое задание?
snmcdonald
@snmcdonald: исправлена ​​опечатка. Используйте лабиринты других людей. Помните, что двигатель читает лабиринт из стандартного ввода.
Александру
В этом блоге есть отличные статьи о создании лабиринтов с использованием различных и смешанных алгоритмов. Weblog.jamisbuck.org Ознакомьтесь с алгоритмом растущего дерева, в частности weblog.jamisbuck.org/2011/1/27/…
Dve
Я запутался в том, как лабиринт и взаимодействие с пользователем происходят из стандартного ввода. Должен ли пользователь набирать лабиринт, а затем решать его? Кинда побеждает цель показать только часть лабиринта ...
Кит Рэндалл
Вы можете построить приложение (эта задача оставлена ​​для другого вопроса) поверх него, чтобы отделить ввод лабиринта от ввода команд.
Александру

Ответы:

7

C99, 771 символ

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

Требует и использует ncurses. Только одна макрокоманда для длины, и макросы N и M должны заменить отсутствующие минимальные и максимальные операторы, и я не думаю, что здесь можно сделать гораздо больше.

Это предполагает , что входной лабиринт не превышает 80 символов в ширину, и что лабиринты имя файла уже было передано в командной строке, и что число параметров достаточно низко , что начальное значение с не команда движения.

  • Отходит от стандарта тем, что он принимает команды направления из одного символа в качестве строчной первой буквы из предложенных.

  • Показывает неизвестные регионы как '?' S.

Более читабельно с комментариями:

#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 --- котенок экс-модератора
источник