Hexadecimal -> Binary Art

Take a list of 2-digit hexadecimal numbers as input, and output the binary value, replacing each 1 with an 'X', and each 0 with a space.

For example

Input = FF, 81, 47, 99.

• FF = 11111111 in binary, so print XXXXXXXX
• 81 = 10000001 in binary, so print X X
• 47 = 01000111 in binary, so print X XXX
• 99 = 10011001 in binary, so print X XX X

Full output:

XXXXXXXX
X      X
X   XXX
X  XX  X

Clarifications

• The hexadecimal numbers will always be 2-digits.
• There can be any number of hexadecimal numbers.
• You can choose to input in whatever format you want (separated by a space, comma, newline, etc.)
• The character to output for a 1 is X, and for 0 it is a . This will not change.
• The outputs must be padded to length 8

Also, apparently I wasn't clear enough: the input is in Hexadecimal (Base 16) not denary (Base 10)

This is , so the shortest answer in bytes wins!

• Should the binary representations be left-padded with 0s to the length of the longest or always to length 8? Sep 30, 2022 at 16:59
• @Shaggy - they must be padded to length 8, even if the biggest number is not 8 bits long. Sep 30, 2022 at 17:02
• Please edit the question to clearly indicate the padding requirement (people are not supposed to read all comments), and maybe include a test case to address that Sep 30, 2022 at 18:08
• For future challenges, consider relaxing the input and output requirements (such as allowing input in decimal or allowing a the answerer to choose the 1 character, not necessarily X). I don't think those restrictions make the challenge more interestin Sep 30, 2022 at 18:10
• Is accepting a list of lists of integers from $[0,15]$ valid (i.e. a list of numbers in base sixteen) or should this be tagged string? Sep 30, 2022 at 18:21

Excel (ms365), 74, 72, 59, 58 bytes

-14 Byte thanks to @jdt

=SUBSTITUTE(SUBSTITUTE(HEX2BIN(+A1:A4,8),"0"," "),"1","X")

Original answer using BYROW() for 71 bytes:

=BYROW(A:A,LAMBDA(a,CONCAT(IF(-MID(HEX2BIN(a,8),ROW(1:8),1),"X"," "))))

• Welcome to Code Golf, and nice answer! Sep 30, 2022 at 20:55
• I searched for alternatives for nested SUBSTITUTE functions and came upon your answer which did not really help =). It looks like you can save 1 byte: =BYROW(A:A,LAMBDA(a,CONCAT(IF(-MID(HEX2BIN(a,8),ROW(1:8),1),"X"," ")))).
– jdt
Oct 2, 2022 at 13:16
• @jdt yeah I looked into that too but things get longer than the nested IF(). Good spot on the fact a negative integer will also trigger the TRUE parameter. Adjusted!
– JvdV
Oct 2, 2022 at 14:10
• =SUBSTITUTE(SUBSTITUTE(HEX2BIN(0&A1:A4,8),"0"," "),"1","X")
– jdt
Nov 3, 2022 at 23:52
• @jdt, you pulled of a way to make HEX2BIN() take an array. Sweet!
– JvdV
Nov 4, 2022 at 7:52

Ruby-p, 40 31 bytes

Takes input on stdin separated by newlines.

$_=("%08b "%$_.hex).tr"01"," X"

Attempt This Online!

Python, 58 bytes

while 1:print(f"{int(input(),16):08b}".translate(" X"*99))

Attempt This Online!

Takes each hex code on a new line from input, prints to standard out. Terminates on error (is that allowed?)

Python, 67 bytes

lambda n:"\n".join(f"{int(x,16):08b}".translate(" X"*99)for x in n)

Attempt This Online!

Takes input as a list of hex strings and returns a string with newlines separating lines.

• You're going to have to add '\n'.join somewhere. The output must be in the format of the example in the question. Sep 30, 2022 at 17:13
• also this doesn't work correctly, you need bin(int(x,16))[2:].zfill(8), not bin(int(x,16)).zfill(8)[2:] Sep 30, 2022 at 17:18
• You can save a few bytes with f'{int(x,16):>08b}' instead of bin(int(x,16))[2:].zfill(8) Sep 30, 2022 at 17:31
• The > isn't necessary since we already know all the strings are of length 8. Sep 30, 2022 at 20:17

Japt-mR, 9 bytes

nG" X" ù8

Try it

nG" X" ù8    :Implicit map of input array
n            :Convert from base
G           :16
" X"       :To base " X"
ù8   :Left pad with spaces to length 8
:Implicit output joined with newlines

Retina 0.8.2, 61 57 bytes

.
$& (?=..[89A-F]|.[4-7C-F]|[2367ABEF]) X +TdA-F Xo Try it online! Explanation: .$&

Precede each digit with three spaces.

(?=..[89A-F]|.[4-7C-F]|[2367ABEF])
X

Replace the spaces with Xs where appropriate.

+TdA-F Xo

Reduce the remaining digit modulo 2 and replace with space or X as appropriate.

• @JvdV From the OP: The hexadecimal numbers will always be 2-digits.
– Neil
Oct 1, 2022 at 9:50
• Had to re-read and you are absolutely correct!
– JvdV
Oct 1, 2022 at 9:53

$_=sprintf"%08b ",hex;y/01/ X/ Pretty much identical to Jordan's Ruby answer Try it online! • 24 bytes: Try it online! Oct 3, 2022 at 4:22 sed 4.2.2, -E178 141 bytes s/./&FEDCBA9876543210:/g s/(\w)\w*\1//g s/\w/ /g s/ +/&&&&/ s/ +/&&&&/ s/:// : s/^(.+)\1:/\1: / s/^ (.*)\1:/\1:X/ t s/:// :z s/^.{,7}$/ &/
tz

Takes newline-separated input

-35 thanks to DLosc

Explanation

s/./&FEDCBA9876543210:/g  add hex digits to each input char
s/(\w)\w*\1//g            find index of input char in hex string
s/\w/ /g                  left is 2 strings which lengths corresponds to the input
s/ +/&&&&/
s/ +/&&&&/                multiply first strings' length by 16
s/://                     add the 2 strings, left is a unary number
:
s/^(.+)\1:/\1: /          convert to base 2, one bit at a time
s/^ (.*)\1:/\1:X/
t
s/://
:z
s/^.{,7}$/ &/ pad with spaces until length > 7 tz • Nice work! I did some rearranging and got it down to 143 bytes. Oct 1, 2022 at 16:13 • Even the naïve approach is only 175 bytes. – Neil Oct 1, 2022 at 16:45 JavaScript (ES6), 60 bytes -1 thanks to @MatthewJensen Expects a list of 2-character hexadecimal strings. a=>a.map(s=>(g=k=>k--?" X"['0x'+s>>k&1]+g(k):'')(8)).join  Try it online! Commented a => // a[] = input array a.map(s => // for each string s in a[]: ( g = k => // g is recursive function taking a counter k k-- ? // if k is not equal to 0 (decrement it afterwards): " X"[ // append either ' ' or 'X': '0x' + s // parse s as a hexadecimal string >> k // right-shift it by k position & 1 // and isolate the least significant bit ] // end of lookup + g(k) // append the result of a recursive call : // else: '' // stop the recursion )(8) // initial call to g with k = 8 ).join\n // end of map(); join with line-feeds • Save one byte by starting recursion at 8: a=>a.map(s=>(g=k=>k--?' X'['0x'+s>>k&1]+g(k):'')(8)).join  Oct 3, 2022 at 0:29 Brainfuck, 442 bytes ++++++++++>>>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[<<+>+>-]<----------------------------<++++++++++++++++++++++++++++>>,[------------------------------------------------[-[-[-[-[-[-[-[-[-[--------[-[-[-[-[-[<<<.>>>[-]>]<[<....>>]>]<[<...>.>]>]<[<..>.<.>>]>]<[<..>..>]>]<[<.>.<..>>]>]<[<.>.<.>.>]>]<[<.>..<.>>]>]<[<.>...>]>]<[.<...>>]>]<[.<..>.>]>]<[.<.>.<.>>]>]<[.<.>..>]>]<[..<..>>]>]<[..<.>.>]>]<[...<.>>]>]<[....>],] Attempt This Online! The input can be separated by every character with a value bigger than 'F'. The working section looks like this: | '\n' | 'X' | ' ' | {input character} | 0 (used for stopping loops) | prepare the initial state ++++++++++ newline prepare space and X >>> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ [<<+>+>-] < ---------------------------- space < ++++++++++++++++++++++++++++ X Go to start position and read char >>, [ subtract '0' ------------------------------------------------ [ if !0 -[ if !1 -[ if !2 -[ if !3 -[ if !4 -[ if !5 -[ if !6 -[ if !7 -[ if !8 -[ if !9 subtract difference between 'A' and '9' ------- -[ if !A -[ if !B -[ if !C -[ if !D -[ if !E -[ if !F print newline <<<.>>> clear input character [-]> ] <[ print 'F' <....>> ]> ] <[ print 'E' <...>.> ]> ] <[ print 'D' <..>.<.>> ]> ] <[ print 'C' <..>..> ]> ] <[ print 'B' <.>.<..>> ]> ] <[ print 'A' <.>.<.>.> ]> ] <[ print '9' <.>..<.>> ]> ] <[ print '8' <.>...> ]> ] <[ print '7' .<...>> ]> ] <[ print '6' .<..>.> ]> ] <[ print '5' .<.>.<.>> ]> ] <[ print '4' .<.>..> ]> ] <[ print '3' ..<..>> ]> ] <[ print '2' ..<.>.> ]> ] <[ print '1' ...<.>> ]> ] <[ print '0' ....> ] read next input , ] Vyxal, 10 8 bytes H‛ Xτ8↳⁋ Try it Online! -2 thanks to Steffan Port of Japt. • Your 6-byter suffers from the same issue with left-padding that my 5-byter did. Sep 30, 2022 at 17:02 • @Shaggy oops, fixed. Sep 30, 2022 at 17:09 Husk, 3431 28 bytes mȯötm!"X "ḋ+256B16m€f□…"1F"w Try it online! Takes input as a space-separated argument Husk is missing some useful functions such as pad and hex which makes this answer so long, or maybe I'm just bad. -3 DLosc -3 Razetime Explanation mȯötm!"X "ḋ+256B16m€f□…"1F"w w split on spaces mȯö map the following ultra composed penta-function m€f□…"1F" map input to indices the generated string "1-9A-F" B16 convert from digits in base 16 +256 add 256 to make the binary string 9 chars long ḋ convert to digits in base 2 m!"X " index into "X ", one-indexed modular t chop of first bit implicit output joined on newlines • Oct 1, 2022 at 5:01 • 26 bytes by prepending a 1 digit instead of adding 256... Nov 4, 2022 at 13:04 • ...which would be 23 bytes by taking input as a list (as in the challenge description), rather than as a single string... Nov 4, 2022 at 13:35 C (clang), 80 74 bytes i;f(**b){for(i=8;*b;)putchar(i--?strtol(*b,0,16)&1<<i?88:32:(b++,i=8)+2);} -3 bytes thanks to Arnauld!! Try it online! Alternative method proposed by Arnauld: C (clang), 73 bytes i;f(**b){while(*b)putchar(++i%9?strtol(*b,0,16)&1<<8-i%9?88:32:!++b+10);} Try it online! This will only work correctly for the first 477,218,588 lines. • 77 bytes by doing one more iteration for the linefeed. Sep 30, 2022 at 18:48 • 73 bytes but not 100% valid (it's not infinitely reusable because i will eventually overflow and not be congruent to 0 modulo 9 anymore when the function terminates). Sep 30, 2022 at 19:34 Factor, 60 bytes [ [ hex> "%08b"sprintf "10""X "zip substitute print ] each ] Try it online! • [ ... ] each Call [ ... ] on each hex string in the input sequence • hex> convert from hex to decimal • "%08b"sprintf format as a binary number string left-padded with spaces 8 wide • "10""X "zip create the following associative mapping: { { 49 88 } { 48 32 } } • substitute substitute characters in the binary string according to the mapping • print print to stdout with a newline Charcoal, 13 bytes ＷＳ⟦◧⍘⍘↧ι¹⁶ X⁸ Attempt This Online! Link is to verbose version of code. Explanation: ＷＳ Loop over all lines of input ⟦ Output each result on its own line ι Current line ↧ Lowercased ⍘ ¹⁶ Converted from base 16 ⍘ X Converted to custom base  X ◧ ⁸ Left padded to length 8 APL(Dyalog Unicode), 29 bytes SBCS ⍉' X'⌷⍨∘⊂2⊥⍣¯1(16⊥(⎕D,⎕A)∘⍳)¨ Try it on APLgolf! Python, 89 bytes lambda n:[print(bin(int(i,16))[2:].zfill(8).replace("1","X").replace("0"," "))for i in n] Function which takes in a list of hexadecimal strings. Try it online! Python, 98 bytes [print(*('X'if int(b)else' 'for b in bin(int(a,16))[2:].zfill(8)),sep='')for a in input().split()] Takes input itself, no header/footer code. Try it online! • a=lambda n:[print(bin(i)[2:].replace("1","X").replace("0"," "))for i in n].Works, but prints a list whose items are all None in the end. Oct 1, 2022 at 3:03 • @py3programmer - thanks. I think bin(int(i,16)) was needed instead of just bin(i) since bin needs an integer as the parameter. Also, you need the .zfill(8) otherwise it won't print a leading space. Oct 1, 2022 at 12:05 • Late comment, just pointing out on my answer: If you allow input to be taken as 0xFF instead of FF, you can shave off a byte by changing the bin(i,16) to bin(i,0) Feb 18, 2023 at 17:47 MATL, 10 bytes 1ZA8&B88*c Try it online! How it works % Implicit input: cell array of char vectors. 1ZA % Convert each char vector to number. Gives a numeric vector 8&B % Convert each number to 8-digit binary. Gives an 8-column binary matrix 88* % Multiply each element by 88 (ASCII code of 'X') c % Convert to char % Implicit display. char(0) is displayed as space K (ngn/k), 45 bytes {"\n"/|'8$|'" X"@+2\16/+"0123456789ABCDEF"?x}

Try it online!

This is way too long...

Bash + coreutils + dc, 6858 51 bytes

Takes input as arguments.

-10 bytes thanks to Steffan
-7 bytes thanks to manatwork

for a;{
printf "%08s
" dc<<<2o16i$a?n|tr 01 \ X } Try it online! • 58 bytes Oct 3, 2022 at 2:48 • @Steffan Very clever. Thanks! Oct 3, 2022 at 3:14 • Usually dc is shorter than bc. Try it online! Oct 3, 2022 at 4:36 • If you let dc do the conversion from base 16, you can save another character: Try it online! Oct 3, 2022 at 8:29 • @manatwork Thanks! Looks like I need to dig into dc. Oct 3, 2022 at 13:03 Pip-l, 17 bytes " X"@S*TDgFB16+E8 Takes the hex pairs as command-line arguments. Try It Online! Explanation " X"@S*TDgFB16+E8 g ;; List of command-line arguments FB16 ;; Converted (each) from base 16 + ;; Add (to each): E8 ;; 2 to the 8th power (256) TD ;; Convert (each) to binary as a list of digits S* ;; Get all but the first element of each " X"@ ;; Use those 0's and 1's to index into this string The result is a depth-2 nested list of spaces and X's. The -l flag concatenates each sublist together and outputs it on a separate line. (For a flagless version, add P* to the beginning of the code and u to the end.) Knight, 75 bytes ;=fB;=n 4W+=n-nT1O I%/-aI>60a 48 55^2n 2'X\'' \'W=pP;=aAp;Cf;=aA GpT1;CfO'' Try it online! Input each hexidecimal value on a separate line. Could be a bit shorter if it isn't required to output X's and spaces: Knight, 72 bytes ;=fB;=n 4W+=n-nT1O++''%/-aI>60a 48 55^2n 2'\'W=pP;=aAp;Cf;=aA GpT1;CfO'' Try it online! PowerShell, 63 bytes %{[convert]::ToString("0x1$_",2)}|% S*g 1|% *ce 1 X|% *ce 0 ' '

Try it online!

Input comes from the pipeline.
Pretty straightforward; converts to binary, replaces 0 and 1.

run $F(["FF", "81", "47", "99"]); Should output the expected result. Slightly more readable Both versions do exactly the same. fn($list) => {
&array_map(
$list, fn($line) => {

Try it online!