# Braille graphics

Cut a boolean matrix in 4x2 blocks and render them as Braille characters U+2800...U+28FF.

[[0,1,0,0,1,0],
[1,0,0,0,0,0],
[1,0,0,0,1,0],
[1,1,1,1,0,0]]

⣎⣀⠅


Pad with 0-s if dimensions are not multiples of 4 and 2.

[[0,1,0],
[1,0,0],
[1,1,1]]

⠮⠄


Usual golfing rules apply, flexible on input format. Output should either have the structure of a matrix or look like a matrix, e.g. list of strings; single string with newlines.

Hint: chr(0x2800 + 128*b7 + 64*b6 + 32*b5 + 16*b4 + 8*b3 + 4*b2 + 2*b1 + b0) is the dot pattern

b0 b3
b1 b4
b2 b5
b6 b7


Larger test:

[[0,0,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,0],
[0,1,1,1,1,1,1,0,0,0,0,0,1,1,1,0,0,0,1,1,1,1,1],
[0,1,1,0,0,1,1,1,0,0,0,1,1,1,1,0,0,1,1,0,0,0,1],
[1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,0,0,1,1,0,0,1,1],
[1,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,1,1,1,0,1,0],
[1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0],
[1,1,0,1,1,1,1,1,1,0,0,0,0,0,1,0,0,0,0,1,0,0,0],
[1,1,0,1,1,1,1,1,0,0,1,1,0,0,1,0,0,1,1,1,1,1,1],
[1,1,0,1,1,1,1,0,0,1,1,1,1,0,1,0,1,1,1,1,1,1,0],
[1,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,0,0,0,1,1,0,0],
[1,1,0,0,0,1,1,0,1,0,0,0,1,0,1,1,0,0,0,1,1,0,0],
[1,1,0,0,0,1,1,0,1,0,0,0,1,0,1,1,1,0,0,1,1,0,0],
[0,1,1,0,1,1,1,0,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0],
[0,1,1,1,1,1,0,0,1,1,1,1,1,0,0,1,1,0,1,1,1,0,0],
[0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,1,0,1,1,1,1,0]]

⣰⠟⠻⣦⠀⠠⠾⡇⢠⡞⢛⡆
⣿⢠⣬⣥⠄⣀⠀⡇⢈⣻⣈⡀
⣿⠘⢹⡇⡞⠙⡇⣧⡉⢹⡏⠀
⠘⠷⠟⠁⠳⠾⠃⠘⠇⠾⠧⠀

• Congrats on second challenge.
Aug 27 '17 at 10:49
• Better description: you have a 2D array of Boolean values whose rows represents the horizontal raster lines of a black-and-white (1 bit per pixel) frame buffer or graphics canvas. Encode all of the 4x2 rectangular blocks of this canvas into Unicode Braille characters. To handle fractional blocks at the edges, pad the canvas's width to a multiple of 2, and height to a multiple of four, with zeros (or otherwise ensure the equivalent output, treating the data as if it were so padded).
– Kaz
Aug 27 '17 at 17:44
• @Kaz I don't know, I personally really appreciate how concise this post is. IMO, not a lot of clarity would be added by writing any more (besides a few small clarifications like noting that the height should be a mult of 4 and the width of 2); your suggestion is harder for me to read than the current post. Sep 10 '17 at 19:43

# Jelly,  31  30 bytes

sz0Z
ç€2ZF€ç€8Zœ?@€€-36Ḅ+⁽$ṁỌY  Try it online! ### How? sz0Z - Link 1, split & right-pad with zeros: list, items; number, chunkSize s - split items into chunks of length chunkSize z0 - transpose with filler zero Z - transpose ç€2ZF€ç€8Zœ?@€€-36Ḅ+⁽$ṁỌY - Main link: list of lists of numbers (1s & 0s), M
ç€2                       - call the last link (1) as a dyad for €ach (left=M, right=2)
-  ((left,right) bits read left-right then top-bottom)
Z                      - transpose the resulting list of lists of lists
-  ((left, right) bits read top-bottom then left-right)
F€                    - flatten €ach
ç€8                 - call the last link (1) as a dyad for €ach (left=^, right=8)
Z                - transpose the resulting list of lists of lists
-  ("blocks" each and all read left-right top-to bottom)
-36        - literal -36
€€           - for €ach (block-wise row) for €ach (block)
œ?@             -   lexicographical permutation with reversed arguments
-    (get the permutation at index -36 (modular) in a list of
-     all permutations of the indexes sorted lexicographically.
-     That is the 8!-36 = 40284th - equivalently the values at
-     indexes [8,7,6,4,2,5,3,1])
Ḅ       - convert from binary list to integer (vectorises)
⁽$ṁ - base 250 literal = 10240 + - add Ọ - cast to character (vectorises) Y - join with newlines - implicit print  • Does Ḅ support "digits" greater than 1? Instead of adding 10240 (0x2800 - two bytes) to the result, you could prepend 40 (0x28 - one byte) to the vector of binary digits. I don't know much about Jelly, so I'm not sure if this would really work. – ngn Aug 27 '17 at 17:22 • Ḅ would indeed convert a leading digit of 40 as you suggest, but we'd need to prepend it to each such list (at a depth of 2) which, I think, would require more bytes of code (;@€€40Ḅ). Aug 27 '17 at 17:28 # Mathematica, 12611097 90 FromCharacterCode[10240+ListCorrelate[2^{{0,3},{1,4},{2,5},{6,7}},#,1,0][[;;;;4,;;;;2]]]&  This solution takes advantage of ListCorrelate to convolve a (reversed) kernel over a matrix, which is essentially a sliding matrix multiplication (or dot product). See a visual explanation here. Padding is done by using 0 as the fourth argument. In the following example, we expect the result to match the hint above: ListCorrelate[ 2^{{0, 3}, {1, 4}, {2, 5}, {6, 7}}, {{b0, b3}, {b1, b4}, {b2, b5}, {b6, b7}} ] (* returns {{b0 + 2 b1 + 4 b2 + 8 b3 + 16 b4 + 32 b5 + 64 b6 + 128 b7}} *)  Note that ListConvolve is not any shorter, since the third argument would be -1. Since this applies the kernel at every position of the matrix, we just need to extract the elements in every fourth row and second column. We use shorthands for Span and Part: [[;;;;4,;;;;2]]. Helpfully, FromCharacterCode can take a matrix of character codes and return a list of strings. This solution returns a list of strings, which is one of the allowed output formats. Simply prepend Column@ for the output to “look like a matrix.” You can play around with this in a free online Mathematica notebook. Go here, click Create a New Notebook, wait a moment, paste in this code, then press shift+enter. m1={{0,1,0,0,1,0},{1,0,0,0,0,0},{1,0,0,0,1,0},{1,1,1,1,0,0}}; m2={{0,1,0},{1,0,0},{1,1,1}}; m3={{0,0,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,0},{0,1,1,1,1,1,1,0,0,0,0,0,1,1,1,0,0,0,1,1,1,1,1},{0,1,1,0,0,1,1,1,0,0,0,1,1,1,1,0,0,1,1,0,0,0,1},{1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,0,0,1,1,0,0,1,1},{1,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,1,1,1,0,1,0},{1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0},{1,1,0,1,1,1,1,1,1,0,0,0,0,0,1,0,0,0,0,1,0,0,0},{1,1,0,1,1,1,1,1,0,0,1,1,0,0,1,0,0,1,1,1,1,1,1},{1,1,0,1,1,1,1,0,0,1,1,1,1,0,1,0,1,1,1,1,1,1,0},{1,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,0,0,0,1,1,0,0},{1,1,0,0,0,1,1,0,1,0,0,0,1,0,1,1,0,0,0,1,1,0,0},{1,1,0,0,0,1,1,0,1,0,0,0,1,0,1,1,1,0,0,1,1,0,0},{0,1,1,0,1,1,1,0,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},{0,1,1,1,1,1,0,0,1,1,1,1,1,0,0,1,1,0,1,1,1,0,0},{0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,1,0,1,1,1,1,0}}; MatrixToBraille := Column@ FromCharacterCode[10240+ListCorrelate[2^{{0,3},{1,4},{2,5},{6,7}},#,1,0][[;;;;4,;;;;2]]]& MatrixToBraille/@{m1,m2,m3}  Then you should see this: • (recently Wolfram cloud requires user sign in, but that code works on TIO as well; however I didn't figure out how to get it to print Unicode characters) Feb 15 '21 at 3:28 # JavaScript ES7 210207201200198194185 183 bytes a=>eval('for(y=0,c="";A=a[y];y+=4,c+=\n)for(x=0;A[x]+1;x+=2)c+=String.fromCharCode(10240+eval("for(N=k=0;k<6;k++)N+=(g=(X,Y=3)=>(a[Y+y]||0)[X+x]|0)(k>2,k%3)*2**k")|g(0)+g(1)*2<<6)')  4 bytes saved thanks to ngn 3 bytes saved thanks to Luke # How it works I'm going to split the code up into parts and speak about them separately: for(y=x=0, c=""; a[y]; x+=2) !((a[y] || [])[x]+1) && (y+=4,x=0,c+=\n)  This is where every variable gets declared. x and y is the position of the "cursor" (the upper left edge of the current braille character). The x coordinate increases by 2 every iteration, and it stops, when there's no row with the index y (a[x] returns undefined if it doesn't exist, which gets converted to false). There are multiple tricks in the second row. (a[y] || [])[x] ensures that looking up the value at the (x, y) position doesn't throw an error. The && is the usual and operator, and it only checks the right side of the expression, if the left was true. This can be translated to if (!((a[y] || [])[x] + 1)) y+=4,x=0,c+=\n  The next part: c+=String.fromCharCode(10240+eval("for(N=k=0;k<6;k++)N+=(g=(x,y)=>(a[y]||[])[x]||0)(~~(k/3)+x,k%3+y)*2**k,N")+g(x,y+3)*64+g(x+1,y+3)*128)  String.fromCharCode simply converts the passed number to a unicode character with the same character code. The expression in the parentheses calculates the index of the Braille character: for(N=k=0;k<6;k++)N+=(g=(x,y)=>(a[y]||[])[x]||0)(~~(k/3)+x,k%3+y)*2**k  Goes through the position in the 1 4 2 5 3 6  order, multiplies the values at those positions with 2i, where i is the index and adds them together. The g=(x,y)=>(a[y]||[])[x]||0  part declares a lambda function called g, which given an x and y coordinate returns either the value at the (x, y) position or 0 if the position lies outside the bounds of the array. +g(x,y+3)*64+g(x+1,y+3)*128  This part adds up the last two positions with the correct weights using the function defined a bit earlier. Last but not least, the a=>eval('...')  part has 2 functions. It defines an anonymous lambda and ensures, that the for loop doesn't cause any problems (a single line lambda such as this one can't contain a single for loop only, an evaluation circumvents this). • a few simple suggestions: ||0 -> |0; ~~(k/3) -> (k>2); *128 -> <<7 (replacing +-s with |-s) – ngn Aug 27 '17 at 17:09 • Why not submit the ES7 version as your primary solution? Aug 27 '17 at 17:10 • @Shaggy Not everyone can run ES7 yet, so it's a backup Aug 27 '17 at 17:12 • That's irrelevant 'round these parts ;) As long as there is one, single interpreter (browser) that can run your code properly, it's considered to be valid here. Aug 27 '17 at 17:15 • @ngn Thanks for the first two, but bit shifting has a lower precedence than basically anything, so that won't work Aug 27 '17 at 17:17 # Dyalog APL, 133122114112101100989594939088 86 bytes Assumes ⎕IO←0 {C⍴{⎕UCS 10240+2⊥(∊S⌷⍨⍵+⍳¨A)[⍎¨⍕76531420]}¨(,b)/,⍳⍴b←{0 0≡A|⍵}¨⍳⍴S←⍵↑⍨A×C←⌈(⍴⍵)÷A←4 2}  -8 9 12 bytes thanks to @Adám in chat -2 bytes thanks to @ngn Try it online! ## How (input is ⍵)? • A←4 2, store the vector 4 2 in variable A • (⍴⍵)÷, the dimensions of ⍵ divided by A • ⌈, ceiling • C←, stored in C • A×, multiplied by A • ⍵↑⍨, fit ⍵ to those dimensions • S←, stored in S • ⍳⍴, indexes of S • {0 0≡A|⍵}¨, 1 where the top left of a cell is, 0 everywhere else • (,b)/,⍳⍴b←, truthy indexes • {⎕UCS 10240+2⊥(∊S⌷⍨⍵+⍳¨A)[⍎¨⍕76531420]}¨, turn each element into braille • C⍴, reshape the dimensions to C • consider +/(2*0 3 1,A,4+⍳3)×something2⊥something[⍎¨⍕76524130] – ngn Aug 27 '17 at 17:30 • WOuld that still work now that I changed it to ⎕IO←0? Aug 27 '17 at 17:31 • Actually, it would only work in ⎕IO←0 :) – ngn Aug 27 '17 at 17:36 • I tried that, am I doing something wrong? tio.run/… Aug 27 '17 at 17:38 • Sorry, I forgot about this stupid thing (⎕IO) in APL. For ⎕IO←1, of course you'd have to add 1 to each digit of 76524130. – ngn Aug 27 '17 at 17:38 # JavaScript, 136 bytes a=>(b=a.map(x=>[]),a.map((l,i)=>l.map((c,j)=>b[i>>2][j>>1]|=c<<'01263457'[i%4+j*4%8])),b.map(l=>l.map(c=>String.fromCharCode(10240+c))))  Thanks to ngn, using bit shifts save 4 bytes. • you can use bit shifts like i/4|0 -> i>>2 – ngn Aug 28 '17 at 8:44 • c*2** is a bit shift, too :) – ngn Aug 28 '17 at 10:10 # Python 2 + drawille, 141125120 116 bytes Saved 16 bytes thanks to ngn and L3viathan Saved 5 bytes thanks to L3viathan Saved 4 bytes thanks to ngn from drawille import* def a(d,c=Canvas(),e=enumerate):[c.set(j,i)for i,x in e(d)for j,y in e(x)if y];print c.frame()  Try it online! tio does not have drawille installed so it does not work • Python and its batteries! :) Doesn't fail to surprise me. You can shrink this to under 120 bytes if you use enumerate() and a list comprehension. – ngn Aug 28 '17 at 6:52 • Save a couple of bytes by making the function a one-liner: def b(d,c=l.Canvas()):print([c.set(j,i)for i,x in enumerate(d)for j,y in enumerate(x)if y]and c).frame() Aug 28 '17 at 10:32 • Got it to 120 bytes Aug 28 '17 at 11:08 • you don't need the and c trick - the comprehension could be a statement on its own followed by ;print c.frame() – ngn Aug 28 '17 at 11:34 # APL (Dyalog), 57 54 bytes* -3 thanks to OP. Prompts for Boolean matrix. Prints character matrix. 1↓⎕UCS{2⊥40,⌽(,⍉3↑⍵),⊢⌿⍵}⌺(2 2⍴4 2)⊢0⍪⍣3⍪∘0⍣3⊢⎕,0  Try it online! ⎕,0 append a zero on right (ignored if even number of columns) ⊢ yield that (to separate 3 and ⎕) ⍪∘0⍣3 append zeros on bottom thrice (because ⌺ drops partial windows) 0⍪⍣3 stack zeros on top thrice (because ⌺ starts in the top left corner) ⊢ yield that (separates the parenthesis and the 0) {}⌺(2 2⍴4 2) on each 4-row 2-column window, with 4-row vertical and 2 row horizontal step: ⊢⌿⍵ last row (lit. vertical right reduction); [b6,b7] (), prepend: 3↑ take three rows; [[b0,b3],[b1,b4],[b2,b5]] ⍉ transpose; [[b0,b1,b2],[b3,b4,b5]] , ravel; [b0,b1,b2,b3,b4,b5] now we have [b0,b1,b2,b3,b4,b5,b6,b7] ⌽ reverse; [b7,b6,b5,b4,b3,b2,b1,b0] 40, prepend 40 (for 40×29 = 10240); [40,b7,b6,b5,b4,b3,b2,b1,b0] 2⊥ evaluate as base-2 (binary) ⎕UCS convert to character 1↓ drop the first row (all-zero because of ⌺'s padding) * In Classic, counting ⌺ as ⎕U233A. • There's an easy way to save a few bytes, see my comment under the Jelly solution. – ngn Sep 10 '17 at 11:36 • There must be a mistake - the TIO link doesn't match the code you posted here. – ngn Sep 10 '17 at 15:33 • it's the zero-padding code near the end: 0⍪⍣3⍪∘0⍣3⊢⎕,0 vs 0⍪∘0⍣3⊢⎕,0 – ngn Sep 10 '17 at 15:35 • @ngn Fixed, but I have a feeling that ⍪∘0⍣3 and ,0 are only needed due to a bug in ⌺, and the first one isn't needed for your test cases. – Adám Sep 10 '17 at 15:56 • My test cases aren't exhaustive - the solution should, of course, work for any valid input. You can shorten 0⍪⍣3⍪∘0⍣3⊢⍵,0 to 0(⊖⍪)⍣6⊢⍵,0. – ngn Sep 10 '17 at 16:19 # Python 3, 168165 161 bytes def f(m): while m: r,m,s=[*zip(*m)],m[4:],'' while r:s+=chr(10240+sum(q<<int(w)for(q,w)in zip((r[0]+(0,)*3)[:4]+(r+[()])[1],'01263457')));r=r[2:] print(s)  Try it online! • Nicely golfed! You can save three bytes with [*zip(*m[:4])] instead of calling list. – Lynn Aug 28 '17 at 11:42 # Haskell, 145 bytes (a!b)c=take b$c++repeat a
r([]:_)=[]
r l=['⠀'..]!!(sum.zipWith(*)[1,8,2,16,4,32,64,128]$l>>=0!2):r(drop 2<$>l)
b[]=[]
b s=r(([]!4)s):b(drop 4s)


Try it online!

# Python 3, 169 bytes

a=[]
y=0
for l in eval(input()):
y-=1;a+=y%4//3*[-~len(l)//2*[10240]];x=0
for v in l:a[-1][x//2]|=v<<(6429374>>y%4*6+x%2*3&7);x+=1
for l in a:print(*map(chr,l),sep='')


Try it online!

• You can rewrite if y%4<1:a+=-~len(l)//2*[10240], as a+=(y%4<1)*[-~len(l)//2*[10240]] and fit x=0;y+=1 on the same line. I think it saves a byte.
– ngn
Aug 28 '17 at 17:46
• @ngn saved a few more bytes from there on out, thank you!
– Lynn
Aug 28 '17 at 18:13

# Perl 5, 164 bytes

163 bytes of code + 1 flag -p

@a=eval}{for(;$r<@a;$r+=4){for($c=0;$c<@{$a[0]};$c+=2){$n="0b";map$n.=0|$a[$r+3][$c+$_],1,0;for$y(1,0){map$n.=0|$a[$r+$_][$c+$y],2,1,0}$\.=chr 0x2800+oct$n}$\.=\$/}


Try it online!

Takes each row comma separated on one line.

# APL (Dyalog), 53 bytes

4 2∘{⎕ucs 2⊥40⍪(⍎¨⍕76531420)∘.⊃,¨⍺∘↑¨↓∘⍵¨⍺∘×¨⍳⌈⍺÷⍨⍴⍵}


Try it online!