RGB zu Xterm Farbkonverter

13

Xterm-kompatible Terminals mit 256 Farben bieten 240 Farben zusätzlich zu den üblichen 16 Systemfarben. In den Farben 16-231 werden 6 Stufen (0, 95, 135, 175, 215, 255) von Rot, Grün und Blau verwendet, die lexikographisch geordnet sind. Bei den Farben 232-255 handelt es sich einfach um 24 Graustufen (8 ... 238 x 10s). Um eine bessere Vorstellung davon zu bekommen, wovon ich spreche, sehen Sie sich diese Tabelle an .

Die Herausforderung

Ihr Ziel ist es, ein Programm oder eine Funktion zu erstellen, die als Eingabe RGB-Werte verwendet und die Zahl ausgibt, die der diesem RGB-Wert am nächsten liegenden XTerm-Farbe entspricht. Da die 16 Systemfarben (Farben 0-15) häufig anpassbar sind, schließen Sie sie von dieser Konvertierung aus.

Verwenden Sie den Manhattan-Abstand entlang der roten, grünen und blauen Komponenten, um die "nächstgelegene" Farbe besser zu definieren . Zum Beispiel rgb(10, 180, 90)ist 20 Einheiten von rgb(0, 175, 95)(Farbe 35) entfernt, weil abs(10 - 0) + abs(180 - 175) + abs(90 - 95) == 20. Wenn die Eingabefarbe zwischen zwei oder mehr Xterm-Farben gleich ist, geben Sie die Xterm-Farbe mit dem höchsten Index aus.

Beispiele

 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

Regeln

  • Standardlücken sind verboten
  • Ihr Programm oder Ihre Funktion darf RGB-Werte in jedem vernünftigen Format annehmen, einschließlich:
    • Separate Argumente für Rot, Grün und Blau
    • Eine Liste, ein Tupel, ein Wörterbuch oder Ähnliches
    • Durch Trennzeichen getrennte Zeichenfolge oder stdin
    • Hex Farben (zB #ff8000)
  • Sie können davon ausgehen, dass alle Werte für r, g und b ganze Zahlen zwischen 0 und 255 sind.
  • Da die 16 Systemfarben von der Abbildung ausgeschlossen werden sollen, sollten alle Ausgänge im Bereich 16 ... 255 liegen.

Das ist , also gewinnt der kürzeste Code.

Beefster
quelle

Antworten:

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

Probieren Sie es online!

Nimmt die Eingabe als Liste von ganzen Zahlen [red, green, blue].

Ziemlich unkomplizierte Implementierung. Zuerst erstelle ich eine Liste der Xterm-Farben, die wir verwenden, mit zwei zusammen verketteten Listenverständnissen. Der erste behandelt die Farben 16-231 durch dreifache Iteration, vdie die Werte enthält, die diese Farben verwenden. Der zweite iteriert nur über die Grauwerte und fügt sie in alle drei Slots ein. Dann indexiere ich es mit zip (beginnend bei 16) und bilde ein Paar mit der Manhattan-Distanz (negiert) und diesem Index und nehme das Maximum. Ich habe Maximum verwendet, weil wir den größten Index brechen und mir auf diese Weise einen zusätzlichen ersparen -.

user1472751
quelle
3

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

Probieren Sie es online!

Ein Lambda, das die Eingabefarbe als Array von Ganzzahlen verwendet.

Ich hatte mehr Probleme, die Xterm-Farben zu erzeugen, als ich erwartet hatte! Ich bin bereit, in diesem Bereich peinlich bescheiden überfordert zu sein . Ich habe die Basiskonvertierung als eine Art Komprimierung verwendet, aber der einzige Weg, den ich in Ruby kenne, ist durchInteger#to_s der, der etwas umständlich ist.

-100 Byte: Lesen Sie das Problem genauer durch und ignorieren Sie die 16 Systemfarben ^ _ ^;

-14 Bytes: Verwenden Sie die Basisumwandlung anstelle von .to_s(6)

-2 Bytes: Überspringen Sie eckige Klammern, wenn Sie ein Array deklarieren

-9 Bytes: Erstellt eine Liste von Xterm-Farben mit nur einer map; Dies spart auch ein Pluszeichen und ein Paar 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
quelle
1
Übrigens müssen Sie nicht auf die 16 Systemfarben abbilden. Vielleicht sollte ich das in der Beschreibung klarer machen.
Beefster
Oh, das wird mir einiges helfen! Das habe ich in der ursprünglichen Fragestellung definitiv verpasst.
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

Verschönert

(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

Prüfung

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

Batch, 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
quelle
1

Stax , 41 Bytes

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

Online ausführen und debuggen!

ASCII-Version von 50 Bytes:

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

C (gcc), 202 192 157 150 (141 abgehört) 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;}

Vielen Dank @ceilingcat

Probieren Sie es online!

PrincePolka
quelle
1
Das Problem wird durch die Tests (die eindeutig als Beispiele gekennzeichnet sind) nicht definiert. Lassen Sie sich stattdessen einen neuen Test hinzufügen.
Ton Hospel
1
@TonHospel Ich habe den Fehler behoben und -3 Bytes reduziert, aber danke für die Antwort
PrincePolka