A Pure Way To Convert Colours

I read the daily programmer subreddit one day and saw a challenge to convert RGB to hex codes notation and didn't see a prolog implementation so had a hack at it.

Here is the original thread

To achieve this, one option is to use the built in predicate hex_bytes/2. This is simple, but not general There is no easy way to make a general predicate from this due to the fact that hex_bytes/2 does not allow all variable arguments.

rgb_hexcodes_simple(R, G, B, HexCodes) :-
    hex_bytes(Hex, [R,G,B]),
    format(atom(HexCodes), '#~w', Hex).

To create a true general version, need to generate a map of byte to hex_code as a list. There are only 256 in total so not too much. The results are included below.

all_hex_codes_as_list :-
    open('hex_bytes.pl', write, S),
    forall(between(0, 255, X),
        (hex_bytes(Hex, [X]),
            atom_chars(Hex, HexList),
            write_term(
                S,
                byte_hex_list(X, HexList),
                [fullstop(true), nl(true), quoted(true)])
        )
        ),
    close(S).

Once the list of code mappings has been created and made available, then a general version can be made.

The following version works but very slow for converting hex to rgb because it has to try every colour.

rgb_hexcodes_slow(R, G, B, HexCodes) :-
    byte_hex_list(R, [R1,R2]),
    byte_hex_list(G, [G1,G2]),
    byte_hex_list(B, [B1,B2]),
    atom_chars(HexCodes,[#,R1,R2,G1,G2,B1,B2]).

Speed up the conversion by ensuring that we we don't traverse the entire set of colours to find what we want

rgb_hexcodes(R, G, B, HexCodes) :-
    var(HexCodes),
    byte_hex_list(R, [R1,R2]),
    byte_hex_list(G, [G1,G2]),
    byte_hex_list(B, [B1,B2]),
    atom_chars(HexCodes,[#,R1,R2,G1,G2,B1,B2]).

rgb_hexcodes(R, G, B, HexCodes) :-
    ground(HexCodes),
    atom_chars(HexCodes,[#,R1,R2,G1,G2,B1,B2]),
    byte_hex_list(R, [R1,R2]),
    byte_hex_list(G, [G1,G2]),
    byte_hex_list(B, [B1,B2]).

Test using all variables for all arguments, the result is a list of all colours.

test1 :-
    rgb_hexcodes(R, G, B, HexCode),
    format('R: ~p, G: ~p, B: ~p, Code: ~p~n', [R,G,B,HexCode]).

Test with R,G,B as vars, Hex as a ground value.

test2 :-
    rgb_hexcodes(R, G, B, '#ab453b'),
    format('R: ~p, G: ~p, B: ~p~n', [R,G,B]).

Test with R,G,B as ground, Hex code as a variable.

test3 :-
    rgb_hexcodes(20, 255, 0, HexCode),
    format('Code: ~p~n', HexCode).

Test with all variables ground

test4 :-
    rgb_hexcodes(20, 255, 0, '#14ff00').

Can do some funky queries now, like getting all grey colour combos.

all_grey_colours(Hex) :-
    rgb_hexcodes(R, R, R, Hex).

All colours that have at least two values the same perhaps?

all_colours_with_dups(Hex) :-
    rgb_hexcodes(R, R, _, Hex).
all_colours_with_dups(Hex) :-
    rgb_hexcodes(_, R, R, Hex).
all_colours_with_dups(Hex) :-
    rgb_hexcodes(R, _, R, Hex).

Enough fun, here is the list of terms that were generated before.

byte_hex_list(0,['0','0']).
byte_hex_list(1,['0','1']).
byte_hex_list(2,['0','2']).
byte_hex_list(3,['0','3']).
byte_hex_list(4,['0','4']).
byte_hex_list(5,['0','5']).
byte_hex_list(6,['0','6']).
byte_hex_list(7,['0','7']).
byte_hex_list(8,['0','8']).
byte_hex_list(9,['0','9']).
byte_hex_list(10,['0',a]).
byte_hex_list(11,['0',b]).
byte_hex_list(12,['0',c]).
byte_hex_list(13,['0',d]).
byte_hex_list(14,['0',e]).
byte_hex_list(15,['0',f]).
byte_hex_list(16,['1','0']).
byte_hex_list(17,['1','1']).
byte_hex_list(18,['1','2']).
byte_hex_list(19,['1','3']).
byte_hex_list(20,['1','4']).
byte_hex_list(21,['1','5']).
byte_hex_list(22,['1','6']).
byte_hex_list(23,['1','7']).
byte_hex_list(24,['1','8']).
byte_hex_list(25,['1','9']).
byte_hex_list(26,['1',a]).
byte_hex_list(27,['1',b]).
byte_hex_list(28,['1',c]).
byte_hex_list(29,['1',d]).
byte_hex_list(30,['1',e]).
byte_hex_list(31,['1',f]).
byte_hex_list(32,['2','0']).
byte_hex_list(33,['2','1']).
byte_hex_list(34,['2','2']).
byte_hex_list(35,['2','3']).
byte_hex_list(36,['2','4']).
byte_hex_list(37,['2','5']).
byte_hex_list(38,['2','6']).
byte_hex_list(39,['2','7']).
byte_hex_list(40,['2','8']).
byte_hex_list(41,['2','9']).
byte_hex_list(42,['2',a]).
byte_hex_list(43,['2',b]).
byte_hex_list(44,['2',c]).
byte_hex_list(45,['2',d]).
byte_hex_list(46,['2',e]).
byte_hex_list(47,['2',f]).
byte_hex_list(48,['3','0']).
byte_hex_list(49,['3','1']).
byte_hex_list(50,['3','2']).
byte_hex_list(51,['3','3']).
byte_hex_list(52,['3','4']).
byte_hex_list(53,['3','5']).
byte_hex_list(54,['3','6']).
byte_hex_list(55,['3','7']).
byte_hex_list(56,['3','8']).
byte_hex_list(57,['3','9']).
byte_hex_list(58,['3',a]).
byte_hex_list(59,['3',b]).
byte_hex_list(60,['3',c]).
byte_hex_list(61,['3',d]).
byte_hex_list(62,['3',e]).
byte_hex_list(63,['3',f]).
byte_hex_list(64,['4','0']).
byte_hex_list(65,['4','1']).
byte_hex_list(66,['4','2']).
byte_hex_list(67,['4','3']).
byte_hex_list(68,['4','4']).
byte_hex_list(69,['4','5']).
byte_hex_list(70,['4','6']).
byte_hex_list(71,['4','7']).
byte_hex_list(72,['4','8']).
byte_hex_list(73,['4','9']).
byte_hex_list(74,['4',a]).
byte_hex_list(75,['4',b]).
byte_hex_list(76,['4',c]).
byte_hex_list(77,['4',d]).
byte_hex_list(78,['4',e]).
byte_hex_list(79,['4',f]).
byte_hex_list(80,['5','0']).
byte_hex_list(81,['5','1']).
byte_hex_list(82,['5','2']).
byte_hex_list(83,['5','3']).
byte_hex_list(84,['5','4']).
byte_hex_list(85,['5','5']).
byte_hex_list(86,['5','6']).
byte_hex_list(87,['5','7']).
byte_hex_list(88,['5','8']).
byte_hex_list(89,['5','9']).
byte_hex_list(90,['5',a]).
byte_hex_list(91,['5',b]).
byte_hex_list(92,['5',c]).
byte_hex_list(93,['5',d]).
byte_hex_list(94,['5',e]).
byte_hex_list(95,['5',f]).
byte_hex_list(96,['6','0']).
byte_hex_list(97,['6','1']).
byte_hex_list(98,['6','2']).
byte_hex_list(99,['6','3']).
byte_hex_list(100,['6','4']).
byte_hex_list(101,['6','5']).
byte_hex_list(102,['6','6']).
byte_hex_list(103,['6','7']).
byte_hex_list(104,['6','8']).
byte_hex_list(105,['6','9']).
byte_hex_list(106,['6',a]).
byte_hex_list(107,['6',b]).
byte_hex_list(108,['6',c]).
byte_hex_list(109,['6',d]).
byte_hex_list(110,['6',e]).
byte_hex_list(111,['6',f]).
byte_hex_list(112,['7','0']).
byte_hex_list(113,['7','1']).
byte_hex_list(114,['7','2']).
byte_hex_list(115,['7','3']).
byte_hex_list(116,['7','4']).
byte_hex_list(117,['7','5']).
byte_hex_list(118,['7','6']).
byte_hex_list(119,['7','7']).
byte_hex_list(120,['7','8']).
byte_hex_list(121,['7','9']).
byte_hex_list(122,['7',a]).
byte_hex_list(123,['7',b]).
byte_hex_list(124,['7',c]).
byte_hex_list(125,['7',d]).
byte_hex_list(126,['7',e]).
byte_hex_list(127,['7',f]).
byte_hex_list(128,['8','0']).
byte_hex_list(129,['8','1']).
byte_hex_list(130,['8','2']).
byte_hex_list(131,['8','3']).
byte_hex_list(132,['8','4']).
byte_hex_list(133,['8','5']).
byte_hex_list(134,['8','6']).
byte_hex_list(135,['8','7']).
byte_hex_list(136,['8','8']).
byte_hex_list(137,['8','9']).
byte_hex_list(138,['8',a]).
byte_hex_list(139,['8',b]).
byte_hex_list(140,['8',c]).
byte_hex_list(141,['8',d]).
byte_hex_list(142,['8',e]).
byte_hex_list(143,['8',f]).
byte_hex_list(144,['9','0']).
byte_hex_list(145,['9','1']).
byte_hex_list(146,['9','2']).
byte_hex_list(147,['9','3']).
byte_hex_list(148,['9','4']).
byte_hex_list(149,['9','5']).
byte_hex_list(150,['9','6']).
byte_hex_list(151,['9','7']).
byte_hex_list(152,['9','8']).
byte_hex_list(153,['9','9']).
byte_hex_list(154,['9',a]).
byte_hex_list(155,['9',b]).
byte_hex_list(156,['9',c]).
byte_hex_list(157,['9',d]).
byte_hex_list(158,['9',e]).
byte_hex_list(159,['9',f]).
byte_hex_list(160,[a,'0']).
byte_hex_list(161,[a,'1']).
byte_hex_list(162,[a,'2']).
byte_hex_list(163,[a,'3']).
byte_hex_list(164,[a,'4']).
byte_hex_list(165,[a,'5']).
byte_hex_list(166,[a,'6']).
byte_hex_list(167,[a,'7']).
byte_hex_list(168,[a,'8']).
byte_hex_list(169,[a,'9']).
byte_hex_list(170,[a,a]).
byte_hex_list(171,[a,b]).
byte_hex_list(172,[a,c]).
byte_hex_list(173,[a,d]).
byte_hex_list(174,[a,e]).
byte_hex_list(175,[a,f]).
byte_hex_list(176,[b,'0']).
byte_hex_list(177,[b,'1']).
byte_hex_list(178,[b,'2']).
byte_hex_list(179,[b,'3']).
byte_hex_list(180,[b,'4']).
byte_hex_list(181,[b,'5']).
byte_hex_list(182,[b,'6']).
byte_hex_list(183,[b,'7']).
byte_hex_list(184,[b,'8']).
byte_hex_list(185,[b,'9']).
byte_hex_list(186,[b,a]).
byte_hex_list(187,[b,b]).
byte_hex_list(188,[b,c]).
byte_hex_list(189,[b,d]).
byte_hex_list(190,[b,e]).
byte_hex_list(191,[b,f]).
byte_hex_list(192,[c,'0']).
byte_hex_list(193,[c,'1']).
byte_hex_list(194,[c,'2']).
byte_hex_list(195,[c,'3']).
byte_hex_list(196,[c,'4']).
byte_hex_list(197,[c,'5']).
byte_hex_list(198,[c,'6']).
byte_hex_list(199,[c,'7']).
byte_hex_list(200,[c,'8']).
byte_hex_list(201,[c,'9']).
byte_hex_list(202,[c,a]).
byte_hex_list(203,[c,b]).
byte_hex_list(204,[c,c]).
byte_hex_list(205,[c,d]).
byte_hex_list(206,[c,e]).
byte_hex_list(207,[c,f]).
byte_hex_list(208,[d,'0']).
byte_hex_list(209,[d,'1']).
byte_hex_list(210,[d,'2']).
byte_hex_list(211,[d,'3']).
byte_hex_list(212,[d,'4']).
byte_hex_list(213,[d,'5']).
byte_hex_list(214,[d,'6']).
byte_hex_list(215,[d,'7']).
byte_hex_list(216,[d,'8']).
byte_hex_list(217,[d,'9']).
byte_hex_list(218,[d,a]).
byte_hex_list(219,[d,b]).
byte_hex_list(220,[d,c]).
byte_hex_list(221,[d,d]).
byte_hex_list(222,[d,e]).
byte_hex_list(223,[d,f]).
byte_hex_list(224,[e,'0']).
byte_hex_list(225,[e,'1']).
byte_hex_list(226,[e,'2']).
byte_hex_list(227,[e,'3']).
byte_hex_list(228,[e,'4']).
byte_hex_list(229,[e,'5']).
byte_hex_list(230,[e,'6']).
byte_hex_list(231,[e,'7']).
byte_hex_list(232,[e,'8']).
byte_hex_list(233,[e,'9']).
byte_hex_list(234,[e,a]).
byte_hex_list(235,[e,b]).
byte_hex_list(236,[e,c]).
byte_hex_list(237,[e,d]).
byte_hex_list(238,[e,e]).
byte_hex_list(239,[e,f]).
byte_hex_list(240,[f,'0']).
byte_hex_list(241,[f,'1']).
byte_hex_list(242,[f,'2']).
byte_hex_list(243,[f,'3']).
byte_hex_list(244,[f,'4']).
byte_hex_list(245,[f,'5']).
byte_hex_list(246,[f,'6']).
byte_hex_list(247,[f,'7']).
byte_hex_list(248,[f,'8']).
byte_hex_list(249,[f,'9']).
byte_hex_list(250,[f,a]).
byte_hex_list(251,[f,b]).
byte_hex_list(252,[f,c]).
byte_hex_list(253,[f,d]).
byte_hex_list(254,[f,e]).
byte_hex_list(255,[f,f]).

You made it all the way down here? That is dedication!