8
\$\begingroup\$

Your program has to take a multi-lined string, like this:

#############
#           #
#     p     #
#           #
#############

p is the player and # is a block.

Now under that in the terminal should be an input line saying:

How do you want to move?

If the player types l he has to walk left when there isn't a block, else, when there is a block, he can't go through and doesn't move of course, now the output in the terminal has to be updated (and the previous output cleared/overwritten):

#############
#           #
#    p      #
#           #
#############

He can type l for left, r for right, u for up and d for down.

The input will always be multiline, but won't always be padded with spaces into a perfect rectangle. In addition, the hashes can be anywhere in the string, and won't always be connected to each other. For example:

##  ##
#  #
## p
     #

is a valid dungeon. (note the lack of trailing spaces on each line)

If the player goes outside of the string, he doesn't have to be displayed. But if he comes back later, he must be displayed again.

And the boundaries of "outside" the string are the length(longest_line) by number_of_lines rectangle, so even if one line isn't padded with spaces on the right, that location isn't considered out of bounds. Example using the earlier dungeon:

##  ##
#  #p
##  
     #

The second line didn't have a space where the p is now, but that doesn't matter.

Finally, your program must loop forever taking input.

Test cases

Test case 1:

####
# p#
#
####

How do you want to move?
d

####
#  #
# p
####

Test case 2:

####
  p#
   #
####

How do you want to move?
l

####
 p #
   #
####

How do you want to move?
d

####
   #
 p #
####

How do you want to move?
l

####
   #
p  #
####

How do you want to move?
l

####
   #
   #
####

How do you want to move?
r

####
   #
p  #
####

Of course, these aren't complete. Your code should loop forever and clear the screen between each output.

Your output is allowed to prompt for input as How do you want to move?\n<input> or How do you want to move?<input> (i.e. you don't need the input on a blank line), and you don't need a empty line between the final line of the dungeon and the prompt. (they can't be on the same line however)

Standard loopholes are disallowed ! This is code-golf, so the shortest code in bytes wins!

\$\endgroup\$
9
  • 3
    \$\begingroup\$ Is it acceptable if the input is a letter followed by enter? Also, I suggest getting rid of having to print that string, which doesn't seem to add anything to the challenge \$\endgroup\$
    – Luis Mendo
    Dec 13, 2016 at 16:03
  • 2
    \$\begingroup\$ I think this is re-openable, but my suggestion is that the input prompt (for l, r, u, or d) can be anything, not just "How do you want to move"? It doesn't really affect the answers except for golfyness. \$\endgroup\$
    – Riker
    Dec 14, 2016 at 21:15
  • \$\begingroup\$ @EasterlyIrk : I wouldnt agree. Because in this case, the golfers will have to think about how to compress the string to save bytes. \$\endgroup\$
    – Luatic
    Dec 15, 2016 at 13:17
  • 2
    \$\begingroup\$ @user7185318 Keep this in mind, basically stick with 1 problem per challenge. Compressing the string is a completely separate problem then making a dungeon crawler, and thus probably shouldn't be tacked on to that challenge. \$\endgroup\$
    – Riker
    Dec 15, 2016 at 16:47
  • 1
    \$\begingroup\$ Is it acceptable if the player is displayed when they are out of bounds, or do they need to disappear? \$\endgroup\$
    – hwm
    Dec 18, 2016 at 7:15

3 Answers 3

4
\$\begingroup\$

Haskell :: 799 703 bytes

Hi

This is my first code-golf submission.

It reads the initial grid from a text file.

Golfed:

    import Data.List
    x=maximum
    n=minimum
    r=filter
    s=length
    pad i r=r++(' '<$[1..(i-s r)])
    f l=let{w=x.map s$l;h=s l}in r((/=' ').snd).zip(flip(,)<$>[h,h-1..]<*>[1..w]).(pad w=<<)$l
    sh b=let{t=x.map(snd.fst)$b;d=n.map(snd.fst)$b;l=n.map(fst.fst)$b;sr _ []=[];sr i xb@((x,c):b)|x==i=c:sr(i+1)b|1>0=' ':sr(i+1)xb}in putStr.unlines.map(sr l.sort).map(\r->[(x,c)|((x,y),c)<-b,y==r])$[t,t-1..d]
    x!b|x`elem`map fst b=b|1>0=(x,'p'):r((/='p').snd)b
    b?i=let((x,y):_)=[x|(x,'p')<-b]in(case i of{'r'->(x+1,y);'l'->(x-1,y);'u'->(x,y+1);'d'->(x,y-1);_->(x,y)})!b
    m b=do{putStrLn"How do you want to move?";i<-getChar;putStr"\ESC[2J";let{d=b?i};sh d;m d}
    main = do{l<-readFile"s.txt";let{s=f.lines$l};sh s;m s}

An arguably more readable version:

import Data.List (sort)

data Board = Board [((Int,Int),Char)]

fromList l =
    let width = maximum . map length $ l
        height = length l
        coords = zip
            [(x,y) | y <- [height,height-1..1], x <- [1..width]]
            (concat (map (pad width ' ') l))
        clean = filter (\((_,_),c) -> c /= ' ') coords
    in Board clean

instance Show Board where
    show (Board xs) =
        let top = maximum . map (\((_,y),_) -> y) $ xs
            bottom = minimum . map (\((_,y),_) -> y) $ xs
            left = minimum . map (\((x,_),_) -> x) $ xs
            rows = map (\r -> [(x,c) | ((x,y),c) <- xs, y == r]) [top,top-1..bottom]
            showrow _ [] = []
            showrow i xxs@((x,c):xs)
                | x == i = c : showrow (i+1) xs
                | otherwise = ' ' : showrow (i+1) xxs
        in unlines . map ((showrow left) . sort) $ rows

insert z (Board zs) = Board (z:zs)

remove y (Board xs) = Board [(x,c) | (x,c) <- xs, x /= y]

at x (Board xs) =
    let match = [c | (x',c) <- xs, x' == x]
        ifempty [] = ' '
        ifempty (c:_) = c
    in ifempty match

move from@(x1,y1) to@(x2,y2) cur@(Board zs)
    | to `elem` [x | (x,c) <- zs] = cur
    | otherwise =
        let c = at from cur
        in insert (to,c) . remove from $ cur

find c (Board b) = [(x,y) | ((x,y),c') <- b, c' == c]

main = do
    startlist <- readFile "start.txt"
    let start = fromList . lines $ startlist
    print start
    maingameloop start

maingameloop board = do
    putStrLn "Where would you like to move?"
    inp <- getChar
    putStr "\ESC[2J"
    let newboard = movePlayer board inp
    print newboard
    maingameloop newboard

movePlayer board inp =
    let (cur@(x,y):[]) = find 'p' board
    in case inp of
        'r' -> move cur (x+1,y) board
        'l' -> move cur (x-1,y) board
        'u' -> move cur (x,y+1) board
        'd' -> move cur (x,y-1) board
        _ -> board

pad :: Int -> a -> [a] -> [a]
pad i c cs = cs ++ replicate (i - length cs) c
\$\endgroup\$
2
  • 2
    \$\begingroup\$ Welcome to the site! I believe reading from a text file is normally allowed. You may also want to check out our tips for golfing in haskell. \$\endgroup\$ Nov 27, 2020 at 18:32
  • \$\begingroup\$ Thanks @RedwolfPrograms! I changed some code to make it even more horrible. \$\endgroup\$
    – Frut Jus
    Dec 1, 2020 at 20:49
1
\$\begingroup\$

MATLAB, 268 247 246 bytes

Probably not competitive, but it was fun. Golfed version:

function f(s);d=char(split(s,'\n'));[y,x]=ind2sub(size(d),find(d=='p'));while 1;d
c=uint8(input('How do you want to move?','s'))-100;v=y+~c-(c==17);w=x+(c==14)-(c==8);try;d(y,x)=' ';end;try;if'#'==d(v,w);v=y;w=x;end;d(v,w)='p';end;y=v;x=w;clc;end

Readable version:

function f(s)
% Split the string on newlines and convert to a padded char array
d = char(split(s,'\n'));

% Get the initial indices of p
[y,x] = ind2sub(size(d),find(d=='p'));

% Loop forever
while 1
    % Implicitly display the dungeon
    d

    % Get the ASCII of the user input, minus 100 (saves a few bytes in
    % the comparisons)
    c=uint8(input('How do you want to move?','s'))-100;

    % Get the new y from the ASCII
    v = y+~c-(c==17);

    % Get the new x from the ASCII
    w = x+(c==14)-(c==8);

    % Clear the player from the dungeon if they are in it
    try
        d(y,x)=' ';
    end

    % Check if new position is a #, and revert to old position if so
    try
        if '#'==d(v,w)
            v=y;w=x;
        end
        d(v,w)='p';
    end
    % Update x and y
    y=v;
    x=w;

    % Clear the screen
    clc;
end

The try blocks are to prevent the function from crashing on out of bounds errors. I'm sure that two of them is overkill, but I can't golf it down any better than that.

It's worth noting that MATLAB will expand the array downwards and to the right, but the player will disappear when moving to an 'unexplored' area for the first time. For example, if you move outside the dungeon's current boundaries to the right by one space, you will disappear, but next turn MATLAB will expand the array to include the new column (or row, if you are moving downwards). '#'==d(y,x) saves a byte compared to d(y,x)=='#', since you don't need a space between if and '#'

\$\endgroup\$
1
  • \$\begingroup\$ Nice answer ! I hope this time not something very short wins, here the common languages should have a chance too, because the bigger the challenge, the better are java etc. :) \$\endgroup\$
    – Luatic
    Dec 18, 2016 at 11:43
1
\$\begingroup\$

Coffee-script: 580 Bytes

I've squeezed everything I could out of this particular algorithm and my tired brain. I need a holiday.

C=console
e='length'
N=null
f=(S)->
    x=y=X=Y=N
    q=(c,v)->
        X=[x+c,N][+(-1<x+c<w)]
        Y=[y+v,N][+(-1<y+v<h)]
        try L[y+v][x+c]!='#'catch
            1
    r=(s)->
        if (X||Y)
            return
        L[y]=((t=L[y].split '')[x]=s)
        L[y]=t.join ''
    while 1
        L=S.split '\n'
        [h,w]=[L[e],L[0][e]]
        x=[X,x][+(x?)]
        y=[Y,y][+(y?)]
        for k in[0..h*w-1]
            if L[k//h][k%w]=='p'
                x=k%w
                y=k//h
        C.clear()
        C.log S
        r(' ')
        switch prompt("How do you want to move?")
            when'l'
                q(-1,0)&&x--
            when'r'
                q(1,0)&&x++
            when'u'
                q(0,-1)&&y--
            when'd'
                q(0,1)&&y++
        r('p')
        S=L.join '\n'
\$\endgroup\$
1
  • \$\begingroup\$ nice solution, Lord Ratte \$\endgroup\$
    – Luatic
    Dec 22, 2016 at 12:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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