Find the closest RGB color [closed]

Input: A valid 6 HEX digit color code wihout a # prefix
Valid:

• 000000
• FF00FF
• ABC123

Your job is to find to which one of these:

Red:   FF0000
Green: 00FF00
Blue:  0000FF
White: FFFFFF
Black: 000000


the input color is the closest too, in this case you try to only match it to black or white when the RGB is the same value for all 3 (the color is grey, or black or white ofc), if there is a "tie" you can pick whichever

The output is one of the aforementioned color codes. Examples:

Input: FF0000, Output: FF0000
Input: F10000, Output: FF0000
Input: 22FF00, Output: 00FF00
Input: FFFF00, Output: FF0000 or 00FF00
Input: 111112, Output: 0000FF
Input: 010101, Output: 000000
Input: A0A0A0, Output: FFFFFF


This is , so fewest bytes will win!

closed as unclear what you're asking by Luis Mendo, user202729, Sriotchilism O'Zaic, Peter Taylor, ZacharýOct 22 '18 at 14:14

Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

• Define "closest". What distance definition should be use? – Luis Mendo Oct 22 '18 at 11:57
• @LuisMendo As I read it, the function is var masked = [color >> 16, color >> 8 & 0xff, color & 0xff]; if (masked.allEqual()) return (~color&24)>color ? Black : White; else return [Red, Green, Blue][masked.indexOf(masked.max)] – Rogem Oct 22 '18 at 12:13
• Are we allowed to take input as a list of 3 hex values, or even better, 3 integers from 0 to 255? – HyperNeutrino Oct 22 '18 at 12:36
• Does input/output case matter? – HyperNeutrino Oct 22 '18 at 12:39
• @KevinCruijssen Why 888888? Surely 808080 is nearer to FFFFFF than 000000? – Neil Oct 22 '18 at 13:51

05AB1E, 3231 30 bytes

3äHDËiнžy@Di'F}6∍ë¾5∍sZk·„FFsǝ


Not really happy with it, so will see if I can golf it further..

When two RGB parts are the largest and equal, it will use the first one (i.e. 11ABAB will result in 00FF00). When all three parts are equal it will output 000000 when it's the range [00,7F] and FFFFFF for the range [80,FF].

Explanation:

3ä                  # Split the (implicit) input into three parts
H                 # Convert each part from Hexadecimal to a base-10 decimal
D                # Duplicate this list
Ëi              # If all three values are equal:
н             #  Leave only the first item of the list
žy@          #  Check if it's larger than or equal to 128 ("80" in hex)
D         #  Duplicate this truthy/falsey result
i  }     #  If the result is truthy:
'F     '#   Push "F"
#  (Implicit else:)
#   (Take the duplicated falsey 0)
6∍   #  Lenghten it to size 6
ë              # Else:
¾5∍           #  Push 0, lenghtened to size 5: "00000"
s          #  Swap so the duplicated list is at the top of the stack
Z         #  Take the max (without popping)
k        #  Take the index of this max in the list
·       #  Double this index
„FFsǝ  #  Replace the "0" in "00000" at this doubled index with "FF"
# (And output the top of the stack implicitly as result)


Python 3, 163 162 150 bytes

-1 byte thanks to Kevin Cruijssen

-12 bytes by some small tricks (thanks to HyperNeutrino for the "0F"[bool] idea)

def f(i):m=i[:2],i[2:4],i[4:];a,b,c=(e==max(m)for e in m);return"".join("0F"[e]*2for e in([i[:2]>"7E"]*3if a&b&c else([a,b,c]if a^b^c else[a,1^a,0])))


Try it online!

I was able to find a solution without turning the three hex values to integers (mainly because 'A' comes later in the ASCII table than '9', and so '9'<'A' is true). I am not really happy with some parts, but this was the shortest I could find.

Because this solution uses a different approach than the other python3 solution, I'm posting this as a seperate answer.

• Nice answer, +1 from me. You can remove the space at else "00" for -1 byte. – Kevin Cruijssen Oct 22 '18 at 12:58

JavaScript (ES6), 94 bytes

s=>'00FF000000FFFFFF'.substr(([r,g,b]=s.match(/../g),r+g==g+b?r<'8'?4:10:r>b?r>g&&2:b>g&&6),6)


Try it online!

How?

.slice(1).toString(16).toUpperCase()


But that would cost 36 bytes, and building such a bitmask is not especially cheap either.

It's significantly shorter to extract the relevant substring from "00FF000000FFFFFF", using the following offsets:

 pattern | offset | 00FF000000FFFFFF
---------+--------+------------------
000000  |    4   |     ^^^^^^
FFFFFF  |   10   |           ^^^^^^
FF0000  |    2   |   ^^^^^^
00FF00  |    0   | ^^^^^^
0000FF  |    6   |       ^^^^^^


Python 3, 219112 110 bytes

def f(s):h=max([0,1,2],key=lambda i:s[i*2:][:2]);return["00"*h+"FF"+"00"*(2-h),"F0"[s[:2]<"80"]*6][s==s[:2]*3]


Try it online!

-107 bytes by not being bad; drew a bit of inspiration from @Heitera by avoiding input integer parsing entirely.
-2 bytes thanks to @Heitera

• You can at least shorten this to 193 bytes by turning it into a true function and just define g, h once. – Black Owl Kai Oct 22 '18 at 13:08
• @Heiteira Thanks! I've already gotten it to 112 bytes with a bit of inspiration from your answer. – HyperNeutrino Oct 22 '18 at 13:08
• "0"*h*2 can be shortened to "00"*h, saving 1 byte. The same with "0"*(2-h)*2 – Black Owl Kai Oct 22 '18 at 13:14