Convertidor de color RGB a Xterm

13

Los terminales compatibles con Xterm de 256 colores añaden 240 colores además de los 16 colores habituales del sistema. Los colores 16-231 usan 6 niveles (0, 95, 135, 175, 215, 255) de rojo, verde y azul, ordenados lexicográficamente. Los colores 232-255 son simplemente 24 niveles de gris (8 ... 238 por 10s). Para tener una mejor idea de lo que estoy hablando, vea esta tabla .

El reto

Su objetivo es hacer un programa o función que tome, como entrada, valores rgb y genere el número correspondiente con el color Xterm más cercano a ese valor rgb. Dado que los 16 colores del sistema (colores 0-15) a menudo son personalizables, los excluirá de esta conversión.

Para definir mejor cuál es el color "más cercano", use la distancia de Manhattan a lo largo de los componentes rojo, verde y azul. Por ejemplo, rgb(10, 180, 90)está a 20 unidades dergb(0, 175, 95) (color 35) porque abs(10 - 0) + abs(180 - 175) + abs(90 - 95) == 20. Si el color de entrada es igual entre dos o más colores Xterm, envíe el color Xterm con el índice más alto.

Ejemplos

 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

Reglas

  • Las lagunas estándar están prohibidas
  • Su programa o función puede tomar valores rgb en cualquier formato razonable, incluyendo:
    • Argumentos separados para rojo, verde y azul.
    • Una lista, tupla, diccionario o similar.
    • Cadena separada por delimitador o stdin
    • Colores hexadecimales (p #ff8000. Ej. )
  • Puede suponer que todos los valores r, g y b serán enteros entre 0 y 255.
  • Dado que los 16 colores del sistema deben excluirse de la asignación, todas las salidas deben estar en el rango de 16 ... 255.

Este es el , por lo que gana el código más corto.

Carne de res
fuente

Respuestas:

4

Haskell , 132 bytes

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]]]

Pruébalo en línea!

Toma la entrada como una lista de enteros [red, green, blue].

Implementación bastante sencilla. Primero construyo una lista de los colores Xterm que estamos usando con dos comprensiones de listas concatenadas juntas. El primero de los cuales maneja los colores 16-231 por iteración triplev que contiene los valores que usan esos colores. El segundo solo itera sobre los valores grises y los coloca en los tres espacios. Luego lo indexo con zip (a partir de 16) y hago un par con la distancia de Manhattan (negada) y ese índice y tomo el máximo. Usé el máximo porque estamos rompiendo el desempate en el índice más grande y de esta manera me ahorro uno extra -.

usuario1472751
fuente
3

Rubí , 280 180 166 164 155 bytes

->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}

Pruébalo en línea!

Una lambda que toma el color de entrada como una matriz de enteros.

¡Tuve más problemas para generar los colores Xterm de lo que esperaba! Estoy preparado para ser superado vergonzosamente modestamente en esa área. Utilicé la conversión base como una especie de compresión, pero la única forma en que sé hacerlo en Ruby es a través deInteger#to_s que es un poco incómodo.

-100 bytes: lea el problema con más cuidado e ignore los 16 colores del sistema ^ _ ^;

-14 bytes: utilice la conversión de base manual en lugar de .to_s(6)

-2 bytes: omite los corchetes al declarar la matriz

-9 bytes: crea una lista de colores Xterm con solo uno map; Esto también guarda un signo más y un par 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
fuente
1
Por cierto, no es necesario asignar a los 16 colores del sistema. Tal vez debería aclarar eso en la descripción.
Beefster
¡Oh, eso me ayudará bastante! Definitivamente me perdí eso en la redacción de la pregunta original.
benj2240
1

Kotlin , 299 290 267 265 bytes

(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

Embellecido

(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

Prueba

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
fuente
1

Lote, 266 bytes

@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
fuente
1

Stax , 41 bytes

¬ÿ▒ú╘Σt∙Æ9φ☻ùí&BQq═IÜH∩Å╧♥f⌠óH]╨⌡≤@■Q‼Hr¼

¡Ejecute y depure en línea!

Versión ASCII de 50 bytes:

"4GOW_g"{52-5*m3|^24{A*vv]3*m+{;\{E:-m|+mc|m|IH16+
Weijun Zhou
fuente
1

C (gcc) 202 192 157 150 (141 con errores) 138 134 bytes

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;}

Gracias @ceilingcat

Pruébalo en línea!

PrincePolka
fuente
1
El problema no está definido por las pruebas (que están claramente etiquetadas como ejemplos), por lo tanto, agregue una nueva prueba en su lugar.
Ton Hospel
1
@TonHospel Arreglé el error ahora y reduje -3 bytes, pero gracias por la respuesta
PrincePolka