Code Golf Asked by TuxCrafting on October 27, 2021
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:
│ ─┬── ┌─ │
└─ │ ┌┘ │
└──┘ ─┘
## #
=>
── #
###
#
=>
─┬─
│
##### ##
# # #
########
=>
─┬─┬─ ┌─
│ │ │
─┴─┴──┴─
# #
#####
# #
=>
│ │
─┼─┼─
│ │
# # # # #
# # # #
# # # # #
# # # #
# # # # #
=>
# # # # #
# # # #
# # # # #
# # # #
# # # # #
#####
#####
#####
#####
#####
=>
┌┬┬┬┐
├┼┼┼┤
├┼┼┼┤
├┼┼┼┤
└┴┴┴┘
Since this is code-golf, the shortest code wins.
WS⊞υιP⪫υ⸿F⪫υ⸿≡ι#§”y#─│┐──┌┬│┘│┤└┴├┼”↨EKV›κ ²ι
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:
WS⊞υι
Read in the text.
P⪫υ⸿
Print it without moving the cursor.
F⪫υ⸿
Loop over the text again.
≡ι#
If the current character is a #
...
§”y#─│┐──┌┬│┘│┤└┴├┼”↨EKV›κ ²
... then look up the box drawing character based on the presence of neighbours.
ι
Otherwise just print the current character.
Answered by Neil on October 27, 2021
'#'⌂draw⊢
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:
' #│─┌─┐─┬││└├┘┤┴┼'⊇⍨⊢×0 0{1+⊥⊢/4 2⍴⍵}⌺3 3⊢
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.
' #│─┌─┐─┬││└├┘┤┴┼'⊇⍨⊢×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
Answered by Bubbler on October 27, 2021
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 "─".
Answered by DanTheMan on October 27, 2021
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*/#$nG/s+8*/G#$n#/s,1%eg
Answered by Ton Hospel on October 27, 2021
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 ).
Improvements to be made:
Try it Online! (may not have box drawing characters support)
Answered by Sanchises on October 27, 2021
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")}
┌┬┬┐
├┼┼┤
├┼┼┤
└┴┴┘
Answered by rturnbull on October 27, 2021
ṖḤ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)
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
+ Add elementwise with
Ḋ 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
+9471 Add 9400 to each
Ọ 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
+ Add elementwise with M
+ Add elementwise with
Ñ€ The helper link applied to each row of M
ị¢ Use each result as an index to select into the nilad
Y Join using newlines
Return and print implicitly
Answered by miles on October 27, 2021
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']
.
Answered by Lynn on October 27, 2021
(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.
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
# # # # #
# # # #
# # # # #
# # # #
# # # # #
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.
Answered by miles on October 27, 2021
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 ...
Answered by Hactar on October 27, 2021
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
.
Answered by Titus on October 27, 2021
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(["###", " # "])
.
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>
Answered by ETHproductions on October 27, 2021
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 '#'
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.
Answered by Arnauld on October 27, 2021
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP