Start > Algorithmik > Labyrinthe und Irrgärten > Linke-Hand-Bot

Ein Linke-Hand-Bot

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.

LabBot-Fenster

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:

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 Labyrinth­karten ent­spre­chend 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 Block­zeichen dargestellt, unter der Zeichen­satz­familie ISO-8859 und unter CP1252 und Unicode jedoch als 'Û' - so wie auf dieser Netzseite, die im Zeichen­satz ISO-8859-1 (Latin1) verfaßt ist. Der Wert 35 ist hingegen im ASCII-Bereich als Gatter­zeichen ('#') zu finden und somit ein universeller Ersatz für das DOS-spezifische Block­zeichen. Letzteres ist übrigens unter Unicode unter der Position 9608 (0x2588) wieder zu finden, nicht jedoch unter der Familie ISO-8859.

Labyrinth

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);
  }
© 2002, 2010 asdala.de: Kon­takt & Daten­obhut