46
\$\begingroup\$

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

⣰⠟⠻⣦⠀⠠⠾⡇⢠⡞⢛⡆
⣿⢠⣬⣥⠄⣀⠀⡇⢈⣻⣈⡀
⣿⠘⢹⡇⡞⠙⡇⣧⡉⢹⡏⠀
⠘⠷⠟⠁⠳⠾⠃⠘⠇⠾⠧⠀
\$\endgroup\$
  • \$\begingroup\$ Congrats on second challenge. \$\endgroup\$ – Adám Aug 27 '17 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 '17 at 17:44
  • 3
    \$\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 '17 at 19:43

12 Answers 12

10
\$\begingroup\$

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
\$\endgroup\$
  • \$\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 '17 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\$ – Jonathan Allan Aug 27 '17 at 17:28
6
\$\begingroup\$

JavaScript ES7 210 207 201 200 198 194 185 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).

\$\endgroup\$
  • \$\begingroup\$ a few simple suggestions: ||0 -> |0; ~~(k/3) -> (k>2); *128 -> <<7 (replacing +-s with |-s) \$\endgroup\$ – ngn Aug 27 '17 at 17:09
  • \$\begingroup\$ Why not submit the ES7 version as your primary solution? \$\endgroup\$ – Shaggy Aug 27 '17 at 17:10
  • \$\begingroup\$ @Shaggy Not everyone can run ES7 yet, so it's a backup \$\endgroup\$ – Bálint Aug 27 '17 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 '17 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 '17 at 17:17
6
\$\begingroup\$

Mathematica, 126 110 97 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:

\$\endgroup\$
5
\$\begingroup\$

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
\$\endgroup\$
  • \$\begingroup\$ consider +/(2*0 3 1,A,4+⍳3)×something2⊥something[⍎¨⍕76524130] \$\endgroup\$ – ngn Aug 27 '17 at 17:30
  • \$\begingroup\$ WOuld that still work now that I changed it to ⎕IO←0? \$\endgroup\$ – Zacharý Aug 27 '17 at 17:31
  • \$\begingroup\$ Actually, it would only work in ⎕IO←0 :) \$\endgroup\$ – ngn Aug 27 '17 at 17:36
  • \$\begingroup\$ I tried that, am I doing something wrong? tio.run/… \$\endgroup\$ – Zacharý Aug 27 '17 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 '17 at 17:38
4
\$\begingroup\$

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.

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

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

\$\endgroup\$
  • \$\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 '17 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 '17 at 10:32
  • \$\begingroup\$ Got it to 120 bytes \$\endgroup\$ – L3viathan Aug 28 '17 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 '17 at 11:34
3
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ There's an easy way to save a few bytes, see my comment under the Jelly solution. \$\endgroup\$ – ngn Sep 10 '17 at 11:36
  • \$\begingroup\$ There must be a mistake - the TIO link doesn't match the code you posted here. \$\endgroup\$ – ngn Sep 10 '17 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 '17 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 '17 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 '17 at 16:19
2
\$\begingroup\$

Python 3, 168 165 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!

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

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!

\$\endgroup\$
1
\$\begingroup\$

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!

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

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.

\$\endgroup\$
1
\$\begingroup\$

APL (Dyalog), 53 bytes

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

Try it online!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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