Nachstehend ein kleines Labyrinth-Programm unter DOS, das die Linke-Hand-Regel implementiert. Es ist als Anregung gedacht und kann sehr leicht um weitere Regeln und Aktionen erweitert werden.
Aufgerufen wird es mit:
lab <labmap> <rob_x_pos> <rob_y_pos> <rob_skydir>,
z.B. mit lab lab.map 1 16 2
Die Parameter bedeuten:
FLOOR
's und WALL
's bestehen (Beispiel). Ein TGT
ist optional. Mit einem Semikolon startende Zeilenkommentare sind möglich (nur im downloadbaren Programm, nicht im nachstehenden Beispielcode).Für die Konsole sollte eine Rasterschrift eingestellt sein.
Anmerkung: Für den Programmeinsatz unter Nicht-DOS-Umgebungen sollte WALL
als (tsquare)35
statt (tsquare)219
definiert werden und die Labyrinthkarten entsprechend mit dem Zeichen 35 statt 219 befüllt sein. Warum? Der Wert 219 wird zwar unter den meisten DOS-Zeichensätzen (CP437, CP850 etc.) als Blockzeichen dargestellt, unter der Zeichensatzfamilie ISO-8859 und unter CP1252 und Unicode jedoch als 'Û' - so wie auf dieser Netzseite, die im Zeichensatz ISO-8859-1 (Latin1) verfaßt ist. Der Wert 35 ist hingegen im ASCII-Bereich als Gatterzeichen ('#') zu finden und somit ein universeller Ersatz für das DOS-spezifische Blockzeichen. Letzteres ist übrigens unter Unicode unter der Position 9608 (0x2588) wieder zu finden, nicht jedoch unter der Familie ISO-8859.
Der Robot wandert solange, bis er aus dem Labyrinth (OUT
) findet oder ein Ziel TGT
erreicht.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
/* Orientation */
typedef enum { N,NE,E,SE,S,SW,W,NW } tskydir;
typedef enum { F,RF,R,RB,B,LB,L,LF,HERE } tdir;
#define lturn(d) (d=(d+6)%8)
#define rturn(d) (d=(d+2)%8)
/* Material */
typedef unsigned char tsquare;
#define WALL (tsquare)219 /* Safer: (tsquare)'#' */
#define FLOOR ' '
#define TGT 'x'
#define OUT (tsquare)255
/* Labyrinth */
#define ARRAY(a,jlen,j,i) (*((a)+(j)*(jlen)+(i)))
#define LAB(j,i) ARRAY(lab,labxlen,(j),(i))
FILE *f;
tsquare *lab;
int labxlen, labylen; /* Width, height */
/* Robot */
int robx, roby; /* Coordinates */
tskydir robskydir; /* Walking direction */
/*** Exit handler ***/
void cleanup(int code)
{ _setcursortype(_NORMALCURSOR); if (lab) free(lab); exit(code); }
/*** Error handler ***/
void error(const char *s)
{ fprintf(stderr, "lab: %s!\a", s); cleanup(2); }
/*** Read a file line ***/
int getline(char *ln)
{
int l;
do
if (fgets(ln,1000,f) == 0)
return 0;
while (ln[0]==';' || ln[0]=='\n');
l = strlen(ln)-1; ln[l] = 0;
return l;
}
/*** Read labyrinth from file ***/
void getlab(char *fName)
{
int i,j,len;
char ln[1000];
if (!(f=fopen(fName, "rt")))
error("cannot open file");
/* File Pass 1: Get lab dimensions */
labxlen = labylen = 0;
while ((len=getline(ln)) != 0) {
if (len > labxlen)
labxlen = len;
labylen++;
}
/* Generate labyrinth memory */
labxlen+=2; labylen+=2;
if ((lab=(tsquare*)malloc(labxlen*labylen)) == 0)
error("not enough memory");
memset(lab, OUT, labxlen*labylen);
/* File Pass 2: copy labyrinth structure into labyrinth */
rewind(f);
for (j=1; len=getline(ln); j++)
for (i=0; i<len; i++)
LAB(j,i+1) = ln[i];
fclose(f);
}
/*** User Interface ***/
void getkey(void)
{ if (getch()==27) cleanup(0); }
/*** Display bot ***/
void robDisp(void)
{
gotoxy(robx+1,roby+1);
switch(robskydir) {
/* ^ */ case N: putch('\x1e'); break;
/* > */ case E: putch('\x10'); break;
/* v */ case S: putch('\x1f'); break;
/* < */ case W: putch('\x11'); break;
}
getkey();
}
/*** Hide bot ***/
void robHide(void)
{ gotoxy(robx+1,roby+1); putch(LAB(roby,robx)); }
/*** Display lab ***/
void labDisp(void)
{
int i,j;
clrscr();
for (j=0; j<labylen; j++)
for (i=0; i<labxlen; i++) {
gotoxy(i+1,j+1); putch(LAB(j,i)); }
}
/*** Turn bot ***/
void robTurn(tdir robTurn)
{
robHide();
if (robTurn == L) lturn(robskydir);
else rturn(robskydir);
robDisp();
}
/*** Move bot ***/
void robStep(void)
{
robHide();
switch (robskydir) {
case N: roby--; break;
case E: robx++; break;
case S: roby++; break;
case W: robx--; break;
}
robDisp();
}
/*** Return type of material of next square at loc ***/
tsquare square(tdir loc)
{
if (loc == HERE)
return LAB(roby,robx);
switch(robskydir) {
case N: break;
case E: rturn(loc); break;
case S: lturn(loc); lturn(loc); break;
case W: lturn(loc); break;
}
switch(loc) {
case F: return LAB(roby-1,robx);
case RF: return LAB(roby-1,robx+1);
case R: return LAB(roby,robx+1);
case RB: return LAB(roby+1,robx+1);
case B: return LAB(roby+1,robx);
case LB: return LAB(roby+1,robx-1);
case L: return LAB(roby,robx-1);
case LF: return LAB(roby-1,robx-1);
}
}
/*** Main play routine ***/
void enterlab(void)
{
_setcursortype(_NOCURSOR); labDisp(); robDisp();
while (square(HERE)!=TGT && square(HERE)!=OUT)
/* Left hand strategy */
if (square(F) != WALL) {
robStep();
if (square(LB)==WALL && square(L)!=WALL)
robTurn(L);
}
else
robTurn(R);
}
/*** Initialisation ***/
void init(int argc, char *argv[])
{
if (argc < 5)
error("missing params");
getlab(argv[1]);
robx = atoi(argv[2]);
roby = atoi(argv[3]);
robskydir = atoi(argv[4]);
}
int main(int argc, char *argv[])
{
init(argc,argv);
enterlab();
cleanup(0);
}