I wrote this code. It is written in C++0x.
You can compile it with e.g.
Intel C++ Compiler by the following commandline:
icc --std=c++0x bisqwitmaze.cc
(Sorry, GCC does not support this syntax yet.)
#include <cstdio>
#include <cstdlib>
#include <wchar.h>
const int w=79, h=23;
static void draw(const wchar_t maze[w*h])
{
for(int p=0; p<h; ++p)
std::printf("%.*ls\n", w, maze+p*w);
}
static void gen(wchar_t maze[w*h])
{
// Mark edges as walls and the interior as space
for(int p=0; p<w*h; ++p)
maze[p] = p%w==0||p%w==w-1 // vert walls at l&r
||p/w==0||p/w==h-1; // horiz walls at t&b
// Populate the maze with maze walls
for(int p=0; p<9999; ++p)
{
int r = std::rand(), x,y,x2,y2, hh=h/2, wh=w/2, l, hits=0, pos;
if(std::rand()%2) // horiz wall
l=4, // length
y = y2 = 2*(r%(hh)+1), // an even row starting from 2
x = 2*(r/(hh)%(wh+2-l)), // an even column
x2 = x+l;
else // vert wall
l=2, // length
x = x2 = 2*(r%(wh)+1), // an even column starting from 2
y = 2*(r/(wh)%(hh+2-l)), // an even row
y2 = y+l;
// s is a scaling helper function
auto s = [&pos,l] (int a,int b) { return a + (b-a)*pos/l; };
for(pos=0; pos<=l; ++pos) hits += maze[s(y,y2)*w + s(x,x2)];
if(hits != 1) continue; // must hit another wall in exactly 1 spot
for(pos=0; pos<=l; ++pos) maze[s(y,y2)*w + s(x,x2)] = 1;
}
// e = helper function which tells whether the given char is not '\0' or space.
// space needs to be recognized due to the scanning order in the loop.
auto e = [] (wchar_t c) { return c && c != L' '; };
// Convert maze to text
for(int y=0, p=0; y<h; ++y)
for(int x=0; x<w; ++x,++p)
{
// Check neighbours (top,bottom,left,right)
int t = y>0 && e(maze[p-w]), b = y<h-1 && e(maze[p+w]);
int l = x>0 && e(maze[p-1]), r = x<w-1 && e(maze[p+1]);
// Convert this spot to a character
maze[p] =
L" ~oI" // 0
L")J\\+" // l
L"(LF+" // r
L"=+z+" // l+r
// 0, t, b, t+b
[maze[p]*(t + b*2 + l*4 + r*8)];
}
}
int main()
{
wchar_t maze[w*h];
gen(maze);
draw(maze);
}
It produces this output:
F=z===z=========z=z=z===z===z=z=z=z=========z=====z=====z===z=====z===z=====z=\
I I I I I I I I I I I I I I I I I I I
I ~ o ~ (=====z=+ I I F=+=) ~ I ~ +=======) I F=z=+=z=) I (=+=\ o ~ (=+=\ o ~ I
I I I I I I I I I I I I I I I I I I I I I I
I o +=z=z=z=\ I I ~ I I I F===J (=+=) o (===J I ~ ~ I (=+=) I ~ +=====z=+=+=\ I
I I I I I I I I I I I I I I I I I I I I I I
+=+=J ~ I ~ ~ ~ I o ~ I I +===) (=+=z=+=\ o o ~ F===J (===\ ~ o ~ o o +===) ~ I
I I I I I I I I I I I I I I I I I I
I (=z=\ L===) o L=+=) ~ ~ L=z=\ F===J o ~ L=+===+=) (=====+=) I (=+=J ~ (=z=\ I
I I I I I I I I I I I I I I
+=z=J L===\ o L=z=) F=======+ ~ ~ (===+ (=z=z=z=z===z===z=+=) I (=+=\ o o I ~ I
I I I I I I I I I I I I I I I I I I I I I
I ~ o o o ~ I (=+=) ~ o o o ~ o F===) I o ~ ~ I ~ o ~ o ~ L===+=z===+=+=+=J o I
I I I I I I I I I I I I I I I I I I I I
+===+=+=+=z=J o +=====+=+=+===+=+ o o L=+=\ (=+=\ L===+===\ (=z=J (=z=) ~ o I I
I I I I I I I I I I I I I I I I I I I
+===) ~ ~ ~ o I ~ o o ~ L===) o +=+=+===\ I o o ~ (=======+===+ o F=+=) F=+=+ I
I I I I I I I I I I I I I I I I I
I F===z=z===+=J (=+=J o o o o I ~ o (===+ L=+=+=z=\ o o o (===+=+=J F===J o ~ I
I I I I I I I I I I I I I I I I I I I I I I
+=+=) ~ ~ o F===) L=z=J I L=+=+ (=+=) o I (===+ ~ ~ I I I o (=+=) F=+=) o I o I
I I I I I I I I I I I I I I I I I I I I
L=========+=+=======+===+=====+===+===+=+=====+=====+=+=+=+===+===+=====+=+=+=J
I present a number of challenges to the coding-savvy people:
3 points: Change the code to produce loops in the maze.
9 points: Change the code such that it compiles on compilers that do not support C++0x.
13 points: Change the code such that it uses
Unicode line-drawing characters, block elements and other geometric shapes for a beautiful outcome. To get you started, the code is already written using the wchar_t type. You don't need to write utf-8 encoders and decoders.
1 point: Change the code such that it may produce locations on the map that are unreachable.
20 points: Complete the above task, and change the code to indicate the unreachable areas somehow (for example, by using "." instead of " " for those unreachable locations).
1 point: Change the code to produce two exits somewhere on the opposing edges of the maze.
15 points: Complete the above task, and change the code to indicate the
longest solution path between the two exits (walking the same path twice is not allowed, though crossing the path is allowed).
24 points: Translate the code into LUA.
In all of these tasks, particularly artistically written code and nice looking output may both give extra points. Lucky bugs or code that doesn't quite work may reduce your points.
Send your solutions to me by a PM. Put the word "maze" somewhere in the message subject. Indicate which challenges you have solved, and which platforms you have compiled the program on. A copy of the solution's output is preferable.
Multiple submissions by the same author are accepted; the latter submission overrides the earlier one.
This challenge is open until 2009-04-20. I will try to maintain a leaderboard in this post. After the challenge closes, I will post some if not all of the source code submitted.
The number of points awarded on each category is subject to change, but I will try to keep it fair.
EDIT: Challenge is closed now.
Here's a useful hint on C++0x.