Convert arbitrary string to color consistently

Share your scripts and packages with other Mudlet users.
Post Reply
User avatar
demonnic
Posts: 884
Joined: Sat Dec 05, 2009 3:19 pm

Convert arbitrary string to color consistently

Post 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
Capture.PNG (10.94 KiB) Viewed 6365 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)
  end))
end

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)
    else
      table.insert(part2, value)
    end
  end
  local newStr = string.reverse(table.concat(part1)) .. table.concat(part2)
  -- end munging of the original string to get more uniqueness
  math.randomseed(string.cut(string.tobyte(newStr),18))
  local r = math.random(0,255)
  local g = math.random(0,255)
  local b = math.random(0,255)
  math.randomseed(os.time())
  return {r,g,b}
end

function colorMungeEcho(strForColor, strToEcho)
  local color = "<" .. table.concat(string.tocolor(strForColor), ",") .. ">"
  decho(color .. strToEcho .. "\n")
end
And finally an attachment.
Attachments
string_to_color.xml
(1.7 KiB) Downloaded 356 times

User avatar
demonnic
Posts: 884
Joined: Sat Dec 05, 2009 3:19 pm

Re: Convert arbitrary string to color consistently

Post 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

User avatar
demonnic
Posts: 884
Joined: Sat Dec 05, 2009 3:19 pm

Re: Convert arbitrary string to color consistently

Post 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

User avatar
demonnic
Posts: 884
Joined: Sat Dec 05, 2009 3:19 pm

Re: Convert arbitrary string to color consistently

Post 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.

Post Reply