18
\$\begingroup\$

The Challenge

Given the two uppercase hexadecimal strings (both 6 characters long, XXXXXX and YYYYYY) representing RGB values (ranging from 000000 to FFFFFF inclusive), and a positive non-zero integer N, display a linear transition of the N+2 colors generated from XXXXXX to YYYYYY that would result in a color gradient.

Example

Input

FF3762
F08800
9

Output

Please note in our example, I've requested 9 interim steps between the two colors, therefore 11 lines will be displayed from initial color to the final color

FF3762
FD3F58
FC474E
FA4F44
F9573A
F75F31
F66727
F46F1D
F37713
F17F09
F08800

Caveats

While I've gone with a simple linear process of deriving the integer values for the interim colors before converting them back into hexadecimal, your methods may vary. Please consider the various ways one could round up/down your numbers accordingly.

Testing

To make this interesting, I've provided a snippet to allow testing of your code, inclusive of a button to provide you with two random colors to test your code against. Displaying your results is optional, but it's encouraged!

c1=()=>('00000'+(Math.random()*(1<<24)|0).toString(16)).slice(-6);

$("#col").click(function(){
  alert("Your two colors are: "+c1()+" and "+c1()+".");
});
        
$("#colors").blur(function(){
  $("#test").empty();
	var colArr = $("#colors").val().split("\n");
	for(c in colArr){
  	$("#test").append('<div class="tester" style="background-color:#'+colArr[c]+';">'+colArr[c]+'</div>')
  }
  
});
.tester{height: 20px;
width: 60px;padding: 4px;border: 1px solid black;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="col">Your two colors</button><br />
<textarea id="colors"></textarea>
<div id="test">

</div>

1) You can access two random colors for your test by clicking on the "Your two colors" button. 2) The number of interim steps will be the same as the number of characters in your PPCG username inclusive of spaces, in the case of "WallyWest" it would be 9 (as per my example above). 3) Run your code with the two colors and the number and once you have your generated list, you have the option of pasting your output into the textarea and tabbing away from it to get your generated color gradient.

My example is shown here:

Gradients

I must admit, that looks pretty awesome!

Please note: As I mentioned, showing your testing of your output using the snippet is optional, but it's encouraged! :)

Output

The list output must be in the form of N+2 sets of 6 digit hex numbers separated by line feeds (\n) as shown in my example above. Output can be in the form of separate lines, space/comma separated list, an array or whatever is best suited for your language... (Thanks @nimi for the heads up) Please remember, that if you plan on testing your code with the snippet, however you separate each "color" is up to you.

Rules

This is code-golf, so the shortest solution in bytes will be crowned the winner. No loopholes, naturally. Input must accept the two strings and a number (which as I said will be equivalent to the number of letters in your username on PPCG, thus your resulting output will always be a minimum of three lines long.

\$\endgroup\$
  • 2
    \$\begingroup\$ Please allow output in list/array format for all languages. \$\endgroup\$ – nimi Sep 7 '16 at 3:30
  • \$\begingroup\$ Noted, and updated... Thanks for the heads up (+1) \$\endgroup\$ – WallyWest Sep 7 '16 at 3:37
  • \$\begingroup\$ Out of curiosity, do image apps like Illustrator use linear gradients or gradients in some perceptual color space? I can see use cases for both (maybe you're doing the transformation to perceptual later e.g. a texture for a game). \$\endgroup\$ – Robert Fraser Aug 16 '17 at 3:36

10 Answers 10

1
\$\begingroup\$

MATL, 31 bytes

2+1yhjjh2e!1ZA3e!b:1&Ynk8W5Y2Za

This uses linear interpolation with rounding down. Input format is

9
FF3762
F08800

Try it online!

Graphical output, 31 bytes

2+1yhjjh2e!1ZA3e!b:t2YG1&Ynk2ZG

This is the result for inputs

5
FF3762
F08800

enter image description here

Try it in MATL Online! The interpreter is currently experimental. If you don't get any output refresh the page and press "Run" again.

\$\endgroup\$
4
\$\begingroup\$

JavaScript (ES6), 130 bytes

g=
(f,t,n)=>[...Array(++n+1)].map((_,i)=>f.replace(/../g,(e,j)=>((`0x${e}`*(n-i)+`0x${t[j]+t[j+1]}`*i)/n|256).toString(16).slice(1)))
;
p=_=>g(f.value,t.value,+n.value).map(e=>o.insertRow().insertCell().appendChild(document.createTextNode(e)).parentNode.bgColor=e);
<input id=f value=e14f09><input id=t value=9a04f6><input id=n value=4 type=number><input type=button onclick=p() value=Go!><table id=o bgcolor=black cellpadding=4>

\$\endgroup\$
3
\$\begingroup\$

Dyalog APL, 44 bytes

Prompts for N, then Beginning-color, then Ending-color. Needs ⎕IO←0 which is default on many systems.

h[↑⌊B∘+¨(⍳2+N)×(-/E B←(h←⎕D,⎕A)∘⍳¨⍞⍞)÷1+N←⎕]

h[...] index into h (which has a value when we finish evaluating the the bracket's content)

N←⎕ prompt for numeric N (4)

1+ add one to N (5)

(... use that to divide the result of...

  ⍞⍞ prompt for two character strings ["7E0E7E","FF3762"]

  (...)∘⍳¨ find the indices of the each string's characters in...

   ⎕D,⎕A Digits followed by Alphabet

   h← assigned to h

  now we have "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"

  E B← assign the indices to E and B [[7,14,0,14,7,14],[15,15,3,7,6,2]]

  -/ subtract and enclose B from E [[-8,-1,-3,7,1,12]]

  the result so far is [[-1.6,-0.2,-0.6,1.4,0.2,2.4]]

(... multiply this by...

  2+N two plus N (6)

   first integers [0,1,2,3,4,5]

 this gives us [[0,0,0,0,0,0],[-1.6,-0.2,-0.6,1.4,0.2,2.4],[-3.2,-0.4,-1.2,2.8,0.4,4.8],...]

B∘+¨ add B to each [[15,15,3,7,6,2],[13.4,14.8,2.4,8.4,6.2,4.4],[11.8,14.6,1.8,9.8,6.4,6.8],...]

round down [[15,15,3,7,6,2],[13,14,2,8,6,4],[11,14,1,9,6,6],...]

make list of lists into table

[[15,15, 3, 7, 6, 2]
 [13,14, 2, 8, 6, 4]
 [11,14, 1, 9, 6, 6]
 [10,14, 1,11, 6, 9]
 [ 8,14, 0,12, 6,11]
 [ 7,14, 0,14, 7,14]]

here we index into h, giving

[["F","F","3","7","6","2]
 ["D","E","2","8","6","4]
 ["B","E","1","9","6","6]
 ["A","E","1","B","6","9]
 ["8","E","0","C","6","B]
 ["7","E","0","E","7","E]]

which is the same as

[["FF3762"]
 ["DE2864"]
 ["BE1966"]
 ["AE1B69"]
 ["8E0C6B"]
 ["7E0E7E"]]

and prints as

FF3762
DE2864
BE1966
AE1B69
8E0C6B
7E0E7E

gradient

TryAPL online!

\$\endgroup\$
  • \$\begingroup\$ Nice work! The transition looks great! \$\endgroup\$ – WallyWest Sep 7 '16 at 21:17
  • \$\begingroup\$ @WallyWest Thanks. It is probably a different linear transition than most do: Each letter is transitioned separately. \$\endgroup\$ – Adám Sep 7 '16 at 21:19
2
\$\begingroup\$

Pyth - 35 bytes

Horribly golfed, just gave up.

j++hQsMCm.HMsM:F+dc-FdvzCmiR16cd2Qe

Try it online here.

Example:

example

\$\endgroup\$
  • \$\begingroup\$ I count 11 lines of gradient, though your PPCG name only has 8 letters... So shouldn't you have entered 7cb472 93fb8a 8 and only received 10 lines of output when testing your code? \$\endgroup\$ – WallyWest Sep 7 '16 at 3:04
  • \$\begingroup\$ @WallyWest completely missed that part in the OP about the username, I just used 9 cuz you did, fixing. \$\endgroup\$ – Maltysen Sep 7 '16 at 3:08
  • \$\begingroup\$ @WallyWest updated \$\endgroup\$ – Maltysen Sep 7 '16 at 3:11
  • \$\begingroup\$ Hey @Maltysen, the gradient seems a bit odd... you've got two references of 93fb8a... Did your code output two lines of the same value? \$\endgroup\$ – WallyWest Sep 7 '16 at 3:25
2
\$\begingroup\$

PowerShell v2+, 176 159 150 bytes

param($a,$b,$n)$x=$a-split'(..)'-ne'';$a;++$n..1|%{$j=$_;-join($x=$x|%{"{0:x2}"-f(+"0x$_"-[int]((+"0x$_"-"0x$(($b-split'(..)'-ne'')[$i++%3])")/$j))})}

Takes the input as two strings and a number, then converts the start string into an array of strings split on every two characters, stores that into $x. We then output $a as our starting section, and loop from ++$n to 1 (to ensure proper fenceposting).

Each iteration, sets helper $j to the current number (used later for ensuring we've got the right number of steps between where we're currently at to our destination) and calculates the next step based on a loop through $x.

Each inner loop is just an assignment. We're setting $x at the appropriate place equal to a new string "{0:x2}" using the -format operator. The x2 here specifies a two-digit hexadecimal output, and the input is the right-hand side of the -f operator. PowerShell has a native hexadecimal-to-decimal operator 0x, so this lengthy parens-nested expression is using that operator to convert the current hex to numbers, subtracting to find the difference yet to go (done by dynamically splitting $b here just like we did to $a, and using modulo to select the right element), dividing by $j steps remaining, casting to an [int] (PowerShell does banker's rounding by default), and subtracting that step-count from the current hex to get what our next hex needs to be.

The result of that calculation is stored back into $x as three hex elements. That's encapsulated in parens to create a copy on the pipeline, and -joined together into a single string. All those resultant strings are left on the pipeline, and output via implicit Write-Output happens at program execution.


Example

I was given 0ba7c5 and 6c0e50 for my two colors, and TimmyD has 6 characters in it.

PS C:\Tools\Scripts\golfing> .\rgb-gradients-generation.ps1 '0ba7c5' '6c0e50' 6
0ba7c5
1991b4
277ba3
356592
434f82
513971
5f2361
6c0e50

Gradient Example

\$\endgroup\$
1
\$\begingroup\$

Python 2, 189 bytes

w='[int(%s[i:i+2],16)for i in range(0,6,2)]'
def f(a,b,n):
 l=lambda x,y:'%02x'%int((x*(n-i)+y*i)/n);c,d,e=eval(w%'a');f,g,h=eval(w%'b');n+=1
 for i in range(n+1):print l(c,f)+l(d,g)+l(e,h)

gradient screenshot

\$\endgroup\$
  • \$\begingroup\$ Gorgeous pair of colors, @AndrewEpstein... Nice work with the code! \$\endgroup\$ – WallyWest Sep 7 '16 at 19:29
1
\$\begingroup\$

[Groovy] Final Update (199 Bytes) - As per request

Non-golf

def g(a,b,n){
  (0..(1.0/n)).collect{
    c->
    x={s->s.split("(?<=\\G.{2})").collect{Integer.parseInt(it,16)}};
    (0..2).collect {
      (int)(x(a).get(it)*n*c+x(b).get(it)*(1-n*c))
    }.collect {
      String.format("%X", it)
    }.join()
  }
}
g('FFFFFF','000000',1/10​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​)​​​​​​​​​​​​​​

Golf

g(a,b,n){(0..(1.0/n)).collect{c->x={s->s.split("(?<=\\G.{2})").collect{Integer.parseInt(it,16)}};(0..2).collect {(int)(x(a).get(it)*n*c+x(b).get(it)*(1-n*c))}.collect{String.format("%X",it)}.join()}}

Try the final here: https://groovyconsole.appspot.com/script/5130696796405760


OLD VERSIONS BELOW, DECLINED BY OP


Groovy (123 Bytes)

Golf

def g(r,g,b,r2,g2,b2,s){(1..(1.0/s)).collect{c->[(int)(r*s*c+r2*(1-s*c)),(int)(g*s*c+g2*(1-s*c)),(int)(b*s*c+b2*(1-s*c))]}}

Non-golf

def g(r,g,b,r2,g2,b2,s){
  (1..(1.0/s)).collect {
    c ->
    [(int)(r*s*c+r2*(1-s*c)),(int)(g*s*c+g2*(1-s*c)),(int)(b*s*c+b2*(1-s*c))]
  }
}

Inputs

r,g,b -> Starting RGB Color
r2,g2,b2 -> Ending RGB Color
s -> Gradient step

Output Example

(00,00,00,255,255,255,.5)

results in

[
  [255, 255, 255]
  [127, 127, 127]
  [0, 0, 0]
]

Try it yourself: https://groovyconsole.appspot.com/script/5184465357766656

With Hex Conversions Included

Guess I'm kind of cheating as well... Here's the script with using hex:

New code with hex conversions:

​    def g(r,g,b,r2,g2,b2,s){
      (0..(1.0/s)).collect {
        c ->
        String.format("%X", ((int)(r*s*c+r2*(1-s*c)))) +  String.format("%X", ((int)(g*s*c+g2*(1-s*c)))) + "" +  String.format("%X", ((int)(b*s*c+b2*(1-s*c))))
      }
    }

    g(126,34,166,218,26,33,0.0625)​

188 characters when golfed:

def g(r,g,b,r2,g2,b2,s){(0..(1.0/s)).collect {c->String.format("%X",((int)(r*s*c+r2*(1-s*c))))+String.format("%X",((int)(g*s*c+g2*(1-s*c))))+String.format("%X",((int)(b*s*c+b2*(1-s*c))))}}

Output for 000000 to FFFFFF and 16 (Username Length)

g(00,00,00,255,255,255,0.0625).each{println it}​

Monochromatic Gradient with 1/16 Steps

\$\endgroup\$
  • \$\begingroup\$ Err... slightly invalid, original version used "(0..(1.0/s))", should have been "(1..(1.0/s))". \$\endgroup\$ – Magic Octopus Urn Sep 7 '16 at 17:23
  • 1
    \$\begingroup\$ Hi @carusocomputing... The input needs to be two hexadecimal strings and an integer... I'm not sure if Groovy can take input in this fashion, but you haven't quite nailed the brief... Could you please update your code based on the input mentioned in the Challenge section? \$\endgroup\$ – WallyWest Sep 7 '16 at 19:32
  • \$\begingroup\$ {s-> s.split("(?<=\\G.{2})").collect{Integer.parseInt(it,16)}}('FFFFFF') Results in [255,255,255] I can add 62 bytes to my code using that conversion if you really want me to. \$\endgroup\$ – Magic Octopus Urn Sep 7 '16 at 19:42
  • 1
    \$\begingroup\$ Wally, I've added an updated version and upped my final byte count to 199 with conversions included. \$\endgroup\$ – Magic Octopus Urn Sep 7 '16 at 20:16
1
\$\begingroup\$

R, 68 bytes

There is a built-in function that interpolates two colours:

a=scan(,'')
colorRampPalette(paste0("#",a[1:2]))(as.numeric(a[3])+2)

Input:

d9e7a5
3ef951
15

Output: a vector with values

"#D9E7A5" "#CFE89F" "#C5E99A" "#BBEA95" "#B2EB90" "#A8EC8A" "#9EED85" "#95EE80"
"#8BF07B" "#81F175" "#78F270" "#6EF36B" "#64F466" "#5BF560" "#51F65B" "#47F756"
"#3EF951"

Colour specification in R requires a hash symbol.

Colour ramp

Let’s plot something, like a function:

filled.contour(outer(1:20, 1:20, function(x,y) sin(sqrt(x*y)/3)),
    col = colorRampPalette(paste0("#",a[1:2]))(as.numeric(a[3])+2))

sin(sqrt(x*y)/3)

\$\endgroup\$
  • \$\begingroup\$ Great answer, but the brief asks to use as many steps as there are in your PPCG user name, which counting the space makes 15... Could you please update your answer based on FF3762 F08800 15? \$\endgroup\$ – WallyWest Sep 8 '16 at 20:10
  • \$\begingroup\$ @WallyWest Sorry, I had missed that part where one obtains two colours and counts his own username length. Now the answer should be fully compliant with the specification! \$\endgroup\$ – Andreï Kostyrka Sep 9 '16 at 0:20
1
\$\begingroup\$

C, 175 169 168 bytes

i;j;x[6];f(a,b,n)char*a,*b;{char*f="%2x%2x%02x";for(n++;i<=n;i++,puts(""))for(j=sscanf(a,f,x,x+1,x+2)-sscanf(b,f,x+3,x+4,x+5);j++<printf(f+6,x[j]+(x[j+3]-x[j])*i/n););}

Ungolfed:

int i, j;
int x[3], y[3];

f(char *a, char *b, int n) {
  sscanf(a, "%2x%2x%2x", &x[0], &x[1], &x[2]);
  sscanf(b, "%2x%2x%2x", &y[0], &y[1], &y[2]);

  for(i = 0, n++; i <= n; i++) {
    for(j = 0; j < 3; j++)
      printf("%02x", x[j] + (y[j] - x[j]) * i / n);
    puts("");
  }
}

Thanks to @h-walters for shaving off 5 bytes!

\$\endgroup\$
  • \$\begingroup\$ Remind me what the puts syntax does again? \$\endgroup\$ – WallyWest Sep 9 '16 at 12:27
  • \$\begingroup\$ It's like printf(), but doesn't do any formatting, instead it just prints the given string as it is, and it adds a newline. \$\endgroup\$ – G. Sliepen Sep 9 '16 at 20:38
  • \$\begingroup\$ Ah, so there's no way of golfing that... C's a bit restrictive like that, ain't it? \$\endgroup\$ – WallyWest Sep 9 '16 at 20:56
  • \$\begingroup\$ "so there's no way of golfing that"... Sure there is! Move puts("") into the third part of the first for loop (the ; after becoming a , before)... +0 bytes. However, this allows you to remove the curly braces after the second loop... -2 bytes. You can save another 1 byte by removing 3 from j<3, and replacing it with your printf statement (this is sneaky... printf will only return 2, but it still has to evaluate the third time). \$\endgroup\$ – H Walters Sep 10 '16 at 2:05
  • \$\begingroup\$ ...two more bytes can be saved by subtracting your sscanf return values from each other (resulting in 0), and using that instead of the literal 0 in j=0. Once everything here is in place your program should be 5 bytes shorter, and at least 50% stranger. \$\endgroup\$ – H Walters Sep 10 '16 at 2:23
1
\$\begingroup\$

sh + ImageMagick, 81 bytes

convert -size 1x$((2+$3)) gradient:#$1-#$2 -depth 8 txt:-|grep -o "[A-F0-9]\{6\}"

usage:

> ./grad.sh FF3762 F08800 9
FF3762
FE3F58
FC474E
FB4F45
F9573B
F86031
F66827
F5701D
F37814
F2800A
F08800

("-depth 8" is not necessary if your IM is compiled with 8bpp as the default)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.