Join up the rooms

15

1

So, here's a map of, let's say, a dungeon...

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

Let's say that the hero is in Room A (at the top left) and their goal (a prince in distress?) is in Room B (to the bottom right). Our map does not allow the hero to progress to their goal.

We need to add a passageway...

##########
#    #####
#    #####
####.#####
####.#####
####.#####
####.#####
####    ##
####    ##
##########

There, much better!


Rules

  • A program or function which accepts a dungeon map (made up of hashes and spaces, with rows separated by new line characters).
  • It will output a map with dots added to denote passages in all spaces which are on a direct path between the space characters.
  • It will not change the line length, or number of lines.
  • Passages are all in a direct line from spaces to spaces.
    • Passages can not turn around corners
    • They will not be between spaces and the edge of the map.
  • Use any language.
  • Attempt to perform the conversion in the fewest bytes.
  • If no passageways can be drawn, return the map, unchanged.
  • The map should always have hashes around all edges (You do not need to handle spaces at the edge).
  • Input maps are always rectangular, each row should be the same width.

Test cases

####       ####
#  #   =>  #  #
#  #       #  #
####       ####

##########        ##########
#    #####        #    #####
#    #####        #    #####
##########        ####.#####
##########    =>  ####.#####
##########        ####.##### 
##########        ####.#####
####    ##        ####    ##
####    ##        ####    ##
##########        ##########

##########        ##########
#    #####        #    #####
#    #####        #    #####
##########        ##########
##########    =>  ##########
##########        ########## 
##########        ##########
######  ##        ######  ##
######  ##        ######  ##
##########        ##########

##########        ##########
#    #####        #    #####
#    #####        #    #####
##########        ####.#####
##########    =>  ####.#####
####   ###        ####   ### 
##########        ######.###
######  ##        ######  ##
######  ##        ######  ##
##########        ##########

##########        ##########
#    #####        #    #####
#    #####        #    #####
##########        ##..######
##########    =>  ##..######
##########        ##..###### 
##########        ##..######
## #######        ## .######
##  ######        ##  ######
##########        ##########

##########        ##########
#    #####        #    #####
#    #####        #    #####
##########        #.########
##########    =>  #.########
##########        #.######## 
#######  #        #.#####  #
#######  #        #.#####  #
# #####  #        # .....  #
##########        ##########

##########        ##########
#    #####        #    #####
#    #####        #    #####
##########        #.########
#####  ###    =>  #.###  ###
#####  ###        #.###  ### 
#######  #        #.#####  #
#######  #        #.#####  #
# #####  #        # .....  #
##########        ##########

##########        ##########
##       #        ##       #
##########        ##......##
##########        ##......##
##########    =>  ##......##
##########        ##......## 
##########        ##......##
##########        ##......##
#       ##        #       ##
##########        ##########

##########        ##########
####  ####        ####  ####
####### ##        ####..# ##
###### ###        ####.. ###
# ### ## #    =>  # ... .. #
# ## ### #        # .. ... # 
### ######        ### ..####
## #######        ## #..####
####  ####        ####  ####
##########        ##########

AJFaraday

Posted 2018-04-05T13:45:50.683

Reputation: 10 466

Can I use different characters than # and .? – user202729 – 2018-04-05T14:36:26.310

1@user202729 Nope. It was in the rules from the start, and there's already been one answer with it. Probably best to leave the reqs consistent. – AJFaraday – 2018-04-05T14:37:01.250

@user202729 The test case you suggested is similar to my penultimate case. I might add it when i next change the question, but it doesn't add much. – AJFaraday – 2018-04-05T14:57:06.797

... I just didn't scroll down. No problem. – user202729 – 2018-04-05T14:57:34.327

@l4m2 Same rules apply, wherever there's a straight line between rooms, it's a passage. So a u-shaped room would have the gap filled in with passages. – AJFaraday – 2018-04-05T14:58:55.250

"between rooms" may mean "should connect two different room", so i ask – l4m2 – 2018-04-05T15:00:21.813

@l4m2 Okay, that's the answer. It doesn't matter if it's a single room, if there's a straight line between parts of it. – AJFaraday – 2018-04-05T15:01:01.963

Are the inputs always squares? – recursive – 2018-04-05T15:20:21.217

@recursive Not necessarily (although all my test cases are). I think they should have to be rectangular. I'll edit the question. – AJFaraday – 2018-04-05T15:21:03.900

I think there's an issue with the second to last example. I think in the output there are extra # in the second column, specifically, (1,1) just shows up. Am I missing something? – Drise – 2018-04-05T21:19:07.180

Answers

7

Jelly, 17 bytes

ỴḲaLḊṖƊ¦”.KƊ€Z$⁺Y

Try it online!

Tricky -1 thanks to user202729.

Explanation:

ỴḲaLḊṖƊ¦”.KƊ€Z$⁺Y Arguments: S
Ỵ                 Split S on newlines
 ḲaLḊṖƊ¦”.KƊ€Z$   Monadic link
 ḲaLḊṖƊ¦”.KƊ€      Map over left argument
 ḲaLḊṖƊ¦”.KƊ        Monadic link
 Ḳ                   Split on spaces
  aLḊṖƊ¦”.           Dyadic link with right argument '.'
  aLḊṖƊ¦              Apply at specific indices
  a                    Logical AND (vectorizes)
   LḊṖƊ                Monadic link
   L                    Length
    Ḋ                   Range [2..n]
     Ṗ                  Remove last element
          K          Join with spaces
             Z     Zip
               ⁺  Previous link
                Y Join with newlines

Erik the Outgolfer

Posted 2018-04-05T13:45:50.683

Reputation: 38 134

2It always amazes me how quickly people can meet these challenges, and in so few characters. – AJFaraday – 2018-04-05T14:07:02.157

@AJFaraday Well, then you can be a part of it too. :) Just start with stack-based golfing languages (e.g. CJam, 05AB1E) and work your way from there. – Erik the Outgolfer – 2018-04-05T14:08:46.127

It does seem a long way beyond me, to be honest, but I love seeing how the process works. – AJFaraday – 2018-04-05T14:09:39.717

...we can continue the discussion over TNB if you want. ;) – Erik the Outgolfer – 2018-04-05T14:23:38.547

7Wait, is TNB short for 'tea and biscuits'? Or am I just being super-British right now? – AJFaraday – 2018-04-05T14:24:36.213

@AJFaraday Our chat room, The Nineteenth Byte.

– Erik the Outgolfer – 2018-04-05T14:25:24.183

5An explanation would be cool for this answer. – Tamás Sengel – 2018-04-05T15:53:57.580

Explanation – caird coinheringaahing – 2018-04-09T12:44:31.103

The explanation looks like some kind of ASCII art (a tree? or fire?), it's beautiful. :P – RedClover – 2018-04-12T18:48:48.260

5

Perl 5 -p0, 56 bytes

#!/usr/bin/perl -p0
/
/;$n="(.{@+})*";s%#%/ #*\G#+ |(?= )$n\G$n /s?".":$&%eg

Try it online!

Ton Hospel

Posted 2018-04-05T13:45:50.683

Reputation: 14 114

3

APL+WIN, 87 bytes

Prompts for character matrix:

n←(' '=m←⎕)⋄c←(∨⍀n)+⊖∨⍀⊖n⋄r←(∨\n)+⌽∨\⌽n⋄((,c>1)/,m)←'.'⋄((,r>1)/,m)←'.'⋄((,n)/,m)←' '⋄m

Graham

Posted 2018-04-05T13:45:50.683

Reputation: 3 184

3

Haskell, 209 165 162 bytes.

import Data.List
t=transpose
k=concat
j a=(foldr1 max<$>)<$>t<$>t[a,f<$>a,t$f<$>t a]
f b|(e:g:d@(h:_:_))<-group b=k[f$e++g,'.'<$h,drop(length h)$f$k d]|1>0=' '<$b

Try it online!

Not the most efficient way of doing it in Haskell I'm sure. It's got too many parentheses for my liking but I'm not sure how to remove any more.

aoemica

Posted 2018-04-05T13:45:50.683

Reputation: 793

2Welcome to the site! You can reduce some of the parentheses by using $ ((k(take 2 c)) becomes (k$take 2 c)). You can also use !!0 instead of head in some cases. – Post Rock Garf Hunter – 2018-04-07T17:48:48.773

Actually in the particular case of (k(take 2 c)) you can just remove the outer parentheses, they are not needed. But in the case of drop(length(head d)) you can still use the $, replacing it with drop(length$head d) (and even drop(length$d!!0)). – Post Rock Garf Hunter – 2018-04-07T17:53:01.703

In addition if you use k instead of ++ you can greatly reduce the last line. k[' '<$k(take 2 c),'.'<$d!!0,drop(length$d!!0)$f$k$d]. – Post Rock Garf Hunter – 2018-04-07T17:55:11.217

One last golf, the last line can be replaced with f b|(e:g:d@(h:_:_))<-group b=k[' '<$e++g,'.'<$h,drop(length h)$f$k d]|1>0=' '<$b, this uses a pattern match to do a lot of the heavy lifting that was being done before. – Post Rock Garf Hunter – 2018-04-07T18:10:18.317

1Thanks for the heavy duty golfing @user56656! Ungolfed I had f as 2 functions and just pasted them together without optimizing them as a whole. That's a good thing to keep in mind. – aoemica – 2018-04-07T20:24:54.530

I think you can also replace the use of ' '<$e++g with f$e++g, because it will fail the first match and move to the second. – Post Rock Garf Hunter – 2018-04-07T21:48:42.630

2

Python 2, 173 148 bytes

m=input().split('\n')
exec"m=zip(*[[c*(c!='#')or'#.'[(' 'in r[i:])*(' 'in r[:i])]for i,c in enumerate(r)]for r in m]);"*2
for r in m:print''.join(r)

Try it online!

ovs

Posted 2018-04-05T13:45:50.683

Reputation: 21 408

2

Retina 0.8.2, 95 bytes

+`(?<=(.)*)#(?=.*¶(?>(?<-1>.)*)[ .])
.
+`\.(?=(.)*)(?<![ .](?>(?<-1>.)*)¶.*)
#
 (\S+) 
 $.1$*. 

Try it online! Explanation:

+`(?<=(.)*)#(?=.*¶(?>(?<-1>.)*)[ .])
.

This looks for # signs that are above spaces or .s and turns them into dots until there are none left. The lookbehind finds the #'s column and then the lookahead skips to the next line and atomically to the same column below so that the space or . can only match if it's exactly below the #.

+`\.(?=(.)*)(?<![ .](?>(?<-1>.)*)¶.*)
#

This looks for .s that are not below spaces or .s and turns them back into #s until there are none left. The lookahead finds the .'s column and then the lookbehind skips to the previous line and atomically to the same column above in much the same way so that the space or . can only match if it's exactly above the #. A negative lookbehind is used so that this also works for .s in the top row.

 (\S+) 
 $.1$*. 

(Note trailing space on both lines) This simply looks for all runs of non-whitespace characters between spaces and ensures that they are all .s.

Neil

Posted 2018-04-05T13:45:50.683

Reputation: 95 035

1

Ruby, 104 bytes

->s{2.times{s=((0...s=~/\n/).map{|i|s.lines.map{|b|b[i]}*""}*"\n").gsub(/ [#.]+(?= )/){$&.tr(?#,?.)}};s}

Try it online!

Well, it's not great, but at least it's convoluted. I'm sure it can be improved.

Reinstate Monica -- notmaynard

Posted 2018-04-05T13:45:50.683

Reputation: 1 053

1

JavaScript (Node.js),205 193 190 186 181 175 172 bytes

r=>r.split`
`.map(x=>[...x]).map((R,y,r)=>R.map((c,x)=>{for(D=2;c<"#"&&D--;){for(;(T=(r[y+=D]||0)[x+=!D])>" ";);for(;r[y-=D][x-=!D]>c;)T?r[y][x]=".":0}})&&R.join``).join`
`

Try it online!

Commented

f=r=>r.split`
` ->                                     //getting as string with lines
.map(x=>[...x])                          //to 2d string array
  .map((R,y,r)=>                         //r - the new 2d string array
    R.map((c,x)=>{                       //
      for(D=2;c<"#"&&D--;)              //instead of using if joining c==" " with the loop,D=1/0
        {for(;                           //
         (T=(r[y+=D]||0)[x+=!D])>" ";);  //0[num] = undefined. checking for a path - consisting of # or .(or not consisting of space or undefined), we dont need temp (X,Y) because in the next loop we will return to our original position regardless of the correctness of the path
           for(;T&&r[y-=D][x-=!D]>c;)    //again instead of if(T) combine with loop. if T is not undefined it will be a space because the array can return .#(space). and we then go back to the source(x,y)
                                         //remeber that c==" "
             r[y][x]="."                 //and just putting . where weve been
     }})&&R.join``                       //instead of return r as string at the end , we know that we cant change a row at a smaller index(due to D-0/1) so we can return R.join`` already
    ).join`
`

DanielIndie

Posted 2018-04-05T13:45:50.683

Reputation: 1 220

1

Stax, 19 bytes

╛XA╟φkôα`æbπ┐w↨╙j≥☺

Run and debug it

recursive

Posted 2018-04-05T13:45:50.683

Reputation: 8 616

I'm afraid your debug link shows blank code. – AJFaraday – 2018-04-13T18:56:57.337

@AJFaraday: Which browser are you using? It's working for me on Chrome for Windows. – recursive – 2018-04-13T20:24:32.027