Browse Source

New fpcgame, MAZE

marco 25 years ago
parent
commit
2bd8c56263
1 changed files with 481 additions and 0 deletions
  1. 481 0
      install/demo/maze.pas

+ 481 - 0
install/demo/maze.pas

@@ -0,0 +1,481 @@
+{A demo with some interesting algoritms, and for Graph.
+
+The sources for this game was found on a site that claims to only have
+PD stuff with the below header(which was only reindented), and the webmaster
+said that everything he published was sent to him with that purpose. We tried
+to contact the authors mentioned below via mail over internet, but that
+failed. If there is somebody that claims authorship of these programs,
+please mail [email protected], and the sources will be removed from our
+websites.
+
+------------------------------------------------------------------------
+
+ORIGINAL Header:
+
+created by Randy Ding July 16,1983   <April 21,1992>
+
+Very small FPC fixes by Marco van de Voort (EgaHi to vgahi), and tried
+setting the maze dimensions maxx and maxy to a bigger size.
+Won't work, you'll have to update all vars to al least word to increase the
+complexity of the grid further. I didn't do it, since 200x200 is already
+unreadable to me.
+
+Don't forget the BGIPATH of InitGraph.
+}
+
+{$R-}   { range checking }
+
+program makemaze;
+
+uses
+  crt, graph;
+
+const
+  screenwidth   = 640;
+  screenheight  = 480;
+  minblockwidth = 2;
+  maxx = 200;   { BP: [3 * maxx * maxy] must be less than 65520 (memory segment) }
+                { FPC: Normally no problem. ( even if you'd use 1600x1200x3< 6MB)}
+  maxy = 200;   { here maxx/maxy about equil to screenwidth/screenheight }
+  flistsize = maxx*maxy DIV 2; { flist size (fnum max, about 1/3 of maxx * maxy) }
+
+  background = black;
+  gridcolor  = green;
+  solvecolor = white;
+
+  rightdir = $01;
+  updir    = $02;
+  leftdir  = $04;
+  downdir  = $08;
+
+  unused   = $00;    { cell types used as flag bits }
+  frontier = $10;
+  reserved = $20;
+  tree     = $30;
+
+
+type
+  frec = record
+          column, row : byte;
+         end;
+  farr = array [1..flistsize] of frec;
+
+  cellrec = record
+              point : word;  { pointer to flist record }
+              flags : byte;
+            end;
+  cellarr = array [1..maxx,1..maxy] of cellrec;
+
+  {
+    one byte per cell, flag bits...
+
+    0: right, 1 = barrier removed
+    1: top    "
+    2: left   "
+    3: bottom "
+    5,4: 0,0 = unused cell type
+         0,1 = frontier "
+         1,1 = tree     "
+         1,0 = reserved "
+    6: (not used)
+    7: solve path, 1 = this cell part of solve path
+  }
+
+
+var
+  flist     : farr;         { list of frontier cells in random order }
+  cell      : ^cellarr;      { pointers and flags, on heap }
+  fnum,
+  width,
+  height,
+  blockwidth,
+  halfblock,
+  maxrun    : word;
+  runset    : byte;
+  ch        : char;
+
+procedure initbgi;
+var
+  grdriver,
+  grmode,
+  errcode : integer;
+begin
+  grdriver := vga;
+  grmode   := vgahi;
+  initgraph(grdriver, grmode, 'd:\pp\bp\bgi');
+  errcode:= graphresult;
+  if errcode <> grok then
+  begin
+    CloseGraph;
+    writeln('Graphics error: ', grapherrormsg(errcode));
+    halt(1);
+  end;
+end;
+
+
+function adjust(var x, y : word; d : byte) : boolean;
+begin                              { take x,y to next cell in direction d }
+  case d of                        { returns false if new x,y is off grid }
+    rightdir:
+    begin
+      inc (x);
+      adjust:= x <= width;
+    end;
+
+    updir:
+    begin
+      dec (y);
+      adjust:= y > 0;
+    end;
+
+    leftdir:
+    begin
+      dec (x);
+      adjust:= x > 0;
+    end;
+
+    downdir:
+    begin
+      inc (y);
+      adjust:= y <= height;
+    end;
+  end;
+end;
+
+
+procedure remove(x, y : word);      { remove a frontier cell from flist }
+var
+  i : word; { done by moving last entry in flist into it's place }
+begin
+  i := cell^[x,y].point;          { old pointer }
+  with flist[fnum] do
+    cell^[column,row].point := i;   { move pointer }
+  flist[i] := flist[fnum];        { move data }
+  dec(fnum);                    { one less to worry about }
+end;
+
+
+procedure add(x, y : word; d : byte);  { add a frontier cell to flist }
+var
+  i : byte;
+begin
+  i := cell^[x,y].flags;
+  case i and $30 of   { check cell type }
+    unused :
+    begin
+      cell^[x,y].flags := i or frontier;  { change to frontier cell }
+      inc(fnum);                        { have one more to worry about }
+      if fnum > flistsize then
+      begin     { flist overflow error! }
+        dispose(cell);  { clean up memory }
+        closegraph;
+        writeln('flist overflow! - To correct, increase "flistsize"');
+        write('hit return to halt program ');
+        readln;
+        halt(1);        { exit program }
+      end;
+      with flist[fnum] do
+      begin    { copy data into last entry of flist }
+        column := x;
+        row    := y;
+      end;
+      cell^[x,y].point := fnum; { make the pointer point to the new cell }
+      runset := runset or d;   { indicate that a cell in direction d was }
+    end;                      {    added to the flist }
+
+    frontier : runset := runset or d;     { allready in flist }
+  end;
+end;
+
+
+procedure addfront(x, y : word);    { change all unused cells around this }
+var                              {    base cell to frontier cells }
+  j, k : word;
+  d    : byte;
+begin
+  remove(x, y);       { first remove base cell from flist, it is now }
+  runset := 0;         {    part of the tree }
+  cell^[x,y].flags := cell^[x,y].flags or tree;   { change to tree cell }
+  d := $01;            { look in all four directions- $01,$02,$04,$08 }
+  while d <= $08 do
+  begin
+    j := x;
+    k := y;
+    if adjust(j, k, d) then
+      add(j, k, d);  { add only if still in bounds }
+    d := d shl 1;    { try next direction }
+  end;
+end;
+
+
+procedure remline(x, y : word; d : byte);  { erase line connecting two blocks }
+begin
+  setcolor(background);
+  x := (x - 1) * blockwidth;
+  y := (y - 1) * blockwidth;
+  case d of
+    rightdir : line (x + blockwidth, y + 1, x + blockwidth, y + blockwidth - 1);
+    updir    : line (x + 1, y, x + blockwidth - 1, y);
+    leftdir  : line (x, y + 1, x, y + blockwidth - 1);
+    downdir  : line (x + 1, y + blockwidth, x + blockwidth - 1, y + blockwidth);
+  end;
+end;
+
+
+{ erase line and update flags to indicate the barrier has been removed }
+procedure rembar(x, y : word; d : byte);
+var
+  d2 : byte;
+begin
+  remline(x, y, d);       { erase line }
+  cell^[x,y].flags := cell^[x,y].flags or d; { show barrier removed dir. d }
+  d2 := d shl 2;  { shift left twice to reverse direction }
+  if d2 > $08 then
+    d2 := d2 shr 4;  { wrap around }
+  if adjust(x, y, d) then  { do again from adjacent cell back to base cell }
+    cell^[x,y].flags := cell^[x,y].flags or d2;    { skip if out of bounds }
+end;
+
+
+function randomdir : byte;  { get a random direction }
+begin
+  case random(4) of
+    0 : randomdir := rightdir;
+    1 : randomdir := updir;
+    2 : randomdir := leftdir;
+    3 : randomdir := downdir;
+  end;
+end;
+
+
+procedure connect(x, y : word);    { connect this new branch to the tree }
+var                             {    in a random direction }
+  j, k  : word;
+  d     : byte;
+  found : boolean;
+begin
+  found := false;
+  while not found do
+  begin { loop until we find a tree cell to connect to }
+    j := x;
+    k := y;
+    d := randomdir;
+    if adjust(j, k, d) then
+      found := cell^[j,k].flags and $30 = tree;
+  end;
+  rembar(x, y, d);   { remove barrier connecting the cells }
+end;
+
+
+procedure branch(x, y : word);  { make a new branch of the tree }
+var
+  runnum : word;
+  d      : byte;
+  i      : boolean;
+begin
+  runnum := maxrun;      { max number of tree cells to add to a branch }
+  connect(x, y);        { first connect frontier cell to the tree }
+  addfront(x, y);       { convert neighboring unused cells to frontier }
+  dec(runnum);         { number of tree cells left to add to this branch }
+  while (runnum > 0) and (fnum > 0) and (runset > 0) do
+  begin
+    repeat
+      d := randomdir;
+    until d and runset > 0;  { pick random direction to known frontier }
+    rembar(x, y, d);          {    and make it part of the tree }
+    i := adjust(x, y, d);
+    addfront(x, y);      { then pick up the neighboring frontier cells }
+    dec(runnum);
+  end;
+end;
+
+
+procedure drawmaze;
+var
+  x, y, i : word;
+begin
+  setcolor(gridcolor);    { draw the grid }
+  y := height * blockwidth;
+  for i := 0 to width do
+  begin
+    x := i * blockwidth;
+    line(x, 0, x, y);
+  end;
+  x := width * blockwidth;
+  for i := 0 to height do
+  begin
+    y := i * blockwidth;
+    line (0, y, x, y);
+  end;
+  fillchar(cell^, sizeof(cell^), chr(0));    { zero flags }
+  fnum   := 0;   { number of frontier cells in flist }
+  runset := 0; { directions to known frontier cells from a base cell }
+  randomize;
+  x := random(width) + 1;   { pick random start cell }
+  y := random(height) + 1;
+  add(x, y, rightdir);       { direction ignored }
+  addfront(x, y);      { start with 1 tree cell and some frontier cells }
+  while (fnum > 0) do
+  with flist[random(fnum) + 1] do
+    branch(column, row);
+end;
+
+procedure dot(x, y, colr : word);
+begin
+  putpixel(blockwidth * x - halfblock, blockwidth * y - halfblock, colr);
+end;
+
+procedure solve(x, y, endx, endy : word);
+var
+  j, k : word;
+  d    : byte;
+  i    : boolean;
+begin
+  d := rightdir;  { starting from left side of maze going right }
+  while (x <> endx) or (y <> endy) do
+  begin
+    if d = $01 then
+      d := $08
+    else
+      d := d shr 1; { look right, hug right wall }
+    while cell^[x,y].flags and d = 0 do
+    begin { look for an opening }
+      d := d shl 1;                            { if no opening, turn left }
+      if d > $08 then
+        d := d shr 4;
+    end;
+    j := x;
+    k := y;
+    i := adjust(x, y, d);         { go in that direction }
+    with cell^[j,k] do
+    begin    { turn on dot, off if we were here before }
+      flags := ((((cell^[x,y].flags xor $80) xor flags) and $80) xor flags);
+      if flags and $80 <> 0 then
+        dot(j, k, solvecolor)
+      else
+        dot(j, k, background);
+    end;
+  end;
+  dot(endx, endy, solvecolor);    { dot last cell on }
+end;
+
+procedure mansolve (x,y,endx,endy: word);
+var
+  j, k : word;
+  d    : byte;
+  ch   : char;
+begin
+  ch := ' ';
+  while ((x <> endx) or (y <> endy)) and (ch <> 'X') and (ch <> #27) do
+  begin
+    dot(x, y, solvecolor);    { dot man on, show where we are in maze }
+    ch := upcase(readkey);
+    dot(x, y, background);    { dot man off after keypress }
+    d := 0;
+    case ch of
+      #0:
+      begin
+        ch := readkey;
+        case ch of
+          #72 : d := updir;
+          #75 : d := leftdir;
+          #77 : d := rightdir;
+          #80 : d := downdir;
+        end;
+      end;
+
+      'I' : d := updir;
+      'J' : d := leftdir;
+      'K' : d := rightdir;
+      'M' : d := downdir;
+    end;
+
+    if d > 0 then
+    begin
+      j := x;
+      k := y;    { move if no wall and still in bounds }
+      if (cell^[x,y].flags and d > 0) and adjust(j, k, d) then
+      begin
+        x := j;
+        y := k;
+      end;
+    end;
+  end;
+end;
+
+procedure solvemaze;
+var
+  x, y,
+  endx,
+  endy : word;
+  ch   : char;
+begin
+  x := 1;                         { pick random start on left side wall }
+  y := random(height) + 1;
+  endx := width;                  { pick random end on right side wall }
+  endy := random(height) + 1;
+  remline(x, y, leftdir);         { show start and end by erasing line }
+  remline(endx, endy, rightdir);
+  mansolve(x, y, endx, endy);      { try it manually }
+  solve(x, y, endx, endy);         { show how when he gives up }
+  while keypressed do
+    ch := readkey;
+  ch := readkey;
+end;
+
+
+procedure getsize;
+var
+  j, k : real;
+begin
+  clrscr;
+  writeln('       Mind');
+  writeln('       Over');
+  writeln('       Maze');
+  writeln;
+  writeln('   by Randy Ding');
+  writeln;
+  writeln('Use I,J,K,M or arrow keys to walk thru maze,');
+  writeln('then hit X when you give up!');
+  repeat
+    writeln;
+    write('Maze size: ', minblockwidth, ' (hard) .. 95 (easy) ');
+    readln(blockwidth);
+  until (blockwidth >= minblockwidth) and (blockwidth < 96);
+  writeln;
+  write('Maximum branch length: 1 easy .. 50 harder, (0 unlimited) ');
+  readln(maxrun);
+  if maxrun <= 0 then
+    maxrun := 65535;  { infinite }
+  j := screenwidth / blockwidth;
+  k := screenheight / blockwidth;
+  if j = int(j) then
+    j := j - 1;
+  if k = int(k) then
+    k := k - 1;
+  width  := trunc(j);
+  height := trunc(k);
+  if (width > maxx) or (height > maxy) then
+  begin
+    width  := maxx;
+    height := maxy;
+  end;
+  halfblock := blockwidth div 2;
+end;
+
+begin
+  repeat
+    getsize;
+    initbgi;
+    new(cell);    { allocate this large array on heap }
+    drawmaze;
+    solvemaze;
+    dispose(cell);
+    closegraph;
+    while keypressed do
+      ch := readkey;
+    write ('another one? ');
+    ch := upcase (readkey);
+  until (ch = 'N') or (ch = #27);
+end.
+