11
\$\begingroup\$

Back in the day, all the 1337 kids used text faders in chatrooms. I don't know about you guys, but I want to feel cool like they did. The only problem is that their old scripts and applications were heavily coupled to the software they were made for, so I can't just make use of this amazing functionality wherever I want. I also want the solution to be easily portable so you're going to need to make the code as small as possible so that it will fit on my floppy disk (I'd rather only carry one floppy but if your source code is too big I can carry more than one :P).

Input

  • A list of colors (rgb, hex, names, etc)
  • Text to format

Your program should expect the list of colors to contain at least 2 colors.
Text to format can be any length greater than zero and characters will be limited to printable ascii. (Hint: Longer text inputs may require you to reuse intermediate colors for consecutive characters)

Output

The output text should not differ from the input text in any way other than font and/or markup/styling (Note: if your output contains html markup then you'll need to html encode the input). You may output text with markup/styling (html style tags, console colors, etc.) or a picture of the faded text. All color hexes should be present in the output unless the input does not contain enough characters to meet this requirement. If this is the case, then consult the priority rules to determine which color hexes should be present in your output. The order or these colors in your output should still be input order.

Color Priority Rules

  1. In the event that the input is one character, the first color will be used
  2. In the event that there are only two characters, the first and last color will be used
  3. In the event that there are more than three colors and more colors than characters, the first and last colors should be prioritized, then the rest of the colors in their inputted order.
  4. In the event that there are more characters than colors, the characters should fade from one color to the next using intermediate colors

Examples (Priority rules 1-3 respectively):
# Colors | Color0 | ... | Colorn | Text
3 ff0000 0000ff ffff00 M -> only first
3 ff0000 0000ff ffff00 hi -> ignore 2nd
4 ff0000 0000ff ffff00 0fff00 sup -> ignore 3rd

To be clear, the text color should fade from one color hex to the next. The fade does not have to be perfectly uniform but it shouldn't be an abrupt color change unless there aren't enough characters to fade nicely. Generally this fade is achieved by choosing intermediate colors for each of the characters by incrementing/decrementing the rgb values by some interval determined by the number of characters you have to work with and the difference between the colors. For example if we needed a single color between red (#ff0000) and black (#000000), we might choose #800000 as it sits right in the middle. Optimal output will look rather pretty.

Example (Priority rule 4):
3 ff0000 ff7f00 f0ff00 To be or not to be, that is the question... -> to be or not
-OR-

<span style="color:#ff0000;">T</span><span style="color:#ff0600;">o</span><span style="color:#ff0c00;"> </span><span style="color:#ff1200;">b</span><span style="color:#ff1800;">e</span><span style="color:#ff1e00;"> </span><span style="color:#ff2400;">o</span><span style="color:#ff2a00;">r</span><span style="color:#ff3000;"> </span><span style="color:#ff3600;">n</span><span style="color:#ff3c00;">o</span><span style="color:#ff4300;">t</span><span style="color:#ff4900;"> </span><span style="color:#ff4f00;">t</span><span style="color:#ff5500;">o</span><span style="color:#ff5b00;"> </span><span style="color:#ff6100;">b</span><span style="color:#ff6700;">e</span><span style="color:#ff6d00;">,</span><span style="color:#ff7300;"> </span><span style="color:#ff7900;">t</span><span style="color:#ff7f00;">h</span><span style="color:#fe8500;">a</span><span style="color:#fe8b00;">t</span><span style="color:#fd9100;"> </span><span style="color:#fc9700;">i</span><span style="color:#fb9d00;">s</span><span style="color:#fba400;"> </span><span style="color:#faaa00;">t</span><span style="color:#f9b000;">h</span><span style="color:#f9b600;">e</span><span style="color:#f8bc00;"> </span><span style="color:#f7c200;">q</span><span style="color:#f6c800;">u</span><span style="color:#f6ce00;">e</span><span style="color:#f5d400;">s</span><span style="color:#f4da00;">t</span><span style="color:#f4e100;">i</span><span style="color:#f3e700;">o</span><span style="color:#f2ed00;">n</span><span style="color:#f1f300;">.</span><span style="color:#f1f900;">.</span><span style="color:#f0ff00;">.</span> 

In your answer please specify how your output should be displayed (as html, in a console, as an image, etc.).

* All black backgrounds are only for color emphasis and are not required

Scoring

This is , so the shortest answer (in bytes) wins.
If you manage to add fade to individual characters then I'll forever think you're cool (but no bonus to score as this will not be fair for some langs)

\$\endgroup\$
  • \$\begingroup\$ The average of #000000 and #ff0000 is not #800000. \$\endgroup\$ – Leaky Nun May 24 '16 at 23:26
  • \$\begingroup\$ @LeakyNun In RGB space it is near enough, the other option being #7f0000. \$\endgroup\$ – Neil May 24 '16 at 23:42
  • \$\begingroup\$ Not really. Try to average red and green in this way and see if you get yellow. To do it the right way, take the root-mean-square instead of direct average. \$\endgroup\$ – Leaky Nun May 25 '16 at 0:19
  • \$\begingroup\$ The average of 000000 and ff0000 should be b40000 (255*sqrt((0+1)/2)) \$\endgroup\$ – Leaky Nun May 25 '16 at 0:21
  • 1
    \$\begingroup\$ @LeakyNun I never said you needed to average the colors. I described an easy method of fading that is sometimes employed for challenges like this. In this case we averaged the reds of the two colors (and rounded). I also noted in the challenge that the fade does not have to be perfectly uniform. It is up to you how you want to implement this fade. \$\endgroup\$ – Poke May 25 '16 at 5:28
3
\$\begingroup\$

JavaScript (ES6), 290 bytes

h=a=>f(a,a.shift());f=
(a,w)=>[...w].map((c,i)=>{l=w.length-1;m=a.length-1;s=o.appendChild(document.createElement('span'));s.textContent=c;s.style.color=`#${i?i-l?a[r=l%m,n=l/m|0,i<r*n+r?++n:i-=r,k=i/n|0,k++].replace(/./g,(c,d)=>((parseInt(c,16)*(n-i%n)+i%n*parseInt(a[k][d],16))/n|0).toString(16)):a[m]:a[0]}`;})
<textarea rows=10 cols=40 oninput="o.textContent='';h(this.value.split`\n`)">Type the text here and the colours on subsequent lines.
FF0000
00FF00
0000FF</textarea><div id=o>

\$\endgroup\$
  • 1
    \$\begingroup\$ That's really cool to see it happen in real time with the code snippet. :D \$\endgroup\$ – AdmBorkBork May 25 '16 at 15:43
1
\$\begingroup\$

Pyth, 126 bytes

Obligatory root-mean-square average instead of direct arithmetic mean.

L%"<span style=\"color:#%s\">%s</span>",smt.H+256s*255@d2ebhbMm+hG*-eGhGcdHH=Q^RL2Q+smsyMC,hdCgRlhdCedC,ctlQPzC,QtQy,ez?tlzeQh

Try it online!

Sample output:

sample

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

Java, 702 662 characters

Two functions golfed:

import java.awt.*;String f(Color C,char c){return"<span style=\"color:#"+Integer.toHexString(C.getRGB()).substring(2)+";\">"+c+"</span>";}String c(String t,String[]h){String r="";int l=h.length,e=t.length(),i=0,s=0,g=1,c=-1,p,q,u;double d,m=0,v;char[]T=t.toCharArray();Color C[]=new Color[l],H[],a,b;for(;i<l;)C[i]=Color.decode(h[i++]);if(l>e){H=java.util.Arrays.copyOfRange(C,0,e);H[e-1]=C[l-1];H[0]=C[0];C=H;l=e;}d=--e/(l-1.);for(;++c<e;){a=C[s];b=C[g];p=b.getRed()-a.getRed();q=b.getGreen()-a.getGreen();u=b.getBlue()-a.getBlue();v=m/d;r+=f(new Color(a.getRGB()+((int)(v*p)<<16|(int)(v*q)<<8|(int)(v*u))),T[c]);if(++m>d){m-=d;s=g++;}}return r+f(C[l-1],T[e]);}

As nobody can read this: here are both functions in there ungolfed version in a class:

import java.awt.*;

public class Q80554 {

    static String format(Color color, char character) {
        return "<span style=\"color:#" + Integer.toHexString(color.getRGB()).substring(2) + ";\">" + character + "</span>";
    }

    static String colorizeB(String text, String[] hexColors) {
        String result = "";
        int colorsLength = hexColors.length, textLength = text.length(), i, currentStartColorPos = 0, currentGoalColorPos = 1, currentCharPos = -1, diffColorRed, diffColorGreen, diffColorBlue;
        double difference, goneDifference = 0, relativeChange;
        char[] textArray = text.toCharArray();
        Color colors[] = new Color[colorsLength], changer[], currentStartColor, currentGoalColor;

        for (i = 0; i < colorsLength;)
            colors[i] = Color.decode(hexColors[i++]);

        if (colorsLength > textLength) {
            changer = Arrays.copyOfRange(colors, 0, textLength);
            changer[textLength - 1] = colors[colorsLength - 1];
            changer[0] = colors[0];

            colors = changer;
            colorsLength = textLength;
        }

        // fade
        difference = --textLength / (colorsLength - 1.); // space between colors    

        for (; ++currentCharPos < textLength;) {
            currentStartColor = colors[currentStartColorPos];
            currentGoalColor = colors[currentGoalColorPos];

            diffColorRed = currentGoalColor.getRed() - currentStartColor.getRed();
            diffColorGreen = currentGoalColor.getGreen() - currentStartColor.getGreen();
            diffColorBlue = currentGoalColor.getBlue() - currentStartColor.getBlue();

            relativeChange = goneDifference / difference;

            result += format(new Color(currentStartColor.getRGB() + ((int) (relativeChange * diffColorRed) << 16 | (int) (relativeChange * diffColorGreen) << 8 | (int) (relativeChange * diffColorBlue))), textArray[currentCharPos]);

            if (++goneDifference > difference) {
                goneDifference -= difference;
                currentStartColorPos = currentGoalColorPos++;                   
            }
        }

        // last character always has last color
        return result + format(colors[colorsLength - 1], textArray[textLength]);
    }
}

Here you have an upper bound for your own code. Usage is by calling colorize (or c in the golfed version) and pass the text and an array of hex color codes. The function will return a String with HTML-tags like the OP did, thus you need some way to render the HTML.

The algorithm is easier as the question looks like. The first character always gets the first color, the last one always the last. If we have more colors than chars in the text we just iterate over the text and colors and apply these. The fun part is the one with the fades: I started of by finding out in what distance the colors are on the text. I basically calculate the red, green and blue difference between two given colors and then add a part of this difference to the first color, depending on where the char is between the colors. If it leaves the interval of two colors we start from new with the next two colors. This is repeated for all but the last character, which we know is always the last color. This gives a very beautiful fading.

That question was very much fun! Thanks!

Updates

Now I don't handle all the cases specially. Instead I trim the colors if there are two much and apply the fade function to every string. If there were more colors than text then the colors will be trimmed and the fading function will work exactly as a simple mapping.

\$\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.