Your input will consist of an 18×18 image in any reasonable format, containing a horizontally and vertically centered 14px Roboto Mono character. This can be any of 94 printable ASCII characters (not including the space). But: you only need to be able to recognize some 80 character subset of your choice.

Output should be the character in the input image, as a character/string, code point, or some other reasonable representation.

To clarify input formats allowed, you can take input as an image in any reasonable representation, a matrix or array of pixels, or any other reasonable representation. You are allowed to assume the image will first be grayscaled or converted to black and white, and you can use that to, e.g., take input as a matrix of bools for white and black.

Test cases

Since you choose a subset of printable ASCII to use, these may or may not need to be handled.

An uppercase N

N, 0x4e, 78

A plus sign

+, 0x2b, 43

A lowercase z

z, 0x7a, 122

An at sign

@, 0x40, 64


You can find a .zip containing all 94 images here: png, pgm, pbm

This is , so shortest answer (in bytes) per-language wins.

  • \$\begingroup\$ (sandbox); This is part one of a two part challenge, part two of which will involve reading a whole page of Roboto Mono text. \$\endgroup\$ Nov 14, 2021 at 1:46

3 Answers 3


Python 3, 211 209 bytes

print("".join([")UUeG5W2jPfE-z@`od;,vlpBuF/D^Ym7Lk[]a%t}R'9>+6O_8gc=#!Z{SH~qCNyir3|xK$wn(J&T4?.Vs"[i]*(2**(0x1666a5a453070400d46a8119056156c0881a5746>>2*i&3))for i in range(81)])[sum(open(0,"rb").read())%203])

Reads a .rgba file from stdin and outputs the character to stdout. You can get the .rgba file with convert input.png -depth 8 output.rgba. The input is then hashed, by taking the sum of the byte values modulo 203. The long string and the large number are a compressed hash lookup-table.

Correctly recognizes every character except "<MIA*1XbhO:Q\

  • \$\begingroup\$ Welcome to Code Golf and nice first answer! You might be able to make this a bit shorter by recognising different character sets, using digits instead of b, or using a different formula. But nice job! \$\endgroup\$
    – emanresu A
    Nov 14, 2021 at 10:08

Python 2, 150 149 147 140 136 133 bytes

Takes the content of the pbm file as an argument.

lambda s:'Bf  R N  z (y !2VH:3 k9eMI7 CO;g[b#  8LGi n%u <"pEhW|_l  ,/ FJ?a10 DKo\'j*Z- $>s} ^xdm+)\{A@STv4Uwr`'[hash(s)%619914302%99]

Try it online! or Try the search program!

Incorrectly recognizes &.56=PQXY]cqt~ as kjdAm0|MMsiOyx. I've searched for formulas of the form hash(s)%a%b for a up to the limit of signed 32-bit integers. To improve on this you probably need to use a different idea, maybe hash(s+'...')%a%b as suggested by dingledooper, or something involving other operations than moduli.

  • 1
    \$\begingroup\$ A suggestion to shorten this if you're up for it: instead of a modulo, append some random string to s (hash(s+'???')%mod). You'd have to implement the hash algorithm from scratch, but I think this method has very good potential. \$\endgroup\$ Nov 14, 2021 at 20:07
  • \$\begingroup\$ @dingledooper I have had a short look into that and couldn't get anything better. I'm sure that with more time this would be the shorter approach, but for now I'm happy with the ...%99. \$\endgroup\$
    – ovs
    Nov 15, 2021 at 22:03

Ruby -p + Tesseract (4.1.1), 50 47 35 34 bytes

$_=`tesseract --psm 7 #$_ -`[/.$/]

Full program taking the name of a PNG file (terminated by EOF) from STDIN and printing the character to STDOUT. Somewhat fortuitously, exactly 80 characters are correctly identified:


The 14 characters not correctly recognised are:

input:  !$/0:CLOSV^`fl
output: t§I8fcb0sv“7F1

All the heavy lifting is done by Tesseract, a full-fledged OCR engine. The --psm 7 option causes the input image to be treated as a single line of text. For this set of images, --psm 7 gives the same results as the more appropriate but longer --psm 10, which enables single-character mode. (Strangely enough, the results differ for single-word mode, --psm 8.)

Tesseract returns a two-character string for some images (even with --psm 10); in these cases it turns out that the second character is correct slightly more often than the first. In the general case we therefore extract the last character before the linefeed.

  • \$\begingroup\$ You could technically save 2 bytes by using p to print instead of $_=..., right? \$\endgroup\$ Nov 14, 2021 at 7:07
  • \$\begingroup\$ @dingledooper If printing the character in quotes is considered reasonable, then yes. \$\endgroup\$
    – Dingus
    Nov 14, 2021 at 8:04

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.