# Decode Faux Braille

⢣⠃⢎⠆⣇⡇⡯⡂⠈⡏⢰⢵⢐⡭⢸⠪⡀⢸⢐⡭⠀⢹⠁⢎⠆⢸⣱⢸⡃⢎⠰⡱⢸⣱⢸⡃⠈⡏⢸⡃⡱⡁⢹⠁⢸⡀⡇⡗⢅⢸⡃⠈⡏⢸⢼⢸⢐⡭⠀

⣇⢸⡃⢹⠁⢹⠁⣟⢸⢕⢐⡭⠀⡮⡆⡯⡂⣟⠀⡯⠰⡱⢸⣸⢸⢕⠀⣏⡆⢎⠆⢹⠁⣪⠅⢸⢼⢸⠰⣩⢸⢼⠀⡮⡆⡗⢼⢸⣱⠀⢎⠆⡯⠀⢇⠇⡮⡆⡯⡂⡇⡮⡆⣟⡆⣇⢸⡃⠸⡰⡸⢸⢸⣱⠈⡏⢸⢼⠀

⢎⠆⡗⢼⢸⡃⢸⡃⡗⠔⡇⡯⠂⢹⠁⢣⠃⠸⡸⢸⡃⡯⡂⢹⠁⡇⢎⢰⢵⢸⡀⢸⡀⡇⡗⢼⢸⡃⢐⡭⢸⡃⡯⠂⡮⡆⡯⡂⡮⡆⢹⠁⣟⢐⡭⠀⢎⢸⢼⢰⢵⢸⢕⢰⢵⠰⡁⢹⠁⣟⢸⢕⢐⡭⠀

⡮⡆⢐⡭⢸⠕⢰⢵⠰⡁⣟⠀⡇⣪⠅⢈⣝⢸⡃⡯⡂⢎⠆⠸⡰⡸⢸⢸⣱⠈⡏⢸⢼⠀

⣪⠅⢎⠆⢸⠈⡏⠀⣇⠰⡱⠰⡱⢸⠪⡀⣪⠅⢸⡀⡇⡗⢅⢸⡃⠸⡰⡸⠰⡱⢸⢕⢸⣱⢐⡭⠀⡮⡆⡯⡂⣟⠀⣪⠅⣟⢸⠕⢰⢵⢸⢕⢰⢵⠈⡏⢸⡃⣏⡆⢸⣳⠘⡜⠀⢹⠁⢇⢆⠇⢎⠆⢸⡀⡇⡗⢼⢸⡃⣪⠅

⡇⡗⢼⢸⠕⢸⣸⠈⡏⠀⡇⣪⠅⢰⢵⠀⣪⠅⢹⠁⡯⡂⡇⡗⢼⠰⣩⠀⢎⠰⡱⢸⠢⡇⢹⠁⡮⡆⡇⡗⢼⢸⢸⠢⡇⢎⡅⢸⠅⡮⡆⣇⡇⡱⡁⢸⣳⢸⢕⢰⢵⢸⢸⡀⣇⢸⡃⠰⡱⢸⠅

⢎⠆⡗⢼⢸⡀⢣⠃⢸⡃⡗⢼⠰⣩⢸⡀⡇⣪⠅⡧⡇⢸⣸⢸⠕⢸⠕⢸⡃⡯⡂⢎⢰⢵⢐⡭⢸⡃⢸⡀⣟⠈⡏⠈⡏⢸⡃⡯⡂⣪⠅⢰⢵⢸⠢⡇⣏⡆⢐⡭⢸⠕⢰⢵⠰⡁⣟⢐⡭⠀

⡮⡆⣟⡆⢎⢸⣱⢸⡃⡯⠰⣩⢸⢼⢸⢀⠇⡗⢅⢸⡀⡗⠔⡇⡗⢼⠰⡱⢸⠕⠰⣩⡆⡯⡂⣪⠅⢹⠁⣇⡇⢇⠇⢇⢆⠇⡱⡁⢣⠃⣩⡃

⢎⠆⣇⡇⢹⠁⡯⠂⣇⡇⢹⠁⢸⠢⢺⢰⢵⠘⡜⠀⣟⡆⣟⠀⣇⡇⡯⠂⡯⠂⣟⢸⢕⠀⢎⠆⡯⡂⢸⡀⢎⠆⢇⢆⠇⣟⢸⢕⠰⡁⡮⡆⣪⠅⣟⠀

⣪⠅⡧⡇⢎⠆⡯⡂⢹⠁⣟⢐⡭⠈⡏⠀⢇⢆⠇⡇⡗⢼⢐⡭⠀

⡗⢼⠰⡱⠀⣇⠰⡱⠰⡱⢸⠕⢸⢼⠰⡱⢸⡀⣟⢐⡭⠀


ASCII version of the above

⡯⡂⣟⢸⡀⡮⡆⢹⠁⣟⢸⣱⠀

# About Braille characters

A Braille character packs a 4 by 2 rectangle of dots, which can be viewed as a Boolean matrix.

The concatenation of all such matrices is a 4 by 2*n boolean matrix, where n is the length of the input string.

You should look for vertical lines without any dots in them, and use those as separators to split the big matrix into smaller matrices for each character.

Then, look for patterns to convert them to letters of the English alphabet or spaces. Note that after removing the separators (vertical empty lines), a space is a 4 by 0 matrix.

Below is a description of the alphabet in ASCII:

A   | B   | C  | D   | E  | F  | G   | H   | I | J  | K    | L  | M     | N    | O   | P   | Q    | R   | S   | T   | U   | V   | W     | X   | Y   | Z
----+-----+----+-----+----+----+-----+-----+---+----+------+----+-------+------+-----+-----+------+-----+-----+-----+-----+-----+-------+-----+-----+----
.#. | ##. | .# | ##. | ## | ## | .## | #.# | # | .# | #.#. | #. | #...# | #..# | .#. | ##. | .##. | ##. | .## | ### | #.# | #.# | #...# | #.# | #.# | ###
#.# | ### | #. | #.# | ## | #. | #.. | #.# | # | .# | ##.. | #. | ##.## | ##.# | #.# | #.# | #..# | #.# | #.. | .#. | #.# | #.# | #.#.# | .#. | #.# | ..#
### | #.# | #. | #.# | #. | ## | #.# | ### | # | .# | #.#. | #. | #.#.# | #.## | #.# | ##. | #.## | ##. | .## | .#. | #.# | #.# | #.#.# | .#. | .#. | .#.
#.# | ### | .# | ### | ## | #. | .## | #.# | # | #. | #..# | ## | #...# | #..# | .#. | #.. | .### | #.# | ##. | .#. | ### | .#. | .#.#. | #.# | .#. | ###


# Specification

• The input is a sequence of Unicode code points in the range U+2800..U+28FF represented as the usual string type in your language (e.g. char array, char pointer) in any popular encoding supported (UTF-8, UCS-2, etc).

• Trailing spaces in the output are fine.

EDIT: apologies to those whose browsers misrender the dots, it's supposed to look like this (image):

• your task is to decode text like this / letters are four dots high and of variable width / one empty vertical line separates characters / a space is zero width / so it looks like words are separated by two lines / input is a string containing faux braille of / only english uppercase letters and spaces / abcdefghijklmnopqrstuvwxyz / output may be upper or lowercase / shortest wins / no loopholes / related
– ngn
Nov 26, 2017 at 9:41
• Braille patterns Nov 26, 2017 at 10:26

# Python 3, 181179171167161 159 bytes

Input by UTF-16 little-endian bytes without BOM. First decompose into columns using bit shifts, split by empty column, then hash them into a lookup table.

-2 bytes thanks to ngn.
-5 bytes thanks to Mr. Xcoder.

lambda h,j=''.join:j(' ZAQV;JWP;MBOS;YRKCGXDF;ILHUENT'[int('0'+i,27)%544%135%32]for i in j(chr(64|i&7|i>>3&8)+chr(64|i>>3&7|i>>4&8)for i in h[::2]).split('@'))


Try it online!

• python won't complain if you remove the space between 39 and if; it's even shorter if you replace if-else with the and-or trick
– ngn
Nov 26, 2017 at 13:15
• 175 bytes by replacing i and int(i,27)%15472%39or 0 with int(i or'0')%15472%39 --- Try it online! Nov 26, 2017 at 13:29
• And 174 bytes by assigning ''.join to a variable --- Try it online! Nov 26, 2017 at 13:30

# JavaScript (ES6),  148 146 143  142 bytes

Saved 1 byte thanks to @ngn

s=>[...s].map(c=>g((k=c.charCodeAt()/8)&8|k*8&7)&g(k&7|k/2&8),o=x='',g=n=>x=n?x*27+n:!(o+=' DZQGYWXNHJ.CSTIO.AFB.LPVE..KUMR'[x%854%89%35]))&&o


Try it online!

• g((k=c.charCodeAt())&7|k/8&8)&g(k/8&7|k/16&8) -> g((k=c.charCodeAt()/8)&8|k*8&7)&g(k&7|k/2&8)
– ngn
Nov 26, 2017 at 17:15
• @ngn Thanks :) Merged with another pending optimization. Nov 26, 2017 at 17:20
• May I ask, how did you come up with the brilliant x%854%89%35? Did you try many different random moduli?
– ngn
Nov 26, 2017 at 17:20
• @ngn I've tried m0 < 1000, m1 < m0, m2 < m1 (actually with some other optimizations, but that's the idea). And for the factor by which x is multiplied: [4,6,8,9,10,11,12] and [15...31]. Currently trying some other approaches. Nov 26, 2017 at 17:26

# Python 3, 305302301286251198 182 bytes

def f(s,A=''):
for c in s:l=bin(ord(c))[-8:];A+='7'+l[5:]+l[1]+'7'+l[2:5]+l[0]
print(''.join('K.L.SXC PRU.NYEOGZVJIW..HFBTAQDM'[int('7'+c,22)%141%109%35]for c in A.split('70000')))


Try it online!

• 302 (-3 bytes) Nov 26, 2017 at 13:34
• @Mr.Xcoder Thanks :) Nov 26, 2017 at 13:38