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



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



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:


  • \$\begingroup\$ Congrats on second challenge. \$\endgroup\$
    – Adám
    Aug 27, 2017 at 10:49
  • 5
    \$\begingroup\$ 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). \$\endgroup\$
    – Kaz
    Aug 27, 2017 at 17:44
  • 4
    \$\begingroup\$ @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. \$\endgroup\$
    – Quelklef
    Sep 10, 2017 at 19:43

12 Answers 12


Jelly,  31  30 bytes


Try it online!


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
  • \$\begingroup\$ 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. \$\endgroup\$
    – ngn
    Aug 27, 2017 at 17:22
  • \$\begingroup\$ 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Ḅ). \$\endgroup\$ Aug 27, 2017 at 17:28

Mathematica, 126 110 97 90


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:

  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.


MatrixToBraille := Column@


Then you should see this:

  • \$\begingroup\$ (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) \$\endgroup\$
    Feb 15, 2021 at 3:28

JavaScript ES7 210 207 201 200 198 194 185 183 bytes


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)) 

The next part:


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:


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


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.


This part adds up the last two positions with the correct weights using the function defined a bit earlier.

Last but not least, the


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).

  • \$\begingroup\$ a few simple suggestions: ||0 -> |0; ~~(k/3) -> (k>2); *128 -> <<7 (replacing +-s with |-s) \$\endgroup\$
    – ngn
    Aug 27, 2017 at 17:09
  • \$\begingroup\$ Why not submit the ES7 version as your primary solution? \$\endgroup\$
    – Shaggy
    Aug 27, 2017 at 17:10
  • \$\begingroup\$ @Shaggy Not everyone can run ES7 yet, so it's a backup \$\endgroup\$
    – Bálint
    Aug 27, 2017 at 17:12
  • \$\begingroup\$ 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. \$\endgroup\$
    – Shaggy
    Aug 27, 2017 at 17:15
  • \$\begingroup\$ @ngn Thanks for the first two, but bit shifting has a lower precedence than basically anything, so that won't work \$\endgroup\$
    – Bálint
    Aug 27, 2017 at 17:17

Dyalog APL, 133 122 114 112 101 100 98 95 94 93 90 88 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
  • , 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
  • \$\begingroup\$ consider +/(2*0 3 1,A,4+⍳3)×something2⊥something[⍎¨⍕76524130] \$\endgroup\$
    – ngn
    Aug 27, 2017 at 17:30
  • \$\begingroup\$ WOuld that still work now that I changed it to ⎕IO←0? \$\endgroup\$
    – Adalynn
    Aug 27, 2017 at 17:31
  • \$\begingroup\$ Actually, it would only work in ⎕IO←0 :) \$\endgroup\$
    – ngn
    Aug 27, 2017 at 17:36
  • \$\begingroup\$ I tried that, am I doing something wrong? tio.run/… \$\endgroup\$
    – Adalynn
    Aug 27, 2017 at 17:38
  • \$\begingroup\$ 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. \$\endgroup\$
    – ngn
    Aug 27, 2017 at 17:38

JavaScript, 136 bytes


Thanks to ngn, using bit shifts save 4 bytes.

  • \$\begingroup\$ you can use bit shifts like i/4|0 -> i>>2 \$\endgroup\$
    – ngn
    Aug 28, 2017 at 8:44
  • \$\begingroup\$ c*2** is a bit shift, too :) \$\endgroup\$
    – ngn
    Aug 28, 2017 at 10:10

Python 2 + drawille, 141 125 120 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

  • \$\begingroup\$ 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. \$\endgroup\$
    – ngn
    Aug 28, 2017 at 6:52
  • \$\begingroup\$ 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() \$\endgroup\$
    – L3viathan
    Aug 28, 2017 at 10:32
  • \$\begingroup\$ Got it to 120 bytes \$\endgroup\$
    – L3viathan
    Aug 28, 2017 at 11:08
  • \$\begingroup\$ you don't need the and c trick - the comprehension could be a statement on its own followed by ;print c.frame() \$\endgroup\$
    – ngn
    Aug 28, 2017 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.

  • \$\begingroup\$ There's an easy way to save a few bytes, see my comment under the Jelly solution. \$\endgroup\$
    – ngn
    Sep 10, 2017 at 11:36
  • \$\begingroup\$ There must be a mistake - the TIO link doesn't match the code you posted here. \$\endgroup\$
    – ngn
    Sep 10, 2017 at 15:33
  • \$\begingroup\$ it's the zero-padding code near the end: 0⍪⍣3⍪∘0⍣3⊢⎕,0 vs 0⍪∘0⍣3⊢⎕,0 \$\endgroup\$
    – ngn
    Sep 10, 2017 at 15:35
  • \$\begingroup\$ @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. \$\endgroup\$
    – Adám
    Sep 10, 2017 at 15:56
  • \$\begingroup\$ 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. \$\endgroup\$
    – ngn
    Sep 10, 2017 at 16:19

Haskell, 145 bytes

(a!b)c=take b$c++repeat a
r l=['⠀'..]!!(sum.zipWith(*)[1,8,2,16,4,32,64,128]$l>>=0!2):r(drop 2<$>l)
b s=r(([]!4)s):b(drop 4s)

Try it online!


Python 3, 168 165 161 bytes

def f(m):
 while m:
  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:]

Try it online!

  • \$\begingroup\$ Nicely golfed! You can save three bytes with [*zip(*m[:4])] instead of calling list. \$\endgroup\$
    – Lynn
    Aug 28, 2017 at 11:42

Python 3, 169 bytes

for l in eval(input()):
 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!

  • \$\begingroup\$ 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. \$\endgroup\$
    – ngn
    Aug 28, 2017 at 17:46
  • \$\begingroup\$ @ngn saved a few more bytes from there on out, thank you! \$\endgroup\$
    – Lynn
    Aug 28, 2017 at 18:13

APL (Dyalog), 53 bytes

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

Try it online!


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.


Your Answer

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

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