Encontre a cor hexagonal de três dígitos mais próxima


23

No CSS, as cores podem ser especificadas por um "trigêmeo hexadecimal" - um número hexadecimal de três bytes (seis dígitos) em que cada byte representa os componentes vermelho, verde ou azul da cor. Por exemplo, #FF0000é completamente vermelho e é equivalente a rgb(255, 0, 0).

As cores também podem ser representadas pela notação abreviada que usa três dígitos hexadecimais. A abreviação se expande para o formato de seis dígitos duplicando cada dígito. Por exemplo, #ABCtorna-se #AABBCC.

Como há menos dígitos na abreviação hexadecimal, menos cores podem ser representadas.

O desafio

Escreva um programa ou função que utilize um código de cores hexadecimal de seis dígitos e produz o código de cores de três dígitos mais próximo.

Aqui está um exemplo:

  • Código hexadecimal de entrada: # 28a086
  • Componente vermelho
    • 0x28 = 40 (decimal)
    • 0x22 = 34
    • 0x33 = 51
    • 0x22 está mais próximo, então o primeiro dígito do código de cor abreviado é 2
  • Componente verde
    • 0xa0 = 160
    • 0x99 = 153
    • 0xaa = 170
    • 0x99 está mais próximo, então o segundo dígito é 9
  • Componente azul
    • 0x86 = 134
    • 0x77 = 119
    • 0x88 = 136
    • 0x88 está mais próximo, então o terceiro dígito é 8
  • O código de cor reduzido é # 298 (que se expande para # 229988)

Seu programa ou função deve aceitar como entrada um código de cores hexadecimal de seis dígitos anexado #e gerar um código de cores de três dígitos anexado #.

Exemplos

  • # FF0000 → # F00
  • # 00FF00 → # 0F0
  • # D913C4 → # D1C
  • # C0DD39 → # BD3
  • # 28A086 → # 298
  • # C0CF6F → # BC7

Pontuação

Este é um desafio do código-golfe, por isso vence a resposta mais curta do seu idioma! Aplicam-se regras padrão.


1
"somando a diferença entre cada componente do código de cores completo e o componente correspondente do código de cores abreviado" - esta parte é confusa. Não há como adicionar em lugar algum, certo?
Grzegorz Oledzki 28/06

3
Observe que, se você simplesmente soltar dígitos alternativos, cada cor curta representa um número igual de cores completas, para que possa ser considerado uma representação melhor do que a cor mais próxima.
Neil

6
Vi isso na Sandbox, mas esqueci de mencionar que não acho que a exigência de #adicionar algo ao desafio.
Shaggy

2
Podemos produzir em minúsculas?
Arnauld

2
0x22 é 34, não 30
Kruga 01/07

Respostas:



8

05AB1E , 13 bytes

ćs2ôH8+17÷hJ«

Experimente online!

Quão?

ćs2ôH8+17÷hJ« | string, S   e.g. stack: "#B23F08"
ć             | decapitate              "B23F08", "#"
 s            | swap                    "#", "B23F08"
  2           | two                     "#", "B23F08", 2
   ô          | chuncks                 "#", ["B2", "3F", "08"]
    H         | from hexadecimal        "#", [178, 63, 8]
     8        | eight                   "#", [178, 63, 8], 8
      +       | add                     "#", [186, 71, 16]
       17     | seventeen               "#", [186, 71, 16], 17
         ÷    | integer divide          "#", [10, 4, 0]
          h   | to hexadecimal          "#", ["A", "4", "0"]
           J  | join                    "#", "A40"
            « | concatenate             "#A40"
              | print top of stack

1
Também pensei em fazer a resposta N 05AB1E - a menos que eu tenha perdido alguma coisa, a conversão hexadecimal no Jelly leva muitos bytes!
Nick Kennedy

1
Sim, não há built-in para conversões básicas de texto no Jelly.
Jonathan Allan

1
" ćdecapitar " Essa é outra maneira de descrevê-lo, lol. : D Boa resposta, porém, +1 de mim.
Kevin Cruijssen

6

Japonês , 16 bytes

r"%w"²_n16_r17Ãg

Experimente ou execute todos os casos de teste

r"%w"²_n16_r17Ãg     :Implicit input of string
r                    :Replace
 "%w"                :RegEx /\w/g
     ²               :Duplicate, giving /\w\w/g
      _              :Pass each match through a function
       n16           :  Convert to decimal
          _          :  Pass through the following function, and convert back to hex
           r17       :    Round to the nearest multiple of 17
              Ã      :  End function
               g     :  Get first character

5

Conjunto 8088, IBM PC DOS, 59. 58 bytes

Listagem desmontada:

BE 0082     MOV  SI, 82H    ; SI to begining of input string 
AC          LODSB           ; load first '#' char into AL 
B4 0E       MOV  AH, 0EH    ; BIOS display char function  
CD 10       INT  10H        ; call BIOS 
B3 11       MOV  BL, 17     ; set up for divide by 17 
B9 0304     MOV  CX, 0304H  ; hex byte loop counter (CH=3), shift counter (CL=4) 
        LOOP_BYTE: 
AD          LODSW           ; load next two ASCII hex chars into AX 
B7 02       MOV  BH, 2      ; hex chars loop counter
        LOOP_ALPHA:
2C 30       SUB  AL, '0'    ; convert from ASCII 
3C 0A       CMP  AL, 10     ; is digit > 10 (A-F)? 
7C 02       JL   NOT_ALPHA  ; if not, jump to next char
2C 07       SUB  AL, 7      ; ASCII adjust alpha char to binary 
        NOT_ALPHA: 
86 E0       XCHG AH, AL     ; swap first and second chars 
FE CF       DEC  BH         ; decrement loop counter
75 F2       JNZ  LOOP_ALPHA ; loop to next hex char
D2 E0       SHL  AL, CL     ; shift low nibble to high nibble 
02 C4       ADD  AL, AH     ; add first and second nibbles
32 E4       XOR  AH, AH     ; clear AH for add/division
05 0008     ADD  AX, 8      ; add 0.5 (8/16) to round (with overflow) 
F6 F3       DIV  BL         ; divide by 17 
3C 0A       CMP  AL, 10     ; is digit > 10? 
7C 02       JL   DISP_CHAR  ; if not, jump to display digit 
04 07       ADD  AL, 7      ; binary adjust alpha char to ASCII 
        DISP_CHAR: 
04 30       ADD  AL, '0'    ; convert to ASCII 
B4 0E       MOV  AH, 0EH    ; BIOS display char function  
CD 10       INT  10H        ; call BIOS 
FE CD       DEC  CH         ; decrement loop counter 
75 D4       JNZ  LOOP_BYTE  ; loop to next hex byte
C3          RET             ; return to DOS 

Executável autônomo do PC DOS. A entrada é via linha de comando, a saída é para o console.

A maior parte do comprimento do código está lidando com a conversão da E / S da cadeia hexadecimal necessária em bytes, pois o código de máquina DOS / x86 não possui recursos internos para isso.

E / S:

insira a descrição da imagem aqui

Faça o download e teste o HEXCLR.COM ou xxdhexdump:

0000000: be82 00ac b40e cd10 b311 b904 03ad b702  ................
0000010: 2c30 3c0a 7c02 2c07 86e0 fecf 75f2 d2e0  ,0<.|.,.....u...
0000020: 02c4 32e4 0508 00f6 f33c 0a7c 0204 0704  ..2......<.|....
0000030: 30b4 0ecd 10fe cd75 d4c3                 0......u..

3

Retina 0.8.2 , 88 bytes

(\w)(.)
$1,$2;
[A-F]
1$&
T`L`d
\d+
$*
+`1,
,16$*
,
8$*
(1{17})*1*;
$#1;
T`d`L`1\d
B\B|;

Experimente online! O link inclui casos de teste. Explicação:

(\w)(.)
$1,$2;

Emparelhe os dígitos hexadecimais.

[A-F]
1$&
T`L`d

Converta cada dígito separadamente em decimal.

\d+
$*

Converta cada dígito decimal em unário.

+`1,
,16$*

Conclua a conversão hexadecimal do par de dígitos.

,
8$*
(1{17})*1*;
$#1;

Adicione 8 e divida por 17.

T`d`L`1\d
B\B|;

Converta de volta para hexadecimal.






2

Wolfram Language (Mathematica) , 63 48 bytes

"#"<>Round[15List@@RGBColor@#]~IntegerString~16&

Experimente online!

-15 bytes graças a attinat ! Substituindo StringJoincom <>e comprimindo a sintaxe.

  1. RGBColor@#converte a sequência de entrada em uma cor do formulário RGBColor[r, g, b]com três argumentos de ponto flutuante no intervalo 0..1.

  2. Round[15 List @@ %]multiplica a lista de três argumentos por 15 e os arredonda para o número inteiro mais próximo. Agora temos uma lista de três valores inteiros correspondentes aos três dígitos hexadecimais desejados.

  3. %~IntegerString~16 converte essa lista de três números inteiros em uma lista de três seqüências hexadecimais de um caractere cada.

  4. "#"<>%precede um #caractere e une todos esses caracteres.



2

MathGolf , 19 12 bytes

╞2/¢8+F/¢'#▌

Saída como lista de caracteres. Se isso não for permitido, um rastreamento adicionaly adicional para associar a lista de caracteres a uma sequência.

-7 bytes graças a @maxb , desde que eu olhei além de um builtin ( 2ô_2<\1>]para 2/).

Experimente online.

Explicação:

              # Remove the first character from the (implicit) input-string
 2/            # Split the string into parts of size 2
   ¢           # Convert each part from hexadecimal to integer
    8+         # Add 8 to each integer
      F/       # Integer-divide each integer by 17
        ¢      # Then convert back from integer to hexadecimal
         '#▌  '# Prepend '#' in front of the list
               # (which is output implicitly as result)

2

Ruby (2.5.3), 45 , 44 , 42 bytes

->a{a.gsub(/\w./){|b|"%X"%((8+b.hex)/17)}}

EDIT: salvou um byte porque não precisamos de um grupo de caracteres para o segundo caractere na regex (inspirado na resposta de Neil)

EDIT 2: salvou 2 bytes porque a sintaxe lambda do dash rocket não precisa de colchetes ao redor do argumento


2
Você pode salvar 7 bytes inserindo stdin e usando o -psinalizador e outros 2 usando em $&vez de um argumento dentro do bloco: tio.run/##KypNqvz/…
Jordan

1
@Jordan Thanks! Eu não sabia sobre nenhum deles, então isso é uma ajuda real para futuras tentativas de golfe
DaveMongoose 03/07

1

Python 2 ( 109 101 97 85 83 74 bytes)

lambda x:'#'+''.join(hex(int(int(x[i:i+2],16)/17.+.5))[2:]for i in[1,3,5])

A "distância mais próxima" é tratada pela divisão por 17 e arredondamento.

Melhorias:

-8 bytes usando o int(...+.5)truque em vez deint(round(...))

-4 bytes usando a compreensão da lista em vez de map()

-1 byte por codificação # na saída (obrigado @movatica)

-10 bytes por não usar re.findall("..",...) favor da emenda explícita de String

-2 bytes por não usar a compreensão da lista, mas uma expressão de gerador embutido em join (obrigado @movatica)

-1 byte, sem emendar o :7 final da parte azul

-9 bytes por melhor iteração sobre cores - ou seja, iterando sobre índices, não caracteres reais (obrigado @movatica)


1
@movatica - você está certo, acrescentou
Grzegorz Oledzki 28/06

1
Economize 1 byte codificando em '#'vez de x[0].
movatica 28/06

1
Você pode pular a compreensão da lista ''.join(...), pois ela também lida com uma expressão geradora. Basta remover o []e salvar mais 2 bytes :)
movatica 28/06

1
Obrigado! range(1,6,2)é ainda melhor com[1,3,5]
Grzegorz Oledzki 28/06

1
Jonathan Allen propôs um truque diferente para arredondar na versão mz Pzthon3. Também se aplica aqui: lambda x:'#'+''.join(hex((int(x[i:i+2],16)+8)/17)[2:]for i in[1,3,5])-> 69 bytes
movatica

1

Perl 5 -p , 35 34 bytes

@nwellnhof salvou um byte

s|\w.|sprintf'%X',.5+(hex$&)/17|ge

Experimente online!

Lê de STDIN, substitui cada par de itens que não #possui o caractere único apropriado, usando o método de divisão por 17 para encontrar o mais próximo e, em seguida, gera implicitamente ( -p) o resultado.


1

Python 3, 67 bytes

f=lambda x:(f(x[:-2])if x[3:]else"#")+f'{(int(x[-2:],16)+8)//17:X}'

Bem vinda. Considere adicionar uma descrição, explicação ou link para um intérprete online, como o TIO, onde podemos executar seu código. As respostas somente de código tendem a ser sinalizadas automaticamente como de baixa qualidade. Veja outras respostas existentes para exemplos.
mbomb007 5/07

0

Vermelho , 103 bytes

func[c][r: to 1 c to #1 rejoin reverse collect[loop 3[keep to-hex/size r % 256 + 8 / 17 1 r: r / 256]]]

Experimente online!

Descobriu-se que a versão atual do Red do Linux não tem uma implementação da hex-to-rgbfunção, é por isso que eu faço a conversão básica "manualmente" :)

Isso funciona bem no console da GUI vermelha no Windows:

Vermelho , 94 bytes

f: func[c][r: hex-to-rgb c to #1 rejoin collect[repeat n 3[keep to-hex/size r/:n + 8 / 17 1]]]


0

Carvão , 22 bytes

#F⪪⮌…⮌S⁶¦²⍘÷⁺⁸⍘ι¹⁶¦¹⁷φ

Experimente online! Link é a versão detalhada do código. Explicação:

#                       Literal `#`
      S                 Input string
     ⮌                  Reversed
    …  ⁶                Truncated to length 6
   ⮌                    Reversed
  ⪪      ²              Split into pairs of characters
 F                      Loop over each pair
               ι        Current pair
              ⍘ ¹⁶      Convert from base 16
            ⁺⁸          Add 8
           ÷       ¹⁷   Integer divide by 17
          ⍘          φ  Convert to large base
                        Implicitly print


0

Pitão , 20 bytes

+\#sm.H/+8id16 17c3t

Experimente aqui.

NOTA: Caso o link acima apresente um ImportError, vá aqui ; atualmente existe um erro na página "oficial" e esta é uma solução temporária da Maltysen . Esse link pode parar de funcionar depois que o oficial for corrigido.


0

Quarto (gforth) , 87 bytes

: f d>s 1- hex ." #"3. do 2 + dup 2 s>number d>s 17 /mod swap 8 > - 1 .r loop decimal ;

Experimente online!

Explicação

  1. Ignorar / truncar o primeiro caractere de input ( #)
  2. Defina o intérprete para o modo hexadecimal
  3. Saída #
  4. Faça um loop 3 vezes, em cada loop:
    1. Adicione 2 ao endereço inicial da string
    2. Converter os próximos 2 caracteres da string em um número hexadecimal
    3. Use a divisão e o módulo até 17 (0x11 ) para obter o valor mais próximo para o componente reduzido
    4. Saída sem espaço anterior
  5. Coloque o intérprete de volta no modo decimal

Código Explicação

: f                    \ start a new word definition
  d>s                  \ convert double-length int to single-length (cheaper drop)
  1- hex               \ subtract 1 from string address, set current base to 10
  ." #"                \ output #
  3. do                \ start a loop from 0 to 2 (inclusive)
    2 + dup            \ add 2 to string starting address and duplicate
    2 s>number         \ parse the next 2 characters to a hexadecimal value
    d>s                \ convert result to single-length value
    17 / mod           \ get the quotient and remainder of dividing by 17
    swap               \ move the remainder to the top of the stack
    8 > -              \ if remainder is greater than 8, add 1 to quotient
    1 .r               \ output result (as hexadecimal) with no space
  loop                 \ end the loop
  decimal              \ set interpreter back to base 10 (decimal)
;                      \ end the word definition


0

K4 , 39 bytes

Solução:

"#",{x@_1%17%8+16/:x?y}[.Q.nA]@/:3 2#1_

Explicação:

Usa a mesma estratégia que muitas dessas respostas (por exemplo, adicione 8, divida por 17):

"#",{x@_1%17%8+16/:x?y}[.Q.nA]@/:3 2#1_ / the solution
                                     1_ / drop first character
                                 3 2#   / reshape as 3x2 (e.g. "FF", "00", "00")
                              @/:       / apply each-right to left lambda
    {                 }[     ]          / lambda with first argument populated
                        .Q.nA           / "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                   x?y                  / get index of hex character, e.g. "AA" => 10 10
               16/:                     / convert from base-16
             8+                         / add 8
          17%                           / 17 divided by...
        1%                              / 1 divided by...
       _                                / floor
     x@                                 / index into .Q.nA to get hex character
"#",                                    / prepend "#"

Extra:

  • "#",{x@*16\:a?&/a:abs(17*!16)-16/:x?y}[.Q.nA]@/:3 2#1_- minha ideia original por 54 bytes
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.