Coding/Blog challenge 6

Coding/Blog challenge 6

Yet another CodeWars problem. This time we are getting a bit more algorithmic. It was pointed out to me that there was a library you could import called rgb2hex that could easily convert for you. Still, the practice of breaking down a problem like this is GREAT. I had a lot of fun with this one & learned some stuff along the way. I felt like Albus Dumbledore or Merlin after solving this. And then to be brought back to the realm of mere mortals when I discovered a much simpler way of doing this.

El Problema(The Problem)

JsProblem6.png

First off, the problem didn't do the best of jobs explaining how RGB is converted to hexadecimal. I had to do some googling to figure out more about how exactly this worked again. Here's my breakdown:

hex.png We will divide each of our RGB values by 16. (This might seem like a random number to some, but this is because of the 16-Bit color system: the maximum amount of colors that can be shown at one time. 16x16 = 256 or 0 to 255 which explains why RGB is numbered in such a way.) Take the number before the decimal & use our handy chart above to see what that number would be in hexadecimal. Then take the decimal number and multiply that by 16, if there is no decimal the hex value would be zero.

Mi pensamientos(my thoughts)

Yeah, okay, I had to google that one. What's the internet for? I first start by creating an object for the hex values.

function rgbToHex(r, g, b) {
    const hexDex = {
        0: "0",
        1: "1",
        2: "2",
        3: "3",
        4: "4",
        5: "5",
        6: "6",
        7: "7",
        8: "8",
        9: "9",
        10: "A",
        11: "B",
        12: "C",
        13: "D",
        14: "E",
        15: "F",
    }
}

After this, I first went to the very verbose way of making if/else statements for each of the RGB colors. But then thought, "wouldn't it be cool to loop through all the arguments?" Well, there is a way to do this with the arguments object in the JavaScript library. I then do conditional statements to check if the color number entered is out of range of our 256 color system and if it is, round to the closest valid number within the system.

This loop was super cool to me! I had an idea that I wanted to loop through all arguments. So I figured out how to do that & implemented it.

function rgbToHex(r, g, b) {
    //object with decimal as key & hex as value to be called upon later
    const hexDex = {
        0: "0",
        1: "1",
        2: "2",
        3: "3",
        4: "4",
        5: "5",
        6: "6",
        7: "7",
        8: "8",
        9: "9",
        10: "A",
        11: "B",
        12: "C",
        13: "D",
        14: "E",
        15: "F",
    }
    //loop through each argument
    for (let i = 0, j = arguments.length; i < j; i++) {
        //check if number is out of range & adjust
        if (arguments[i] >= 255) {
            arguments[i] = "FF"
        } else if (arguments[i] <= 0) {
            arguments[i] = "00"
        }

After this, I needed to use the math logic I spoke of above on each argument passed. I used the Math object to round my numbers. I then chose to convert this number to a string and split it at the decimal into an array. After that, I assign the first element of each array(at zero index) & perform more mathematics on the second element in each array(at one index). I also use the hex object I created to reassign values.

At this point I thought I was done! I passed all tests, but when trying to submit I failed one test. I didn't account for if a number was divisible by 16 & how I was rounding with the Math object. After, I created another condition to check for this and manipulated that to work.

Finally, I smash all these arguments back together to return. At this point I felt like a wizard.

function rgbToHex(r, g, b) {
    //obj with decimal as key & hex as value to be called upon later
    const hexDex = {
        0: "0",
        1: "1",
        2: "2",
        3: "3",
        4: "4",
        5: "5",
        6: "6",
        7: "7",
        8: "8",
        9: "9",
        10: "A",
        11: "B",
        12: "C",
        13: "D",
        14: "E",
        15: "F",
    }

    for (let i = 0, j = arguments.length; i < j; i++) {
        if (arguments[i] >= 255) {
            arguments[i] = "FF"
        } else if (arguments[i] <= 0) {
            arguments[i] = "00"
        //if divisible by 16
        } else if (arguments[i] % 16 == 0) {
            //assign whole number to an array, zero as my default elemnt index 1
            arguments[i] = [arguments[i].toString(), 0]
            //math applied to index zero
            arguments[i][0] = Math.round((arguments[i][0] / 16 * 100)) / 100
            //give argument a hex value
            arguments[i][0] = hexDex[arguments[i][0]];
        } else {
            arguments[i] = (Math.round((arguments[i] / 16 * 100)) / 100).toString().split('.');
            arguments[i][0] = hexDex[arguments[i][0]];
            arguments[i][1] = '.' + arguments[i][1];
            arguments[i][1] = Math.round(Number(arguments[i][1]) * 16).toString();
            arguments[i][1] = hexDex[arguments[i][1]];

        }
    }
    //convert to proper format and replace all commas
    let output = (r.toString() + g.toString() + b.toString()).replace(/,/g, "");
    return output
}

Feeling on top of the world, I decided to look at other solutions to this problem and saw this solution & was brought back to the level of peasant. I didn't know that you could use the toString method to convert to hexadecimal. At this point, my mind was blown.

function rgb(r, g, b) {
    return toHex(r) + toHex(g) + toHex(b);
}

function toHex(d) {
    if (d < 0) { return "00"; }
    if (d > 255) { return "FF"; }
    return ("0" + (Number(d).toString(16))).slice(-2).toUpperCase()
}

Whoa!