Automapping

It’s a rough draft, but I think this is at the point where it could do with other eyes on it for feedback. The idea is that the game automatically produces a map showing visited rooms as you move. It wouldn’t be hard to make it also put links on the map that execute a GO TO.

Automap:

(map $Room at $Coords)
	(now) ($Room has coordinates $Coords)
	(exhaust) (spread coordinates from [$Room])

(spread coordinates from $List)
	(nonempty $List)
	(collect $Next)
		*($This is one of $List)
		*(from $This go $Dir to $Next)
		~($Next has coordinates $)
		($This has coordinates $ThisC)
		($ThisC modified by $Dir becomes $NextC)
		(now) ($Next has coordinates $NextC)
	(into $NextGen)
	(spread coordinates from $NextGen)
(spread coordinates from [])

([$X $Y $Z] modified by #north becomes [$X $Y1 $Z])
	($Y minus 1 into $Y1)
([$X $Y $Z] modified by #south becomes [$X $Y1 $Z])
	($Y plus 1 into $Y1)
([$X $Y $Z] modified by #west becomes [$X1 $Y $Z])
	($X minus 1 into $X1)
([$X $Y $Z] modified by #east becomes [$X1 $Y $Z])
	($X plus 1 into $X1)

([$X $Y $Z] modified by #northeast becomes [$X1 $Y1 $Z])
	($X plus 1 into $X1)
	($Y minus 1 into $Y1)
([$X $Y $Z] modified by #northwest becomes [$X1 $Y1 $Z])
	($X minus 1 into $X1)
	($Y minus 1 into $Y1)
([$X $Y $Z] modified by #southeast becomes [$X1 $Y1 $Z])
	($X plus 1 into $X1)
	($Y plus 1 into $Y1)
([$X $Y $Z] modified by #southwest becomes [$X1 $Y1 $Z])
	($X minus 1 into $X1)
	($Y plus 1 into $Y1)

([$X $Y $Z] modified by #up becomes [$X $Y $Z1])
	($Z plus 1 into $Z1)
([$X $Y $Z] modified by #down becomes [$X $Y $Z1])
	($Z minus 1 into $Z1)

(minimum of [$Head] is $Head)
(minimum of [$Head|$Tail] is $Min)
	(minimum of $Tail is $Other)
	(if) ($Head < $Other) (then)
		($Min = $Head)
	(else)
		($Min = $Other)
	(endif)
(maximum of [$Head] is $Head)
(maximum of [$Head|$Tail] is $Max)
	(maximum of $Tail is $Other)
	(if) ($Head > $Other) (then)
		($Max = $Head)
	(else)
		($Max = $Other)
	(endif)

(draw map of layer $Z)
	(collect $Room)
		*(room $Room)
		($Room is visited)
		($Room has coordinates [$ $ $Z])
	(into $Rooms)
	
	(collect $X)
		*($Room is one of $Rooms)
		($Room has coordinates [$X $ $])
	(into $Xs)
	(collect $Y)
		*($Room is one of $Rooms)
		($Room has coordinates [$ $Y $])
	(into $Ys)
	
	(maximum of $Xs is $XMax)
	(minimum of $Xs is $XMin)
	(maximum of $Ys is $YMax)
	(minimum of $Ys is $YMin)
	
	(draw header of layer $Z from $XMin to $XMax)
	(draw map of layer $Z from $XMin to $XMax and $YMin to $YMax)
	(draw footer of layer $Z from $XMin to $XMax)

(draw map of layer $Z from $XMin to $XMax and $Y to $YMax)
	($Y > $YMax) %% Base case: no more recursion
	(draw exit header of row $Y)
	(draw exits above $Y of $Z from $XMin to $XMax) %% Just draw final row of exits
(draw map of layer $Z from $XMin to $XMax and $Y to $YMax)
	(draw exit header of row $Y)
	(draw exits above $Y of $Z from $XMin to $XMax)
	(draw header of row $Y)
	(draw row $Y of layer $Z from $XMin to $XMax)
	(draw footer of row $Y)
	($Y plus 1 into $YNext)
	(draw map of layer $Z from $XMin to $XMax and $YNext to $YMax)

(draw row $Y of layer $Z from $X to $XMax)
	($X > $XMax) %% Base case
	($X minus 1 into $XM1)
	(if) (exit #east from [$XM1 $Y $Z]) (then)
		-
	(else)
		(space 1)
	(endif)
(draw row $Y of layer $Z from $X to $XMax)
	($X plus 1 into $XP1)
	($X minus 1 into $XM1)
	%% West exit
	(if) (exit #west from [$X $Y $Z]) (or) (exit #east from [$XM1 $Y $Z]) (then)
		-
	(else)
		(space 1)
	(endif)
	%% Room
	(if) (room $Room at [$X $Y $Z] is visited) (then)
		\( (no space) (room glyph $Room) (no space) \)
	(else)
		(space 3)
	(endif)
	(draw row $Y of layer $Z from $XP1 to $XMax)

(room glyph $Room)
	(if) (current room $Room) (then)
		\@
	(else)
		(space 1)
	(endif)

(final exits above $X $Y $Z) %% Cut-down version of the below for the very right edge
	($Y minus 1 into $YM1)
	($X minus 1 into $XM1)
	(if) (exit #southeast from [$XM1 $YM1 $Z]) (then)
		($NorthWest = 1)
	(else)
		($NorthWest = 0)
	(endif)
	(if) (exit #northeast from [$XM1 $Y $Z]) (then)
		($NorthEast = 1)
	(else)
		($NorthEast = 0)
	(endif)
	(if) ($NorthWest = 1) (then)
		(if) ($NorthEast = 1) (then)
			X
		(else)
			\\
		(endif)
	(else)
		(if) ($NorthEast = 1) (then)
			/
		(else)
			(space 1)
		(endif)
	(endif)

(draw exits above $Y of $Z from $X to $XMax)
	($X > $XMax) %% Base case
	(final exits above $X $Y $Z)
	(line)
(draw exits above $Y of $Z from $X to $XMax)
	($X plus 1 into $XP1)
	($X minus 1 into $XM1)
	($Y minus 1 into $YM1)
	%% Northwest exit
	(if) (exit #northwest from [$X $Y $Z]) (or) (exit #southeast from [$XM1 $YM1 $Z]) (then)
		($NorthWest = 1)
	(else)
		($NorthWest = 0)
	(endif)
	%% Northeast exit
	(if) (exit #northeast from [$XM1 $Y $Z]) (or) (exit #southwest from [$X $YM1 $Z]) (then)
		($NorthEast = 1)
	(else)
		($NorthEast = 0)
	(endif)
	(if) ($NorthWest = 1) (then)
		(if) ($NorthEast = 1) (then)
			X
		(else)
			\\
		(endif)
	(else)
		(if) ($NorthEast = 1) (then)
			/
		(else)
			(space 1)
		(endif)
	(endif)
	%% Up exit
	(if) (exit #down from [$X $YM1 $Z]) (then)
		(no space) d (no space)
	(else)
		(space 1)
	(endif)
	%% North exit
	(if) (exit #north from [$X $Y $Z]) (or) (exit #south from [$X $YM1 $Z]) (then)
		\|
	(else)
		(space 1)
	(endif)
	
	(if) (exit #up from [$X $Y $Z]) (then)
		(no space) u (no space)
	(else)
		(space 1)
	(endif)
	
	(draw exits above $Y of $Z from $XP1 to $XMax)

(draw exit header of row $)
	(space 1)

(draw header of row $Y)
	$Y (no space)
(draw footer of row $Y)
	(no space) $Y (line)

(draw header of layer $Z from $XMin to $XMax)
	$Z (space 1)
	(draw legend from $XMin to $XMax)
	(no space) $Z
	(line)
(draw footer of layer $Z from $XMin to $XMax)
	(draw header of layer $Z from $XMin to $XMax)
(draw legend from $XMin to $XMax)
	($XMin > $XMax) %% Base case
(draw legend from $XMin to $XMax)
	(space 1) $XMin (space 2)
	($XMin plus 1 into $XMin1)
	(draw legend from $XMin1 to $XMax)

(room $Room at $Coords is visited)
	*(room $Room)
	($Room has coordinates $Coords)
	($Room is visited)

(exit $Dir from $Coords)
	(room $Room at $Coords is visited)
	(from $Room go $Dir to $Other)
	(room $Other)

And a test scenario:

(from #alpha go #east to #beta)
(from #beta go #west to #alpha)
(from #alpha go #south to #gamma)
(from #gamma go #north to #alpha)
(from #beta go #south to #delta)
(from #delta go #north to #beta)
(from #gamma go #east to #delta)
(from #delta go #west to #gamma)

(from #alpha go #southeast to #delta)
(from #delta go #northwest to #alpha)
(from #beta go #southwest to #gamma)
(from #gamma go #northeast to #beta)
(from #beta go #southeast to #epsilon)
(from #epsilon go #northwest to #beta)
(from #epsilon go #south to #zeta)
(from #zeta go #north to #epsilon)

(from #beta go #up to #eta)
(from #eta go #down to #beta)

(room #alpha/#beta/#gamma/#delta/#epsilon/#zeta/#eta)

(#player is #in #alpha)
(current player #player)
(intro)
	(map #alpha at [1 1 1])
	(perform [look])

(perform [look])
	(current room $Room)
	($Room has coordinates [$ $ $Z])
	(div @map) (draw map of layer $Z)

(style class @map)
	font-family: monospace;

Test with dgdebug test_automap.dg automap.dg stdlib.dg.

Potential next steps:

  • Links!
  • Unicode instead of ASCII
  • Some way of resizing the status line to support it?
3 Likes