# Connect the pixels

Given a text like this:

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


Output the same text but by connecting the pixels with the characters ─│┌┐└┘├┤┬┴┼. If a pixel doesn't have any neighbours, don't change it.

So the output of the last text is:

│ ─┬── ┌─ │
└─ │  ┌┘  │
└──┘  ─┘

• You can take input as a boolean array.
• The input will always contain at least 1 pixel.
• You can count box-drawing chars as 1 byte.
• You can assume the input is padded with spaces.

## Test cases

## #
=>
── #

###
#
=>
─┬─
│

##### ##
# #  #
########
=>
─┬─┬─ ┌─
│ │  │
─┴─┴──┴─

 # #
#####
# #
=>
│ │
─┼─┼─
│ │

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

#####
#####
#####
#####
#####
=>
┌┬┬┬┐
├┼┼┼┤
├┼┼┼┤
├┼┼┼┤
└┴┴┴┘


Since this is , the shortest code wins.

• Must I use the hash character as a pixel? Can I receive input as a boolean array? Sep 19, 2016 at 21:17
• Can there be trailing space(s )or newline(s)? Sep 20, 2016 at 20:25
• btw: -|r7LJE3TW+ is a suitable 1-byte-char replacement for the block characters. Sep 21, 2016 at 22:11
• Can wee use a different character, e.g. *?
Jul 1, 2020 at 4:53

## JavaScript (ES6), 155121103 102 characters

let f =

s=>s.replace(/#/g,(c,p)=>'#│─┘─└─┴││┐┤┌├┬┼'[t=x=>s[p+x]==c,8*t(w=s.search
+1)+4*t(1)+2*t(-1)+t(-w)])

console.log(f(
'# #### ## #\n' +
'## #  ##  #\n' +
'   ####  ##'
));

Edit: saved 18 bytes with the help of ETHproductions
Edit: saved 1 byte by using the 1st parameter of replace() as '#'

### How it works

We iterate on all # characters found in the input string. For each of them, we test whether its neighbors are also # characters using the t() function:

t = x => s[p + x] == c  // where c = '#'


The parameter x of the t() function is the offset of the neighbor with respect to the current position p. We use -1/+1 to test left/right neighbors and -w/+w for top/bottom neighbors (where w is the width of a row, i.e. the position of the first line-break + 1).

Each neighbor is assigned a different weight (1, 2, 4 or 8) according to the following compass:

  1
2 + 4
8


Each weight combination leads to unique value in [ 0 .. 15 ]. For instance, if both the neighbor at the top and the neighbor on the right are set, the sum will be 1 + 4 = 5, which is translated into └ using this table:

00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
#  │  ─  ┘  ─  └  ─  ┴  │  │  ┐  ┤  ┌  ├  ┬  ┼


Therefore, '#│─┘─└─┴││┐┤┌├┬┼'[weight_sum] leads to the expected character.

• Ha, we had basically the same idea ;) Sep 19, 2016 at 22:32
• @ETHproductions - Pretty much so. ^^ Sep 19, 2016 at 22:48
• Really, really nice technique there. You've solidly out-golfed me :) Sep 20, 2016 at 14:55
• You can save 2 bytes like so: s=>(w=s[0].length+1,s=s.join\n).replace(/#/g,(_,p)=>'#│─┘─└─┴││┐┤┌├┬┼'[t=x=>s[p+x]>' ',t(-w)+2*t(-1)+4*t(1)+8*t(w)]) Sep 20, 2016 at 15:07
• And it's actually far shorter to switch back to a multiline string: s=>s.replace(/#/g,(_,p)=>'#│─┘─└─┴││┐┤┌├┬┼'[t=x=>s[p+x]>' ',t(-w)+2*t(-1)+4*t(1)+8*t(w)],w=s.indexOf\n+1) Sep 20, 2016 at 15:09

# J, 8272 66 bytes

(ucp' #───│┌┐┬│└┘┴│├┤┼'){~]+]*3 3((2#.1 7 3 5{,);._3)0,.~0,.0,~0,]


The input is a boolean table of 1's and 0's. The rules state that the box characters each count as one byte, not three, and that has been applied here.

## Usage

   f =: (ucp' #───│┌┐┬│└┘┴│├┤┼'){~]+]*3 3((2#.1 7 3 5{,);._3)0,.~0,.0,~0,]
m =: 1 0 1 1 1 1 0 1 1 0 1 , 1 1 0 1 0 0 1 1 0 0 1 ,: 0 0 0 1 1 1 1 0 0 1 1
m { ' #'
# #### ## #
## #  ##  #
####  ##
f m
│ ─┬── ┌─ │
└─ │  ┌┘  │
└──┘  ─┘
' #' {~ m =: 5 5 $1 f m ┌┬┬┬┐ ├┼┼┼┤ ├┼┼┼┤ ├┼┼┼┤ └┴┴┴┘ ' #' {~ m =: 5 9$ 1 0
# # # # #
# # # #
# # # # #
# # # #
# # # # #
f m
# # # # #
# # # #
# # # # #
# # # #
# # # # #


## Explanation

First the input is padded with 0's on all sides.

   ] m =: 1 0 1 1 1 1 0 1 1 0 1 , 1 1 0 1 0 0 1 1 0 0 1 ,: 0 0 0 1 1 1 1 0 0 1 1
1 0 1 1 1 1 0 1 1 0 1
1 1 0 1 0 0 1 1 0 0 1
0 0 0 1 1 1 1 0 0 1 1
(0,.~0,.0,~0,]) m
0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 1 1 1 1 0 1 1 0 1 0
0 1 1 0 1 0 0 1 1 0 0 1 0
0 0 0 0 1 1 1 1 0 0 1 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0


Then each subarray of size 3 is selected

   3 3 <;._3 (0,.~0,.0,~0,]) m
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│
│0 1 0│1 0 1│0 1 1│1 1 1│1 1 1│1 1 0│1 0 1│0 1 1│1 1 0│1 0 1│0 1 0│
│0 1 1│1 1 0│1 0 1│0 1 0│1 0 0│0 0 1│0 1 1│1 1 0│1 0 0│0 0 1│0 1 0│
├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤
│0 1 0│1 0 1│0 1 1│1 1 1│1 1 1│1 1 0│1 0 1│0 1 1│1 1 0│1 0 1│0 1 0│
│0 1 1│1 1 0│1 0 1│0 1 0│1 0 0│0 0 1│0 1 1│1 1 0│1 0 0│0 0 1│0 1 0│
│0 0 0│0 0 0│0 0 1│0 1 1│1 1 1│1 1 1│1 1 0│1 0 0│0 0 1│0 1 1│1 1 0│
├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤
│0 1 1│1 1 0│1 0 1│0 1 0│1 0 0│0 0 1│0 1 1│1 1 0│1 0 0│0 0 1│0 1 0│
│0 0 0│0 0 0│0 0 1│0 1 1│1 1 1│1 1 1│1 1 0│1 0 0│0 0 1│0 1 1│1 1 0│
│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│0 0 0│
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘


Then only 5 of the values in each subarray is considered

┌───┐
│xAx│
│CED│
│xBx│
└───┘


The values ABCD are selected by flattening each subarray and selecting at indices 1 7 3 5. Those values are multiplied by E which is at index 4. It is then converted from a list of binary digits to a decimal, and incremented by E. The x values are not needed.

   3 3 (4&{([+2#.*)1 7 3 5&{)@,;._3 (0,.~0,.0,~0,]) m
5 0 2  8 4 3  0  6 3 0  5
10 3 0 13 0 0  6 11 0 0 13
0 0 0 10 4 4 11  0 0 2 11


This is used as an index to select which character to draw according to the table below (reordered a bit for golfing). The last column matches the output value of each subarray to a box character.

 0  (space)  0
1  #        1
2  ┌        6
3  ┬        8
4  ┐        7
5  ├        14
6  ┼        16
7  ┤        15
8  └        10
9  ┴        12
10  ┘        11
11  │        5, 9, 13
12  ─        2, 3, 4


Also, in J, the string ' #───│┌┐┬│└┘┴│├┤┼' uses 8-bit characters making it have a length of 47 (for each byte) for the 17 characters needed. The command ucp converts it to 16-bit characters which allows it to be length 17.

# Jelly, 6052515049 48 bytes

ṖḤ0;+Ḋ×
“µ³Q~E!G⁸ṗṫ\’ḃ61+9471Ọ⁾# j
ZÑ€4×Z++Ñ€ị¢Y


Saved a byte thanks to @Dennis.

The input is a boolean array of 1's and 0's. Iterates over each column and each row converting the head and tail of each infix of size 3 from a pair of binary digits to a decimal, and multiplies that with the center of each infix. Then it sums it with itself to find the index into '#───│┌┐┬│└┘┴│├┤┼ '.

Try it online! (case 2) (case 3) (case 4)

## Explanation

This relies on the same idea as my answer in J but instead of processing on each 3x3 subarray, I process over each row and each column while still obtaining the same table of indices.

Over half of the bytes are spent generating the list of box characters '#───│┌┐┬│└┘┴│├┤┼ '. String literals start with “ in Jelly and have different meanings depending on their terminator. Here the terminator ’ means that the string will be parsed as the code points of each character according to the Jelly code page, and convert from a list of base 250 digits to a decimal.

“µ³Q~E!G⁸ṗṫ\’ => 10041542192416299030874093
(bijective base 61) => [1, 1, 1, 3, 13, 17, 45, 3, 21, 25, 53, 3, 29, 37, 61]
(add 9471 and convert to char) => '───│┌┐┬│└┘┴│├┤┼'


Then convert that decimal to a list of digits in bijective base 61 and increment each by 9471 to move it into the range of the box characters and convert each using Python's chr. Then prepend it with a character literal ”# and append a space ⁶.

ṖḤ0;+Ḋ×  Helper link - Input: 1d list A
Ṗ        Get all of A except the last value
Ḥ       Double each value in it
0;     Prepend a 0
Ḋ     All of A except the first value
×  Multiply elementwise by A

“µ³Q~E!G⁸ṗṫ\’ḃ61+9471Ọ⁾# j  Nilad. Represents '#───│┌┐┬│└┘┴│├┤┼ '
“µ³Q~E!G⁸ṗṫ\’               Get the code points of each char in the string and
convert from a list of base 250 digits to decimal
ḃ61            Convert that to a list of digits in bijective base 61
Ọ      Convert from ordinals to chars, gets '───│┌┐┬│└┘┴│├┤┼'
⁾#    A pair of chars ['#', ' ']
j  Join the pair using the box characters

ZÑ€4×Z++Ñ€ị¢Y  Input: 2d list M
Z              Transpose
Ñ€            Apply the helper link to each row of the transpose (each column of M)
4×          Multiply each by 4
Z         Transpose
Ñ€       The helper link applied to each row of M
ị¢   Use each result as an index to select into the nilad
Return and print implicitly


# Python 2.7, 318 315 bytes (270 267 chars)

I'm sure this can be golfed further (particularly I'd love to get rid of that annoying first-line comment) but here's my entry:

#encoding:utf-8
f=lambda t:(lambda l,s:'\n'.join(''.join((u'┼├┤│┬┌┐│┴└┘│───#'[(s==l[i][j-1])+2*(s==l[i][j+1])+4*(i<1 or s==l[i-1][j])+8*(i>len(l)-2 or s==l[i+1][j])],s)[s==l[i][j]]for j in range(len(l[i])-1))for i in range(len(l))))([l+' 'for l in t.split('\n')],' ')


Here's an explanation of how the whole thing works:

#encoding:utf-8 # Dammit, Python. This adds an extra 16 bytes!
f=lambda t:( # main lambda function
lambda l,s: # inner lambda so we can pass it "local constants" (see last line)
'\n'.join( # join each line
''.join( # join each char within the line
(u'┼├┤│┬┌┐│┴└┘│───#'[ # string of all possible characters, indexed by binary 0-15 based on adjacent chars
(s==l[i][j-1])+ # left
2*(s==l[i][j+1])+ # right
4*(i<1 or s==l[i-1][j])+ # up ('i<1' just yields zero in case this is the first line, so that we don't get index problems)
8*(i>len(l)-2 or s==l[i+1][j])], # down ('i>len(l)-2' is same as above)
s)[s==l[i][j]] # if original is space, choose space, else choose the previously chosen box-drawing char
for j in range(len(l[i])-1)) # do this process for each char (excluding last, which is a space)
for i in range(len(l))) # do this for each line
)([l+' ' for l in t.split('\n')],' ') # call the inner lambda with two parameters: first, the text split into lines; second, a space char (actually makes code shorter)


EDIT: Removed some spaces before for ... in ...

• Using Python 3 instead should solve your Unicode encoding problem, I think... Sep 20, 2016 at 0:49

# JavaScript (ES6), 150139133 131 chars

a=>a.map((q,y)=>q.replace(/#/g,(c,x)=>"#│─┘─└─┴││┐┤┌├┬┼"[g=(X,Y=0)=>(a[Y+y]||[])[X+x]==c,g(0,1)*8+g(1)*4+g(-1)*2+g(0,-1)])).join



Takes input as an array of strings, e.g. f(["###", " # "]).

### Test snippet

f=a=>a.map((q,y)=>q.replace(/#/g,(c,x)=>"#│─┘─└─┴││┐┤┌├┬┼"[g=(X,Y=0)=>(a[Y+y]||[])[X+x]==c,g(0,1)*8+g(1)*4+g(-1)*2+g(0,-1)])).join

<textarea id=I rows=6># #### ## #
## #  ##  #
####  ##</textarea>
<br>
<button onclick="O.innerHTML=f(I.value.split('\n')).replace(/\n/g,'<br>')">Run</button>
<pre id=O></pre>

# Python 3, 149 bytes

def f(s):S=' ';w=s.find('\n')+1;t=lambda i:(s+w*S)[i]>S;return[[c,'#│─┘─└─┴││┐┤┌├┬┼'[t(p-w)+2*t(p-1)+4*t(p+1)+8*t(p+w)]][c>S]for p,c in enumerate(s)]


Takes input like ##\n #\n and returns output like ['─', '┐', '\n', ' ', '│', '\n'].

# ALPACA, 414 + 2 = 416 bytes

neighbourhoodV(^ v < >);states" ";statep"#"toA when4inV p,toB when3inV p andvs,toC when3inV p and^s,toD when3inV p and>s,toE when3inV p and<s,toF when2inV p and>s andvs,toG when2inV p andvs and<s,toH when2inV p and<s and^s,toI when2inV p and^s and>s,toJ when^p orvp,toK when<p or>p;stateA"┼";stateB"┴";stateC"┬";stateD"┤";stateE"├";stateF"┘";stateG"└";stateH"┌";stateI"┐";stateJ"│";stateK"─".


Requires the -fI flags.

This solution uses a very large number of bytes, but it is unique in that it uses a cellular automaton. ALPACA is usually used as a metalanguage, but here I'm using it as a programming language.

Ungolfed version:

neighbourhood V (^ v < >);
state s " ";
state p "#" to A when 4 in V p,
to B when 3 in V p and v s,
to C when 3 in V p and ^ s,
to D when 3 in V p and > s,
to E when 3 in V p and < s,
to F when 2 in V p and > s and v s,
to G when 2 in V p and v s and < s,
to H when 2 in V p and < s and ^ s,
to I when 2 in V p and ^ s and > s,
to J when ^ p or v p,
to K when < p or > p;
state A "┼";
state B "┴";
state C "┬";
state D "┤";
state E "├";
state F "┘";
state G "└";
state H "┌";
state I "┐";
state J "│";
state K "─".


# PHP, 203 bytes

This can probably be done in a shorter way.

while($s=fgets(STDIN))$f[]=$s;foreach($f as$y=>&$s)for($x=strlen($s);$x--;)if($s[$x]>$b=" ")$s[$x]="#───│┘└┴│┐┌┬│┤├┼"[($s[$x-1]>$b)+2*($s[$x+1]>$b)+4*($f[$y-1][$x]>$b)+8*($f[$y+1][$x]>$b)];echo join($f);  reads input from STDIN. run with -r. # Perl, 89 88 bytes Includes +2 for -0p. The special characters are counted as 1 byte, but to make them actually display as single characters it's best to also add the -C option. Give input on STDIN with the lines space padded so they all have the same length: perl -C connect.pl # #### ## # ## # ## # #### ## ^D  connect.pl: #!/usr/bin/perl -0p / /;$n=".{@-}";s%#%substr"#───│└┘┴│┌┐┬│├┤┼",/\G##/+2*/#\G/+4*/#$n\G/s+8*/\G#$n#/s,1%eg


# R, 199 212 bytes

EDIT: It's now a function, rather than a code snippet.

The input is a matrix m of 1s and 0s. This is pretty ugly and hacky.

function(m){
v=strsplit(" #─│┘│┐│┤──└┴┌┬├┼","")[[1]]
d=dim(m)+1
n=array(0,dim=d+1)
n[2:d[1],2:d[2]]=m
for(i in 0:(d[1]-2)){for(j in 0:(d[2]-2))cat(v[1+(p<-n[2+i,2+j])*sum(2^(0:3)*n[1:3+i,1:3+j][1:4*2])+p]);cat("\n")}
}


A couple of tests:

> m = matrix(c(1, 1, 1, 0, 1, 0), nrow=2, byrow=TRUE)
> v=strsplit(" #─│┘│┐│┤──└┴┌┬├┼","")[[1]]
> d=dim(m)+1
> n=array(0,dim=d+1)
> n[2:d[1],2:d[2]]=m
> for(i in 0:(d[1]-2)){for(j in 0:(d[2]-2))cat(v[1+(p<-n[2+i,2+j])*sum(2^(0:3)*n[1:3+i,1:3+j][1:4*2])+p]);cat("\n")}
─┬─
│
> m = matrix(rep(1, 16), ncol=4)
> v=strsplit(" #─│┘│┐│┤──└┴┌┬├┼","")[[1]]
> d=dim(m)+1
> n=array(0,dim=d+1)
> n[2:d[1],2:d[2]]=m
> for(i in 0:(d[1]-2)){for(j in 0:(d[2]-2))cat(v[1+(p<-n[2+i,2+j])*sum(2^(0:3)*n[1:3+i,1:3+j][1:4*2])+p]);cat("\n")}
┌┬┬┐
├┼┼┤
├┼┼┤
└┴┴┘

• Submission must be either a full program or a function. Reading from a existing variable is not an allowed form of input. Sep 20, 2016 at 16:17
• How do you get some of the unicode characters to work nicely with R? x = "\U253C" works but x = "┼" does not.
– Vlo
Sep 20, 2016 at 20:16
• @TùxCräftîñg: Fixed now! Sep 20, 2016 at 20:41
• @Vlo utf-8 is my native OS encoding. x = "┼" works just fine for me. Sep 20, 2016 at 20:42

# MATL, 102 characters

I assign a neighbour a value (1, 2, 4 or 8); their sum will match a character in a string containing the drawing characters. I think there is still lots of room for improvements, but for a rough draft:

' #│││─┌└├─┐┘┤─┬┴┼' % String to be indexed
wt0J1+t4$( % Get input, and append zeros at end of matrix (solely to avoid % indexing a non-existent second row/column for small inputs) ttttt % Get a whole load of duplicates to work on 3LXHY) % Select rows 2:end from original matrix (one of the many dupes) w4LXIY) % Select rows 1:end-1 from the 'destination' summing matrix) +HY( % Add the neighbors below, store in 'destination' matrix tIY)b3LY)2*+IY( % +2* the neighbors above +-------------------------------+ tHZ)b4LZ)4*+HZ( % +4* the neighbors right |(note: H and I contain 1:end-1 | tIZ)b3LZ)8*+IZ( % +8* the neighbors left | and 2:end respectively) | HH3$)               % Select the original matrix +-------------------------------+
*                % Make sure only cells that originally had a # get replaced
1+)            % Add one because the original string is one-indexed. Index using ).


• Possibly replace the whole summing part with some kind of loop working on rotated copies of the matrix
• Ditch the entire thing and make something based on a single loop working through the matrix
• Use modular indexing to work on a flattened vector from the original array (?)

Try it Online! (may not have box drawing characters support)

# APL (Dyalog Extended), 9 bytes

'#'⌂draw⊢


Try it online!

A built-in that solves the challenge (except that it accepts the '*' symbol as the default, so '#' needs to be supplied as an explicit argument). ¯\_(⍨)_/¯

Documentation is here.

A non-built-in solution, because a built-in is boring:

# APL (Dyalog Extended), 43 bytes

' #│─┌─┐─┬││└├┘┤┴┼'⊇⍨⊢×0 0{1+⊥⊢/4 2⍴⍵}⌺3 3⊢


Try it online!

An anonymous function that takes the boolean matrix as its argument. Incidentally it wins over Jelly even without the built-in.

The approach is pretty similar to many other answers (base-2 conversion from the four neighbors and index into the target string).

One interesting thing to note is that the box-drawing characters are already part of the SBCS, so it is completely fine to use them in the code.

### How it works

' #│─┌─┐─┬││└├┘┤┴┼'⊇⍨⊢×0 0{1+⊥⊢/4 2⍴⍵}⌺3 3⊢
0 0{          }⌺3 3⊢  ⍝ Map over 3×3 submatrices, with zero padding...
4 2⍴⍵        ⍝ Reshape 3×3 to 4×2:
⍝ . A .   . A
⍝ B . C → . B
⍝ . D .   . C
⍝         . D
⊢/  ⍝ Take the last column
⊥    ⍝ Convert base 2 to integer
1+     ⍝ Offset 1 to distinguish between ' ' and '#'
⊢×  ⍝ Mask the places for blanks
' #│─┌─┐─┬││└├┘┤┴┼'⊇⍨  ⍝ Convert each value in the matrix to the char at that index


# Charcoal, 45 bytes

ＷＳ⊞υιＰ⪫υ⸿Ｆ⪫υ⸿≡ι#§”y#─│┐──┌┬│┘│┤└┴├┼”↨ＥＫＶ›κ ²ι


Try it online! Link is to verbose version of code. Takes input as a newline-terminated list of strings. Scored using 15 1-byte box drawing characters (normally 3 bytes each). Explanation:

ＷＳ⊞υι


Ｐ⪫υ⸿


Print it without moving the cursor.

Ｆ⪫υ⸿


Loop over the text again.

≡ι#


If the current character is a #...

§”y#─│┐──┌┬│┘│┤└┴├┼”↨ＥＫＶ›κ ²


... then look up the box drawing character based on the presence of neighbours.

ι


Otherwise just print the current character.