Page 1 of 1

Convert arbitrary string to color consistently

Posted: Fri Jun 14, 2019 7:15 pm
by demonnic
Someone on discord today asked for a way to colour the names of characters consistently and uniquely. To that end I've created a script that takes a string and converts it to a color table ( { r,g,b } ) using the ascii values for the characters inside the string as the seed to lua's random number generator, then uses that to generate the red/green/blue values. Then I set the seed to os.time() (as a decentish default) so we're not accidentally giving people a way to manipulate our random numbers.

So to get the color table for my name "demonnic", you would use string.tocolor("demonnic")
I also provide colorMungeEcho() as a function to show one potential use for this, taking one string to determine the color (for instance, the name of the person who sent you a message) and another string to echo out in the color set by the first.

Here's the example function in action:
Capture.PNG (10.94 KiB) Viewed 2295 times

Here's the code itself, if you want to copypasta:
Code: [show] | [select all] lua

function string.tobyte(str)
  return (str:gsub('.', function (c)
	  return string.byte(c)

function string.tocolor(str)
  -- This next bit takes the string and 'unshuffles' it, breaking it into odds and evens
  -- reverses the evens, then adds the odds to the new even set. So demonnic becomes cnoedmni
  -- this makes sure that names which are similar in the beginning don't color the same
  -- especially since we have to cut the number for the random seed due to OSX using a default
  -- randomseed if you feed it something too large, which made every name longer than 7 characters
  -- always the same color, no matter what it was.
  local strTable = {}
  local part1 = {}
  local part2 = {}
  str:gsub(".",function(c) table.insert(strTable,c) end)
  for index,value in ipairs(strTable) do
    if (index % 2 == 0) then
      table.insert(part1, value)
      table.insert(part2, value)
  local newStr = string.reverse(table.concat(part1)) .. table.concat(part2)
  -- end munging of the original string to get more uniqueness
  local r = math.random(0,255)
  local g = math.random(0,255)
  local b = math.random(0,255)
  return {r,g,b}

function colorMungeEcho(strForColor, strToEcho)
  local color = "<" .. table.concat(string.tocolor(strForColor), ",") .. ">"
  decho(color .. strToEcho .. "\n")
And finally an attachment.

Re: Convert arbitrary string to color consistently

Posted: Fri Jun 14, 2019 7:53 pm
by demonnic
To use with selectString() and the like:
Code: [show] | [select all] lua
local colors = string.tocolor(matches[2])
-- select what you want to color based on matches[2] between these lines
setBgColor(colors[1], colors[2], colors[3])
-- don't forget to deselect() and resetFormat() when done

Re: Convert arbitrary string to color consistently

Posted: Sat Jun 15, 2019 7:33 pm
by demonnic
A flaw has been discovered with used on OSX where anything over 7 characters generates the same colour. I'll have the fix posted a little later

Re: Convert arbitrary string to color consistently

Posted: Sun Jun 16, 2019 12:35 am
by demonnic
Ok, I updated the xml and code in the original post with the fix. I now take the string which is fed in and munge it up a bit. I break it into even and odd parts, then reverse the even part, add the odd part onto the end, and use the new string to generate the random seed. This is because it was found on OSX that if you give math.randomseed too high a value, it uses the same default every time. This was causing anything over 7 characters long to return the exact same color. So I munge up the string, use that, and then cut the resulting seed down to 18 characters.

This new method means you'll get new colors for things greater than eight characters. I've only noticed one weird thing where "Demonnic1" and "Demonnic12" produce the same color... and it doesn't seem to matter if I use 2 or any other character. "Demonnic123" is once again a different color. I think it might be that the first 7 or 8 characters of the resulting munged word are the same at those two lengths, and have decided that this small edge case is acceptable for now.