View Single Post
Old 14-06-2006, 04:02 PM   #17
guesst
Abandonia Homie
 
guesst's Avatar

 
Join Date: May 2005
Location: Aurora, United States
Posts: 606
Default

Hey, 13 out of 40 in a competition where no morons are allowed isn't bad. You were doing well just to get in.

3DMaze
This is a real cool one. Taken from yet another entry in the International Obvscated C-Code Contest (another exelent place to find C-Code examples written by people better than me). Sean Barrett's winning 1991 entry drew an ascii representation of a first person view through a maze. For the maze the program read it's own code in and used the whitespaces for floor. Clever, but not very dynamic.

So I decided to make a random maze generator and attach it to the drawing algorithm. This meant I had to take code that was not formatted for reading and reformat it with variables with understandable names and everything. It was an interesting way to figure out how this extremely clever routine worked.

The final result is uber-cool and looks like this:
Code:
****\****************************************** /
**** |**************************************** |
**** |**************************************** |
**** |**************************************** |
**** |**************************************** |
**** |--------\********************** /--------|
**** |****** |**\****************** /**|****** |
**** |****** |****\************** /****|****** |
**** |****** |**** |************/|**** |****** |
**** |****** |**** |**********/**|**** |****** |
**** |****** |**** |---------|** |**** |****** |
**** |****** |**** |** |**** |** |**** |****** |
**** |****** |**** |---------|** |**** |****** |
**** |****** |**** |**********\**|**** |****** |
**** |****** |**** |************\|**** |****** |
**** |****** |****/************** \****|****** |
**** |****** |**/****************** \**|****** |
**** |--------/********************** \--------|
**** |**************************************** |
**** |**************************************** |
**** |**************************************** |
**** |**************************************** |
****/****************************************** \

(F)orward, (L)eft or (R)ight?
Do you want to see the program now? Here it is...
Code:
/* 3DMaze
 * by Joseph Larson 2005
 * Maze generator written by Joseph Larson
 * 3D drawing routine by Sean Barrett 1991, found at the International
 * Obfuscated C Code Contest http://www.ioccc.org
 */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <ctype.h>
#include <string.h>
#include <math.h>

#define XMAX 39
#define YMAX 11
#define MID 26
#define WALL 0
#define UNSEEN 1
#define SEEN 2
#define TRAVL 3
#define EXIT -1
#define D(a) (2 * (a + 1))
#define NP(a, b) (a * (b - 1) + (a - 1) * b)
#define SWAP(a,b) a ^= b; b ^= a; a ^= b
#define X(a) xytable[(a) % 4]
#define Y(a) xytable[(a + 1) % 4]

int scale[6] = {11, 10, 6, 3, 1, 0};
int xytable[4] = {1, 0, -1, 0};
int maze[D(XMAX)][D(YMAX)], xsize, ysize, x, y, face, hpos;

void drawmap (void) {
**int c, d;

**for (d = 2 * ysize; d >= 0; d--) {
****putchar ('\n');
****for (c = 1; c < D(xsize); c++) 
******putchar ((c == x && d == y) ? '*' : "## ."[maze[c][d]]);
**}
}

void snr (int n1, int n2) { /* search and replace */
**int c, d;

**if (n1)
****for (c = 2; c < D(xsize); c++) for (d = 1; d < D(ysize) - 1; d++)
******if (maze[c][d] == n1) maze[c][d] = n2;
}

void generate (void) {
**int px[NP(XMAX, YMAX)], py[NP(XMAX, YMAX)], b, c, d;

**for (c = 0; c < D(XMAX); c++) for (d = 0; d < D(YMAX); d++) 
****maze[c][d] = (c) ? WALL : EXIT;
**b = 0;
**/* populate potentials */
**for (c = 3; c < 2 * xsize; c += 2) for (d = 1; d < 2 * ysize; d += 2) {
****px[b] = c; py[b++] = d;
**}
**for (c = 2; c <= 2 * xsize; c += 2) for (d = 2; d < 2 * ysize; d += 2) {
****px[b] = c; py[b++] = d;
**}
**/* randomize potentials */
**for (b = 0; b < NP(xsize, ysize); b++) {
****c = rand () % NP(xsize, ysize); 
****if (c - b) {SWAP (px[c], px[b]); SWAP (py[c], py[b]);}
**}
**/* make the maze */
**for (b = 0; b < NP(xsize, ysize); b++) {
****c = d = 0;
****if (py[b] % 2) c = 1; else d = 1;
****if (!maze[px[b] + c][py[b] + d] || !maze[px[b] - c][py[b] - d] 
******|| maze[px[b] + c][py[b] + d] != maze[px[b] - c][py[b] - d]) {
******snr (maze[px[b] + c][py[b] + d], b + 1); 
******snr (maze[px[b] - c][py[b] - d], b + 1);
******maze[px[b]][py[b]] = maze[px[b] + c][py[b] + d] 
******= maze[px[b] - c][py[b] - d] = b + 1;
****}
**}
**snr (maze[2][1], UNSEEN);
**/* now make an exit */
**maze[1][2 * (rand () % ysize) + 1] = UNSEEN;
**x =**2 * xsize; y =**2 * (rand () % ysize) + 1; face = 2;
}

int look (int f, int s) {
**int c, d, r;

**c = x + X(face) * f + X(face - 1) * s;
**d = y + Y(face) * f + Y(face - 1) * s;
**r = maze[c][d]; if (r == UNSEEN) maze[c][d] = SEEN;
**return r;
}

void draw (int col, char *s) {
**while (hpos < col) {putchar (' '); hpos++;}
**printf ("%s", s); hpos += strlen (s);
}

void draw3d(void) {
**int line, side, depth, p, q, i;
**
**putchar ('\n');
**for (line = -11; line <= 11; ++line) {
****for(side = 1, depth = 0; side + 3; side-=2) {
******for (; depth != 2 + 3 * side; depth += side) {
********if(look (depth, 0) < UNSEEN) {
**********p = scale[depth];
**********if (abs(line) < p && look(depth, 0) == WALL || abs (line) > p) break;
**********for (i = -p; i < p; ++i) draw (MID + i * 2, "--");
**********draw (0, "-"); break;
********}
********if (depth == 5) continue;
********p = scale[depth + 1]; q = scale[depth];
********if (abs (line) > q) continue;
********if (abs (line) < p) draw (MID - side * (2 * p + 1), "|");
********else if (look (depth, side)) {
**********if (abs (line) <= p)
************for(i = (side == 1 ? -q : p); i != (side == 1 ? -p : q);
**************(abs (line)), ++i)
**************draw (MID + 2 * i + (side == -1), "--");
********} else if (abs(line) == p)
**********draw (MID - side * (2 * p + 1), "|");
********else draw (MID - (abs (line) * side * 2),
**********(side == 1) ^ (line > 0) ? "\\" : "/");
******}
******depth -= side;
****}
****putchar ('\n'); hpos=0;
**}
**if (maze[x][y] != EXIT) maze[x][y] = TRAVL;
}

int move (void) {
**char in;

**printf ("\n%c (F)orward, (L)eft or (R)ight? ", "WSEN"[face]);
**do in = getche (); while (!isalnum (in)); in = tolower (in);
**if (in == 'm') drawmap ();
**else {
****if ((in == 'w' || in == 'f') && look (1, 0) != WALL)
******{x += X(face); y += Y(face);}
****if ((in == 's' || in == 'b') && look (-1, 0) != WALL)
******{x -= X(face); y -= Y(face);}
****face += (in == 'd' || in == 'r') + 3 * (in == 'a' || in == 'l');
****if (in == 'z'&& look (1, 0) != WALL) do {x += X(face); y += Y(face); draw3d ();}
******while (look (1, 0) > WALL && look (0, 1) == WALL && look (0, -1) == WALL);
****draw3d (); face %= 4;
**}
**return (in != 'q');
}

void setsize (void) {
**char in;
**
**printf ("(E)asy, (M)edium or (H)ard? ");
**do {
****do in = getche (); while (!isalnum (in)); in = tolower (in);
****switch (in) {
******case 'e' : xsize = ysize = 5; break;
******case 'm' : xsize = 15; ysize = 11; break;
******case 'h' : xsize = XMAX; ysize = YMAX; break;
******default : printf ("\nInvalad Option. Please choose E, M, or H? ");
********xsize = ysize = 0;
****}
**} while (!xsize);
}

int main (void) {
**clock_t st, et;
**double secs;
**
**srand (time (NULL));
**setsize ();
**generate ();
**draw3d ();
**st = clock ();
**while (move () && look (0,0) != EXIT);
**if (look (0, 0) == EXIT) {
****et = clock ();
****secs = (double)(et - st) / CLOCKS_PER_SEC;
****snr (UNSEEN, SEEN);
****drawmap ();
****printf ("\nYou escaped the Labryinth in %2.3f seconds!\n", secs);
**}
**exit (0);
}
I made my own keys for playing this. Yes, 'L' will go left, 'R' will go right and so forth, but also 'WADS' can be used. 'M' displays the map so far and 'Z' is a special command I made that will zip you forward until you hit a wall or a branching path.

The constants WALL, UNSEEN, SEEN, TRAVL, and EXIT are for the map. When the maze is generated you have WALLs and UNSEEN everywhere and EXIT at the end. As you see an area UNSEEN becomes SEEN and as you go there the spot you stand on becomes TRAVL. That way at the end you can see what path you took through the maze.

The maze generating algorithm doesn't make paths through the maze or anything. It just makes sure you can get anywhere from anywhere else one and only one way. It connectes two spaces with a numbered path. If two paths are connected the higher number over rides the other path so that if it wanto to join two areas it only needs to be sure they aren't of the same path, meaining a loop would be generated. A hole is punched in the left side for the exit. I had considered having a square maze, dropping the player in the exact middle, and punching one hole in any of the outside walls, meaning you could wander the wrong direction for a long time before getting out. But I decided against that for a straight east to west progression to make it less diabolical. Besides, a square map of more than 11x11 would not show well on the map printout.

This game is so cool I absolutely recomend downloading DevCPP and playing this one. It's a hoot. I wanted to include the executable here, but the boards don't allow it. But you have the code, so go on with you.

So there is 3DMaze. What's next?
  • Battleship (like the board game vs the computer)
  • Cel Life (multi-player version of John Conway's game of Life)
  • Awari (african counting game with a learning algorithm)
  • Pickup Piles (1000 games in one, set the rules and play)
  • Flash Cards (with pretty output, practice your math)
  • Hammurabi (rule a country, build your kingdom)
  • Black Box (find molecules in the inky depths)
  • Hangman (guess the word before you dangle)
  • Mugwump (find the creatures hiding on a grid with a distance detector)
  • Acey Deucy (a card game of highs, lows, and middles)
  • Reverse (order a list of number by turning them around)
  • Stars/Trap/Letter Guess (3 games in 1 update, variations on a theme)
guesst is offline                         Send a private message to guesst
Reply With Quote