Build a Simple Roguelike

8

2

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!

Paul Prestidge

Posted 2012-08-24T01:49:20.973

Reputation: 2 390

Pretty close to a duplicate of Build an engine for a maze game which could certainly use some additional entries. Thoughts?

– dmckee --- ex-moderator kitten – 2012-08-24T02:46:33.733

@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. – Paul Prestidge – 2012-08-24T02:51:14.680

I'll certainly buy the hardcoded map bit. Now just let me just think on how I might adapt my previous solution... – dmckee --- ex-moderator kitten – 2012-08-24T02:52:32.633

2

I just can't help but mention the game that introduced me to C: http://www.nethack.org/

– SeanC – 2012-08-24T04:53:37.770

Answers

6

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);}

schnaader

Posted 2012-08-24T01:49:20.973

Reputation: 1 132

This doesn't compile for me. – Matt – 2012-08-24T14:11:07.433

Compiles and works for me using Visual Studio 2008. – Sir_Lagsalot – 2012-08-24T15:20:45.483

@Matt: Hm.. I successfully tried both MinGW (gcc 4.6.1) and MSVC (VS 2009) under Windows so far. What's the error message? – schnaader – 2012-08-24T16:19:49.113

@schnaader in gcc 4.4.5 I get: test.c:(.text+0x1a1): undefined reference to `putch'. I get the same error for getch – Matt – 2012-08-24T17:03:05.860

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. – schnaader – 2012-08-24T17:42:17.447

Update: Tried all alternatives I can think of for getch - getchar, scanf, fgetc, fgets, but none handles extended key codes correctly. @Matt: Does adding #include <conio.h> (followed by a newline) to the beginning work for you? – schnaader – 2012-08-24T20:06:52.213

@schnaader replacing all instances of putch with putchar results in an incorrectly drawn map. I don't have conio.h so I can't test that. I don't actually care too much if it works for me since someone else verified it. – Matt – 2012-08-25T01:52:59.743

4

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[]}

Paul Prestidge

Posted 2012-08-24T01:49:20.973

Reputation: 2 390

1That uses a map different from the specified one. I recommend using 0xf3e499e601c0d0240b0380679927cf instead. – Matt – 2012-08-24T04:00:36.593

@Matt good catch, thanks! – Paul Prestidge – 2012-08-24T04:04:49.643

3

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.

Matt

Posted 2012-08-24T01:49:20.973

Reputation: 1 395

1

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.

DLosc

Posted 2012-08-24T01:49:20.973

Reputation: 21 213