8
\$\begingroup\$

This challenge is based on one proposed on the usenet group rec.games.roguelike.development a few years ago. I can't find the original newsgroup post, but you can have a look a the Github repo of solutions. It was only golfed in a couple of languages and I'd love to see some more!

Objective

The aim is to build a program that presents a top-down view of a dungeon using ascii characters. There will be an @ sign representing the player that can be moved through the free space in the dungeon (represented by ), though it cannot pass through the walls (represented by #).

The map of the dungeon must look like this:

####  ####
#  #  #  #
#  ####  #
#        #
##      ##
 #      #
 #      #
##      ##
#        #
#  ####  #
#  #  #  #
####  ####

The player must begin at location {2,2}, where {0,0} is the top left-hand corner.

Interface

The user needs to be able to move the player in the four cardinal directions using the arrow keys on the keyboard.

There needs to be some way for the user to exit the program. It does not need to be a graceful exit (for example, it doesn't matter if an exception is printed).

The map and player need to be drawn before any input has been taken, and the player needs to be updated after each input.

Libraries

Feel free to use established libraries for console input or output, such as Curses. Just mention in your answer what you are using.

Scoring

This is code golf, shortest code wins!

\$\endgroup\$
  • \$\begingroup\$ Pretty close to a duplicate of Build an engine for a maze game which could certainly use some additional entries. Thoughts? \$\endgroup\$ – dmckee Aug 24 '12 at 2:46
  • \$\begingroup\$ @dmckee It's definitely pretty similar. I hope the simpler input mechanism and the challenge of efficiently hardcoding the preset map will make it different enough. \$\endgroup\$ – Paul Prestidge Aug 24 '12 at 2:51
  • \$\begingroup\$ I'll certainly buy the hardcoded map bit. Now just let me just think on how I might adapt my previous solution... \$\endgroup\$ – dmckee Aug 24 '12 at 2:52
  • 2
    \$\begingroup\$ I just can't help but mention the game that introduced me to C: nethack.org \$\endgroup\$ – SeanC Aug 24 '12 at 4:53
6
\$\begingroup\$

C, 257 253 222 220

Uses system("cls") instead of curses (use system("clear") for Linux systems) and a clever algorithm to fit the map into an 8-digit number. Non-extended keys end the program, e.g. escape.

EDIT: Now also shows your hero below the map by using a<230 instead of a<132:

    ##
   ####
 ###  ###
 # #  # #
## #  # ##
   ####
  #    #
 ##    ##

Code:

a,p=14,w=11,X,Y;m(I){X=I%w-1,Y=I/w;return 70313263>>(Y>5?w-Y:Y)*5+(X>4?9-X:X)&1;}main(){do{system("cls");a=a&4?1:a&2?-1:a&8?-w:w;p+=!m(p+a)*a;for(a=0;++a<230;)putch(a%w?a-p?m(a)*35:64:10);}while(a=getch()>>7?getch():0);}
\$\endgroup\$
  • \$\begingroup\$ This doesn't compile for me. \$\endgroup\$ – Matt Aug 24 '12 at 14:11
  • \$\begingroup\$ Compiles and works for me using Visual Studio 2008. \$\endgroup\$ – Sir_Lagsalot Aug 24 '12 at 15:20
  • \$\begingroup\$ @Matt: Hm.. I successfully tried both MinGW (gcc 4.6.1) and MSVC (VS 2009) under Windows so far. What's the error message? \$\endgroup\$ – schnaader Aug 24 '12 at 16:19
  • \$\begingroup\$ @schnaader in gcc 4.4.5 I get: test.c:(.text+0x1a1): undefined reference to `putch'. I get the same error for getch \$\endgroup\$ – Matt Aug 24 '12 at 17:03
  • \$\begingroup\$ For putch, there's putchar which does the same, but I don't know how to replace getch - there's a getchar too, but it doesn't work for me - seems it doesn't recognize the cursor keys. \$\endgroup\$ – schnaader Aug 24 '12 at 17:42
4
\$\begingroup\$

Ruby 1.9 + Curses (248)

require'curses';include Curses;noecho;curs_set 0
b=0xf3e499e601c0d0240b0380679927cf.to_s(2).tr'01',' #'
s=init_screen<<b.scan(/.{10}/)*$/;s.keypad 1
p=22;d=->t=?@{setpos p/10,p%10;addch t;6};d[]
loop{p=b[v=p+[10,-10,-1,1][getch%d[32]]]<?#?v:p;d[]}
\$\endgroup\$
  • 1
    \$\begingroup\$ That uses a map different from the specified one. I recommend using 0xf3e499e601c0d0240b0380679927cf instead. \$\endgroup\$ – Matt Aug 24 '12 at 4:00
  • \$\begingroup\$ @Matt good catch, thanks! \$\endgroup\$ – Paul Prestidge Aug 24 '12 at 4:04
3
\$\begingroup\$

Python 332 319 317

from curses import*
M=0xf3e499e601c0d0240b0380679927cf;S=initscr();S.keypad(1);x,y=2,2;A=S.addstr;[A(a,b,[' ','#'][M>>(10*a+b)&1])for a in range(12)for b in range(10)]
while 1:A(y,x,'@');k=S.getch();A(y,x,' ');X=[[x,x-1],[x+1,1]][k==261][k==260];Y=[[y,y-1],[y+1,y+1]][k==258][k==259];x,y=[(X,Y),(x,y)][M>>(10*Y+X)&1]

The python curses library is only officially supported on linux. There are unofficial ones available for windows, but I can't guarantee that this will work with it.

To save a few characters I hard coded the keycodes for up, down, left, and right. This may cause problems for some people. If this doesn't work for anyone I can post a version that should.

Use ctrl+c to exit. You will probably have to reset your terminal after exiting, but the challenge specifically said the exit didn't have to be graceful.

\$\endgroup\$
1
\$\begingroup\$

QBasic, 314 313 bytes

This sort of problem simply begs for a QBasic solution.

DIM w(12,10)
FOR r=1TO 12
READ d
FOR c=1TO 10
w(r,c)=(d*2AND 2^c)>0
?CHR$(35+3*w(r,c));
NEXT
?
NEXT
i=3
j=3
1LOCATE i,j
?"@"
a$=""
9a$=INKEY$
IF""=a$GOTO 9
k=ASC(RIGHT$(a$,1))
x=i+(k=72)-(k=80)
y=j+(k=75)-(k=77)
LOCATE i,j
?" "
IF w(x,y)THEN i=x:j=y
IF k>9GOTO 1
DATA 48,438,390,510,252,765,765,252,510,390,438,48

This is golfed QBasic, which will be expanded significantly by the autoformatter. But, if you type this exact code into the IDE and hit F5, it should run. Tested on QB64.

Screenshot

Explanation:

The map is encoded row-wise as the bits of the integers in the DATA statement (1 for space, 0 for wall). The nested FOR loop unpacks them, storing truth values in the 2D array w, and printing # or accordingly. (Note that true in QBasic is -1, thus why we're adding to 35 instead of subtracting!) The player starts at 3,3 because most things are 1-indexed in QBasic.

We then enter a GOTO loop: print the @, get keyboard input, convert to extended character code, and modify x and y based on whether the user pressed L/U/R/D. If w(x,y) is true, then it's a space and we can move there; otherwise, stay put. Finally, the shortest way I found to exit is by pressing the tab key (ASCII 9). Any other input loops us back up to the first LOCATE statement.

I must say, I'm rather tickled to have beaten Python with a QBasic answer.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.