Skip to content

Instantly share code, notes, and snippets.

@Costava
Created October 24, 2021 09:23
Show Gist options
  • Save Costava/b9df64f209c524d08e7ed95a65aed25c to your computer and use it in GitHub Desktop.
Save Costava/b9df64f209c524d08e7ed95a65aed25c to your computer and use it in GitHub Desktop.
Print a list of 256 random RGB colors, except some colors at front of list are predetermined.
/*
* Print a list of 256 random RGB colors,
* except some colors at front of list are predetermined.
* Also prints the seed used (epoch time in seconds).
* R component is first.
* Colors are at least a certain distance apart.
* May fail to find a color that is not too close
* to previously generated colors, then the program prints and exits.
* Takes no arguments.
*
* Example compilation:
* gcc randrgbpal.c -o randrgbpal -std=c99 -g -Wall -Wextra -Wconversion -lm
*
* License:
*
* BSD Zero Clause License
*
* Copyright (C) 2021 by Costava
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
// time but, if error, print to stderr and exit.
time_t TimeOrExit(time_t *const arg) {
const time_t value = time(arg);
if (value == (time_t)(-1)) {
fprintf(stderr, "time(%p) errored\n", arg);
exit(1);
}
return value;
}
// Get difference between two given values as positive double.
double AbsComponentDifference(const uint8_t c0, const uint8_t c1) {
return (c1 > c0) ? (c1 - c0) : (c0 - c1);
}
// Return difference between 2 given colors.
double GetColorDifference(
const uint8_t r0, const uint8_t g0, const uint8_t b0,
const uint8_t r1, const uint8_t g1, const uint8_t b1)
{
const double dr = AbsComponentDifference(r0, r1);
const double dg = AbsComponentDifference(g0, g1);
const double db = AbsComponentDifference(b0, b1);
return sqrt(dr * dr + dg * dg + db * db);
}
int main(void) {
{
const time_t seed = TimeOrExit(NULL);
printf("seed: %ld\n", seed);
srand((unsigned)seed);
}
const size_t numColors = 256;
const size_t numComponentsPerColor = 3;
const size_t numComponents = numColors * numComponentsPerColor;
uint8_t components[numComponents];
// We will ensure the first colors are these.
const uint8_t fixedComponents[] = {
0, 0, 0,
255, 255, 255,
0, 255, 0,
0, 0, 255,
255, 0, 0,
255, 255, 0,
255, 0, 255,
0, 255, 255};
// printf("sizeof(fixedComponents): %d\n", sizeof(fixedComponents));
if ((sizeof(fixedComponents) % numComponentsPerColor) != 0) {
fprintf(stderr, "Number of fixedComponents must be multiple of %zu.\n",
numComponentsPerColor);
exit(1);
}
const size_t numFixedColors =
sizeof(fixedComponents) / numComponentsPerColor;
for (size_t i = 0; i < sizeof(fixedComponents); i += 1) {
components[i] = fixedComponents[i];
}
// Initialize to random values that are not too close.
for (size_t c = numFixedColors; c < numColors; c += 1) {
// c is index of current color to generate.
const size_t maxTries = 400000;
size_t t;
for (t = 0; t < maxTries; t += 1) {
const uint8_t newR = (uint8_t)rand();
const uint8_t newG = (uint8_t)rand();
const uint8_t newB = (uint8_t)rand();
// Compare against existing colors for if too similar.
for (size_t k = 0; k < c; k += 1) {
if (k == c) {
continue;
}
const double difference = GetColorDifference(
newR, newG, newB,
components[k * numComponentsPerColor + 0],
components[k * numComponentsPerColor + 1],
components[k * numComponentsPerColor + 2]);
if (difference < 39.5) {
goto TryAgain;
}
}
// No conflict found. Break from retry loop after setting color.
components[c * numComponentsPerColor + 0] = newR;
components[c * numComponentsPerColor + 1] = newG;
components[c * numComponentsPerColor + 2] = newB;
break;
TryAgain:
}
assert(t <= maxTries);
if (t == maxTries) {
fprintf(stderr, "Ran out of tries.\n");
exit(1);
}
}
// // A sort, for looking at the colors sorted.
// #include <stdbool.h>
// for (size_t c = numFixedColors; c < numColors; c += 1) {
// for (size_t k = c + 1; k < numColors; k += 1) {
// const size_t ncpc = numComponentsPerColor;
//
// const bool swapBecauseR =
// (components[c * ncpc + 0] > components[k * ncpc + 0]);
// const bool swapBecauseG =
// (components[c * ncpc + 0] == components[k * ncpc + 0]) &&
// (components[c * ncpc + 1] > components[k * ncpc + 1]);
// const bool swapBecauseB =
// (components[c * ncpc + 0] == components[k * ncpc + 0]) &&
// (components[c * ncpc + 1] == components[k * ncpc + 1]) &&
// (components[c * ncpc + 2] > components[k * ncpc + 2]);
//
// if (swapBecauseR || swapBecauseG || swapBecauseB) {
// uint8_t temp;
//
// temp = components[c * ncpc + 0];
// components[c * ncpc + 0] = components[k * ncpc + 0];
// components[k * ncpc + 0] = temp;
//
// temp = components[c * ncpc + 1];
// components[c * ncpc + 1] = components[k * ncpc + 1];
// components[k * ncpc + 1] = temp;
//
// temp = components[c * ncpc + 2];
// components[c * ncpc + 2] = components[k * ncpc + 2];
// components[k * ncpc + 2] = temp;
// }
// }
// }
// Print colors.
for (size_t c = 0; c < numColors; c += 1) {
const int ret = printf("%3d, %3d, %3d,\n",
components[c * numComponentsPerColor + 0],
components[c * numComponentsPerColor + 1],
components[c * numComponentsPerColor + 2]);
if (ret < 0) {
exit(1);
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment