Reading the text of the millitext font

There is a font here that fits each character into a single, 1x5 pixel block. It does this (assuming you're using an LCD screen) by using the RGB channels of each pixel to expand the one pixel into three subcolumns, one for each channel. Your task is to take in a string of text encoded in this font and 'decode' it.

Millitext Alphabet


I've abbreviated each color to a one character symbol (R=red, G=green, B=blue, C=cyan, Y=yellow, M=magenta, W=white).

Input Format

The input format for this is pretty open. You can have the input be an array containing each column, an array containing each row, a char[][], or anything like that. You can also choose to use the full words "red", "green", "blue", with uppercase/lowercase of your choice (but it must be consistent for each word! You cannot use "RED" and also do "green" or "Blue").

If your language happens to support it, you can also have input be colors (however that might work, I don't know off-hand).

You can assume that the input will ONLY contain encoded characters in the alphabet above (in particular, there will be no spaces or punctuation in your output).

Output Format

You can either output a string or some sort of character array. You can chose whether the letters are uppercase or lowercase, but they must all have the same case.




This is , so shortest answer wins!

Test set

  • 15
    \$\begingroup\$ I feel like you either hardcode all letters or use a Mathematica builtin here. \$\endgroup\$ Commented Jun 10, 2019 at 12:59
  • 7
    \$\begingroup\$ Nice first challenge, BTW! \$\endgroup\$
    – Arnauld
    Commented Jun 10, 2019 at 13:29
  • 7
    \$\begingroup\$ Here is the fixed font (several other characters are wrong). \$\endgroup\$
    – Arnauld
    Commented Jun 10, 2019 at 23:12
  • 7
    \$\begingroup\$ I don't know if you wanted your test set to include all letters from the English alphabet or not, but if son that's called a pangram and "THEQUICKBROWNFOXJUMPEDOVERTHELAZYDOG" isn't one as its missing an "S", if you wanted it to be it should be "THEQUICKBROWNFOXJUMPESOVERTHELAZYDOG" \$\endgroup\$
    – MindSwipe
    Commented Jun 11, 2019 at 7:20
  • 6
    \$\begingroup\$ @JonofAllTrades JUMPS is a possibility.And you can lose two characters by changing one of the THEs for A. \$\endgroup\$ Commented Jun 11, 2019 at 20:02

10 Answers 10


JavaScript (ES6),  103 100 93 92  90 bytes

Saved 9 bytes thanks to @ShieruAsakoto

Takes input as an array of columns. Returns an array of characters.


Try it online!

  • 1
    \$\begingroup\$ @ShieruAsakoto Thanks! The multiplication was not a good idea. I saved 1 more byte with 3 mod's. \$\endgroup\$
    – Arnauld
    Commented Jun 10, 2019 at 15:57
  • 1
    \$\begingroup\$ Those are some big modulos over there... maybe you can improve them more so the -s disappear! :D \$\endgroup\$ Commented Jun 10, 2019 at 16:37
  • \$\begingroup\$ After a whole night of brute-force I got a 90 with 4 mods: a=>a.map(s=>"H-L-D--VGQ87MR6TZ-KJ9WC05BUXF1YI2EON3S-A-P4"[parseInt(s,35)%1161%219%152%43]). \$\endgroup\$ Commented Jun 10, 2019 at 23:44
  • \$\begingroup\$ @ShieruAsakoto Unfortunately, the font described in the challenge is wrong. Waiting for a possible update from the OP. \$\endgroup\$
    – Arnauld
    Commented Jun 10, 2019 at 23:47
  • \$\begingroup\$ @Arnauld For the fixed one my progress now is a 93: a=>a.map(s=>"UIR-L68N--W-X7B-FH-D-EZ--902-S4M5GJCQT3PKV-A1-YO"[parseInt(s,35)%464%107%99%52]) \$\endgroup\$ Commented Jun 11, 2019 at 4:52

Jelly, 50 bytes


Try it online!

A monadic link accepting the input as a list of columns and outputting a Jelly string of the translation. Full explanation to follow, but relies on the fact that each possible set of 5 letters is unique when converted to code points, converted back from base-256 to decimal and then mod 211.

Alternative using Arnauld’s fixed font (49 bytes and using same principle.)


O                   | Convert to code points
 ḅ⁹                 | Convert from base 256 to decimal
   %211             | Mod 211
       “Ẏ...Ṿ‘iⱮ    | Find indices in [209,80,92,55,21,162,24,118,115,42,193,137,85,102,82,77,74,105,189,86,146,41,46,90,10,144,34,125,126,173,121,72,133,199,134,186]
                ịØB | Index into 01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ

dzaima/APL, 80 79 73 72 71 bytes

' P  FL6BDEZQA SY574H TVOK J 08  M  U IC92XW 3G1RN'⊇⍨52|8965|2411⊥¨⎕ucs

Try it online!

  • 1
    \$\begingroup\$ what special features does your APL have? \$\endgroup\$
    – Jonah
    Commented Jun 10, 2019 at 14:33
  • 2
    \$\begingroup\$ @Jonah Here the only used thing is (similar to {⍵[⍺]}), other than that, these two files contain info about it \$\endgroup\$
    – dzaima
    Commented Jun 10, 2019 at 14:35

05AB1E, 45 44 bytes


Try it online!

Takes input as array of columns, and outputs an array of characters.


40ö                       # convert each column from base 40
   98%                    # modulo 98
      •...•2ô             # compressed array: [20, 32, 82, 30, 27, 28, 76, 89, 46, 96, 36, 4, 18, 12, 80, 75, 50, 86, 42, 2, 52, 92, 48, 0, 84, 1, 88, 90, 10, 26, 70, 41, 94, 64, 14, 60]
             žLR          # built-in array 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
                ‡         # transliterate

R, 143 128 bytes

function(v)c(0:9,LETTERS)[match(colSums((sapply(v,U<-utf8ToInt)*194:198)%%45:41),U("#</Eb=,n9J.M4Z+%*V N[Hd\\B?1Oj>KgRYT2")+34)]

Try it online!

Function taking a vector of strings (corresponding to the columns) as input e.g. :


Explanation :

Performing the following operation for each encoded string (e.g 'CRGBY' = 'S') :

        TO ASCII      MULTIPLICATION             MODULO              SUM &              TO
        CODEPOINT                                                    OFFSET             ASCII

'C'        67        67 * 194 = 12998       12998 %% 45 = 38  \
'R'        82        82 * 195 = 15990       15990 %% 44 = 18  |
'G'  --->  71  --->  71 * 196 = 13916  ---> 13916 %% 43 = 27  |---> (140 - 34) = 106 ---> 'j'
'B'        66        66 * 197 = 13002       13002 %% 42 = 24  |
'Y'        89        89 * 198 = 17622       17622 %% 41 = 33  /

we obtain the following string '#</Eb=,n9J.M4Z+%*V N[Hd\B?1Oj>KgRYT2' where each character corresponds to '0123456789ABCDEFGHIJKLMNOPQR'.

So, the code performs the described operations on the input strings, then searches their correspondences inside '#</Eb=,n9J.M4Z+%*V N[Hd\B?1Oj>KgRYT2' obtaining the positions in string '0123456789ABCDEFGHIJKLMNOPQR'.

  • \$\begingroup\$ This looks clever but it’s not clear how to use the code: What shall I pass to the function? Both a list of character vectors and a plain vector fail with “non-conformable argument”. So does a character matrix. \$\endgroup\$ Commented Jun 12, 2019 at 16:09
  • \$\begingroup\$ @KonradRudolph: added a minimal explanation of the input (and changed the TIO in order to be more explicit). As soon as I can I'll add an explanation of the code, which I'm sure can be improved by finding an other "hashing" function for the strings returning values in the ASCII range instead of unicode... \$\endgroup\$
    – digEmAll
    Commented Jun 12, 2019 at 19:00
  • \$\begingroup\$ @digEmAll yeah I've been playing with modding down the digits to a more reasonable range of distinct characters but nothing yet \$\endgroup\$
    – Giuseppe
    Commented Jun 12, 2019 at 19:12
  • \$\begingroup\$ @digEmAll Ah that works (I had the data as col-major rather than row-major) but your example results in “HEKKN”, not “HELLO”. I’m very confused that it appears to work on TIO. Different (non-UTF-8) encoding, I guess. \$\endgroup\$ Commented Jun 12, 2019 at 19:42
  • 1
    \$\begingroup\$ @KonradRudolph: added a brief explanation (and found a shorter code) ;) \$\endgroup\$
    – digEmAll
    Commented Jun 16, 2019 at 17:12

Charcoal, 66 bytes


Try it online! Link is to verbose version of code. Takes input as a list of columns terminated with a blank line. Explanation:


Input strings until one is blank.


Cyclically index into the string OV EX8HSCF5IA L TG 17 M P9RB 4 K ZY2 0JW 63Q ND U which (with trailing space) is 56 characters long.


Perform base-7 conversion using the alphabet WMYCBGR and then reduce successively modulo 360, 113, 71, and 56 implicitly via the cyclic indexing.

My base 7 approach fared really badly with @Arnauld's fixed font; after some searching I was still at 73 bytes. Using @Grimy's approach cut this down to 67 bytes. However I eventually tracked down a 66 byte solution:


Try it online! Link is to verbose version of code. Explanation:


Input strings until one is blank.


Cyclically index into the string ID HAM178 VS4F 3R EP6CQ Z UB O 0 X 9 G 5TNJKL2Y W which is 63 characters long.


Perform base-47 conversion using the alphabet 0-9A-Za-k and then reduce successively modulo 237, 73, 67, and 63 implicitly via the cyclic indexing.


CJam (63 bytes)


or in xxd format

0000000: 7b7b 4762 22f5 e1d6 c59f 7b61 2822 7b69  {{Gb".....{a("{i
0000010: 257d 2f22 0b8a 8340 982f d6b4 e793 fddf  %}/"...@./......
0000020: 7d79 f9dc c519 17a9 0e47 0ef4 c9e7 a222  }y.......G....."
0000030: 3235 3662 3433 6227 3066 2b3d 7d25 7d    256b43b'0f+=}%}

This is an anonymous block (function) which expects input as a list of columns. Online demo.

As many of the other answers, this does a base conversion followed by a chain of % to get a short lookup table. In this case I use base 16 and % chain [245 225 214 197 159 123 97 40].


Jelly, 48 bytes


A monadic Link accepting a list of lists of uppercase characters (each being a column) which yields a list of characters.

Try it online!


OḌ%⁽qƥ%⁹%53“...’b51¤iⱮịØB - Link: columns
O                         - ordinals
 Ḍ                        - convert from base ten
  %⁽qƥ                    - modulo 29415
      %⁹                  - modulo 256
        %53               - modulo 53
                    iⱮ    - map with first index of x in:
                   ¤      -   nilad followed by link(s) as a nilad:
           “...’          -     22270425059867513817410846141176204460122938458128124185752719
                b         -     convert to base
                 51       -       51
                          -     ... = [38,13,19,27,10,16,20,11,35,31,4,17,9,0,50,45,24,25,34,39,22,29,41,32,3,7,46,5,48,18,6,44,28,14,1,8]
                      ị   - index into
                       ØB -   "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"

Ruby, 109 bytes


Try it online!


Stax, 46 bytes


Run and debug it

Each column is decoded as base-36. Successive modulus of 8273, then 95 are applied. This yields a unique number, looked up in a fixed string.

It takes input exactly in the format specified in the examples, and has to transpose them to get columns. I will be able to save some bytes by using some different input format, which I may do at some point.


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.