Convertisseur de couleurs RVB en Xterm

13

Les terminaux compatibles Xterm 256 couleurs ajoutent 240 couleurs aux 16 couleurs système habituelles. Les couleurs 16-231 utilisent 6 niveaux (0, 95, 135, 175, 215, 255) de rouge, vert et bleu, classés lexicographiquement. Les couleurs 232-255 sont simplement 24 niveaux de gris (8 ... 238 par 10s). Pour avoir une meilleure idée de ce dont je parle, consultez ce tableau .

Le défi

Votre objectif est de créer un programme ou une fonction qui prend en entrée des valeurs RVB et génère le nombre correspondant à la couleur Xterm la plus proche de cette valeur RVB. Étant donné que les 16 couleurs du système (couleurs 0-15) sont souvent personnalisables, vous les excluez de cette conversion.

Pour mieux définir la couleur "la plus proche", utilisez la distance Manhattan le long des composants rouge, vert et bleu. Par exemple, rgb(10, 180, 90)est à 20 unités rgb(0, 175, 95)(couleur 35) carabs(10 - 0) + abs(180 - 175) + abs(90 - 95) == 20 . Si la couleur d'entrée se situe également entre deux couleurs Xterm ou plus, sortez la couleur Xterm avec l'indice le plus élevé.

Exemples

 R   G   B     Xterm
  0   0   0 ==> 16
 95 135   0 ==> 64
255 255 255 ==> 231
238 238 238 ==> 255

 90 133 140 ==> 66
218 215 216 ==> 188
175 177 178 ==> 249

175   0 155 ==> 127
 75  75  75 ==> 239
 23  23  23 ==> 234
115 155 235 ==> 111

Règles

  • Les failles standard sont interdites
  • Votre programme ou fonction est autorisé à prendre des valeurs RVB dans n'importe quel format raisonnable, y compris:
    • Arguments séparés pour le rouge, le vert et le bleu
    • Une liste, un tuple, un dictionnaire ou similaire
    • Chaîne ou stdin séparé par un délimiteur
    • Couleurs hexagonales (par exemple #ff8000)
  • Vous pouvez supposer que toutes les valeurs r, g et b seront des entiers compris entre 0 et 255.
  • Étant donné que les 16 couleurs système doivent être exclues du mappage, toutes les sorties doivent être comprises entre 16 et 255.

C'est le , donc le code le plus court l'emporte.

Beefster
la source

Réponses:

4

Haskell , 132 octets

v=0:[95,135..255]
f c=snd$maximum[(-sum(abs<$>zipWith(-)c x),i)|(i,x)<-zip[16..]$[[r,g,b]|r<-v,g<-v,b<-v]++[[g,g,g]|g<-[8,18..238]]]

Essayez-le en ligne!

Prend l'entrée comme une liste d'entiers [red, green, blue] .

Mise en œuvre assez simple. Tout d'abord, je construis une liste des couleurs Xterm que nous utilisons avec deux listes de compréhension concaténées ensemble. La première gère les couleurs 16-231 par triple itération sur vlaquelle contiennent les valeurs utilisées par ces couleurs. Le second itère simplement les valeurs de gris et les place dans les trois emplacements. Ensuite, je l'indexer avec zip (à partir de 16) et faire une paire avec la distance de manhattan (nié) et cet index et prendre le maximum. J'ai utilisé le maximum parce que nous sommes en train de briser l'égalité sur le plus grand indice et cela me fait gagner un extra -.

user1472751
la source
3

Ruby , 280 180 166 164 155 octets

->c{d=0,95,135,175,215,255
a=(0..239).map{|n|n<216?[d[n/36],d[(n%36)/6],d[n%6]]:[n*10-2152]*3}.map{|t|t.zip(c).map{|a,b|(a-b).abs}.sum}
a.rindex(a.min)+16}

Essayez-le en ligne!

Un lambda prenant la couleur d'entrée comme un tableau d'entiers.

J'ai eu plus de mal à générer les couleurs Xterm que prévu! Je suis prêt à être modestement embarrassé dans ce domaine. J'ai utilisé la conversion de base comme une sorte de compression, mais la seule façon de le faire dans Ruby est de passer parInteger#to_s ce qui est un peu gênant.

-100 octets: lisez le problème plus attentivement et ignorez les 16 couleurs système ^ _ ^;

-14 octets: utilisez la conversion de base manuelle au lieu de .to_s(6)

-2 octets: ignorer les crochets lors de la déclaration du tableau

-9 octets: créez une liste de couleurs Xterm avec une seule map; cela enregistre également un signe plus et une paire de parens.

->c{
  d=0,95,135,175,215,255                 # d is the set of possible RGB values
  a=(0..239).map{|n|                     # Create the array of Xterm triplets
    n<216 ? [d[n/36],d[(n%36)/6],d[n%6]] # Convert x from base 6 to base d, or
          : [n*10-2152]*3                #   create a uniform triplet
  }.map{|t|
    t.zip(c).map{|a,b|(a-b).abs}.sum     # Map from triplets to Manhattan distance
  }
  a.rindex(a.min) +                      # Find the last index of the lowest distance
  16                                     # Offset for the exluded system colors
}
benj2240
la source
1
BTW, vous n'avez pas besoin de mapper aux 16 couleurs du système. Je devrais peut-être clarifier cela dans la description.
Beefster
Ooh, ça va m'aider un peu! J'ai certainement manqué cela dans le libellé de la question d'origine.
benj2240
1

Kotlin , 299 290 267 265 octets

(16..255).associate{it to if(it<232)(it-16).let{i->listOf(0,95,135,175,215,255).let{l->listOf(l[i/36],l[(i/6)%6],l[i%6])}}else(8..238 step 10).toList()[it-232].let{listOf(it,it,it)}}.minBy{(k,v)->(it.zip(v).map{(a,b)->kotlin.math.abs(a-b)}.sum()*256)+(256-k)}!!.key

Embellie

(16..255).associate {
    it to if (it < 232) (it - 16).let { i ->
            listOf(0, 95, 135, 175, 215, 255).let { l ->
                listOf(
                        l[i / 36],
                        l[(i / 6) % 6],
                        l[i % 6])
            }
        } else (8..238 step 10).toList()[it - 232].let { listOf(it, it, it) }
}.minBy { (k, v) ->
    (it.zip(v).map { (a, b) -> kotlin.math.abs(a - b) }.sum() * 256) + (256 - k)
}!!.key

Tester

data class Test(val r: Int, val g: Int, val b: Int, val out: Int)

val test = listOf(
        Test(0, 0, 0, 16),
        Test(95, 135, 0, 64),
        Test(255, 255, 255, 231),
        Test(238, 238, 238, 255),

        Test(90, 133, 140, 66),
        Test(218, 215, 216, 188),
        Test(175, 177, 178, 249),

        Test(175, 0, 155, 127),
        Test(75, 75, 75, 239),
        Test(23, 23, 23, 234),
        Test(115, 155, 235, 111)
)
fun z(it:List<Int>): Int =
(16..255).associate{it to if(it<232)(it-16).let{i->listOf(0,95,135,175,215,255).let{l->listOf(l[i/36],l[(i/6)%6],l[i%6])}}else(8..238 step 10).toList()[it-232].let{listOf(it,it,it)}}.minBy{(k,v)->(it.zip(v).map{(a,b)->kotlin.math.abs(a-b)}.sum()*256)+(256-k)}!!.key

fun main(args: Array<String>) {
    for (i in test) {
        val r = z(listOf(i.r, i.g, i.b))
        println("$i ${i.out} ==> $r")
    }
}

TIO

TryItOnline

jrtapsell
la source
1

Lot, 266 octets

@set/ax=15,m=999
@set s=for %%b in (0 95 135 175 215 255)do @
@%s:b=r%%s:b=g%%s%call:c %* %%r %%g %%b
@for /l %%g in (8,10,238)do @call:c %* %%g %%g %%g
@echo %n%
:c
@set/ax+=1,r=%4-%1,g=%5-%2,b=%6-%3
@set/ad=%r:-=%+%g:-=%+%b:-=%
@if %d% leq %m% set/an=x,m=d
Neil
la source
1

C (gcc), 202192157501 (141 buggé) 138 134 octets

l,m,t,i;a(c,x){x=abs(c-=i>215?i*10-2152:x*40+!!x*55);}f(r,g,b){for(i=l=240;i--;t=a(r,i/36)+a(g,i/6%6)+a(b,i%6),t<l?l=t,m=i:1);i=m+16;}

Merci @ceilingcat

Essayez-le en ligne!

PrincePolka
la source
1
Le problème n'est pas défini par les tests (qui sont clairement étiquetés comme exemples), veuillez donc ajouter un nouveau test à la place.
Ton Hospel
1
@TonHospel J'ai corrigé le bogue maintenant et réduit -3 octets, mais merci pour la réponse
PrincePolka