Найти ближайший трехзначный шестнадцатеричный цвет

23

В CSS цвета могут быть определены «шестнадцатеричным триплетом» - трехбайтовым (шестизначным) шестнадцатеричным числом, где каждый байт представляет красный, зеленый или синий компоненты цвета. Например, #FF0000полностью красный и эквивалентен rgb(255, 0, 0).

Цвета также могут быть представлены сокращенной записью, которая использует три шестнадцатеричных цифры. Сокращение расширяется до шестизначной формы путем дублирования каждой цифры. Например, #ABCстановится #AABBCC.

Поскольку в шестнадцатеричном сокращении меньше цифр, можно представить меньше цветов.

Соревнование

Напишите программу или функцию, которая принимает шестизначный шестнадцатеричный цветной код и выводит ближайший трехзначный цветной код.

Вот пример:

  • Введите шестнадцатеричный код: # 28a086
  • Красный компонент
    • 0x28 = 40 (десятичное число)
    • 0x22 = 34
    • 0x33 = 51
    • 0x22 ближе, поэтому первая цифра укороченного цветового кода равна 2
  • Зеленый компонент
    • 0xa0 = 160
    • 0x99 = 153
    • 0xaa = 170
    • 0x99 ближе, поэтому вторая цифра 9
  • Синий компонент
    • 0x86 = 134
    • 0x77 = 119
    • 0x88 = 136
    • 0x88 ближе, поэтому третья цифра 8
  • Сокращенный код цвета # 298 (который расширяется до # 229988)

Ваша программа или функция должны принимать в качестве входных данных шестизначный шестнадцатеричный цветовой код с #предварительным добавлением и выводить трехзначный цветовой код с предварительным добавлением #.

Примеры

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

счет

Это соревнование по коду, поэтому самый короткий ответ на вашем языке выигрывает! Стандартные правила применяются.

wrymug
источник
1
«суммируя разницу между каждым компонентом полноцветного кода и соответствующим компонентом сокращенного цветового кода» - эта часть сбивает с толку. Там нет добавления нигде, верно?
Гжегож Оледзки
3
Обратите внимание, что если вы просто отбрасываете альтернативные цифры, то каждый короткий цвет представляет собой равное количество полных цветов, так что это может рассматриваться как лучшее представление, чем ближайший цвет.
Нил
6
Видел это в Песочнице, но забыл упомянуть, что я не думаю, что требует что-то #добавляет к вызову.
лохматый
2
Можем ли мы вывести в нижнем регистре?
Арно
2
0x22 - это 34, а не 30
Круга

Ответы:

4

JavaScript (ES6), 55 байт

s=>s.replace(/\w./g,x=>(('0x'+x)/17+.5|0).toString(16))

Попробуйте онлайн!

Arnauld
источник
Хорошее использование toString! Я не осознавал, что это может принять радикальный парам.
wrymug
8

05AB1E , 13 байтов

ćs2ôH8+17÷hJ«

Попробуйте онлайн!

Как?

ć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
Я тоже думал о том, чтобы сделать ответ N 05AB1E - если я что-то пропустил, шестнадцатеричное преобразование в Jelly занимает довольно много байтов!
Ник Кеннеди
1
Да, в Jelly нет встроенных текстовых базовых преобразований.
Джонатан Аллан
1
" ćобезглавить " Это еще один способ описать это, смеется. : D Хороший ответ, хотя, +1 от меня.
Кевин Круйссен
6

Japt , 16 байт

r"%w"²_n16_r17Ãg

Попробуйте или запустите все тесты

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

8088 Assembly, IBM PC DOS, 59 58 байт

Несобранный список:

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 

Автономный исполняемый файл DOS для ПК. Ввод через командную строку, вывод на консоль.

Большая часть длины кода обрабатывает преобразование требуемого ввода-вывода шестнадцатеричной строки в байты, так как машинный код DOS / x86 не имеет встроенных функций для этого.

I / O:

введите описание изображения здесь

Загрузите и протестируйте HEXCLR.COM или 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..
640 КБ
источник
3

Сетчатка 0.8.2 , 88 байт

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

Попробуйте онлайн! Ссылка включает в себя тестовые случаи. Объяснение:

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

Соедините шестнадцатеричные цифры.

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

Преобразуйте каждую цифру отдельно в десятичную.

\d+
$*

Преобразовать каждую десятичную цифру в унарную.

+`1,
,16$*

Завершите шестнадцатеричное преобразование пары цифр.

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

Добавьте 8 и разделите на 17.

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

Конвертировать обратно в шестнадцатеричное.

Нил
источник
3

Python 3 , 72 70 68 байт

lambda x:'#'+''.join(f"{(int(x[i:i+2],16)+8)//17:X}"for i in(1,3,5))

Попробуйте онлайн!

Это порт Гжегожа Оледзкиса, оригинальный ответ , который я помог ему сыграть в гольф.

Две особенности Python 3 помогают нам сохранять байты:

  • Деление с плавающей точкой по умолчанию
  • Форматировать строковые литералы

-2 байта спасибо Джонатану Аллану

movatica
источник
2
(int(x[i:i+2],16)+8)//17сохраняет 2
Джонатан Аллан
2

Wolfram Language (Mathematica) , 63 48 байтов

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

Попробуйте онлайн!

-15 байт благодаря attinat ! Замена StringJoinс <>и сжатия синтаксиса.

  1. RGBColor@#преобразует входную строку в цвет формы RGBColor[r, g, b]с тремя аргументами с плавающей точкой в ​​диапазоне 0..1.

  2. Round[15 List @@ %]умножает список из трех аргументов на 15 и округляет их до ближайшего целого числа. Теперь у нас есть список из трех целочисленных значений, соответствующих трем желаемым шестнадцатеричным цифрам.

  3. %~IntegerString~16 преобразует этот список из трех целых чисел в список из трех шестнадцатеричных строк по одному символу в каждой.

  4. "#"<>%готовит #персонажа и объединяет всех этих персонажей.

Римский
источник
1
48 байт
attinat
2

MathGolf , 19 12 байт

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

Вывести как список символов. Если это не разрешено, дополнительный трейлингy , чтобы присоединить список символов к строке.

-7 байт благодаря @maxb , так как я смотрел мимо встроенного ( 2ô_2<\1>]в 2/).

Попробуйте онлайн.

Объяснение:

              # 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

Рубин (2.5.3), 45 , 44 , 42 байта

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

РЕДАКТИРОВАТЬ: сохранил один байт, потому что нам не нужна группа символов для второго символа в регулярном выражении (вдохновленный ответом Нила)

РЕДАКТИРОВАТЬ 2: сохранил 2 байта, потому что синтаксис лямбда-тире ракеты не требует скобок вокруг аргумента

DaveMongoose
источник
2
Вы можете сэкономить 7 байтов, взяв ввод в stdin и используя -pфлаг и еще 2, используя $&вместо аргумента внутри блока: tio.run/##KypNqvz/…
Джордан,
1
@ Джордан Спасибо! Я не знал ни об одном из них, так что это реальная помощь для будущих попыток игры в гольф
DaveMongoose
1

Python 2 ( 109 101 97 85 83 74 байта)

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

«Ближайшее расстояние» обрабатывается делением на 17 и округлением.

Улучшения:

-8 байт, используя int(...+.5)трюк вместоint(round(...))

-4 байта, используя понимание списка вместо map()

-1 байт путем #жесткого кодирования в выводе (спасибо @movatica)

-10 байт, не используя re.findall("..",...)в пользу явного объединения строк

-2 байта, не используя понимание списка, но встроенное выражение генератора в join(спасибо @movatica)

-1 байт, не соединяя :7конец для синей части

-9 байтов за счет лучшей итерации по цветам - т.е. итерации по индексам, а не по фактическим символам (спасибо @movatica)

Гжегож Оледзки
источник
1
@movatica - ты прав, добавил это
Гжегож Оледзки
1
Сохраните 1 байт путем жесткого кодирования '#'вместо x[0].
Моватика
1
Вы можете пропустить понимание списка внутри ''.join(...), так как оно также обрабатывает выражение генератора. Просто удалите []и сохраните еще 2 байта :)
movatica
1
Благодарность! range(1,6,2)еще лучше с[1,3,5]
Гжегож Oledzki
1
Джонатан Аллен предложил другой способ округления в версии mz Pzthon3. Это применимо и здесь: lambda x:'#'+''.join(hex((int(x[i:i+2],16)+8)/17)[2:]for i in[1,3,5])-> 69 байт
movatica
1

Perl 5 -p , 35 34 байта

@nwellnhof сохранил байт

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

Попробуйте онлайн!

Читает из STDIN, заменяет каждую пару элементов, у которых нет #соответствующего одиночного символа, используя метод деления на 17 для нахождения ближайшего, затем неявно выводит ( -p) результат.

Xcali
источник
1

Python 3, 67 байт

f=lambda x:(f(x[:-2])if x[3:]else"#")+f'{(int(x[-2:],16)+8)//17:X}'
GSY
источник
Добро пожаловать. Попробуйте добавить описание, объяснение или ссылку на онлайн-переводчик, такой как TIO, где мы можем запустить ваш код. Ответы, содержащие только код, автоматически помечаются как некачественные. Смотрите другие существующие ответы для примеров.
mbomb007
0

Красный , 103 байта

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

Попробуйте онлайн!

Оказалось, что текущая версия Linux Red не имеет реализации hex-to-rgbфункции, поэтому я делаю базовое преобразование «вручную» :)

Это прекрасно работает в консоли Red GUI на Windows:

Красный , 94 байта

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

Древесный уголь , 22 байта

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

Попробуйте онлайн! Ссылка на подробную версию кода. Объяснение:

#                       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

Pyth , 20 байт

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

Попробуй это здесь.

ПРИМЕЧАНИЕ. В случае, если приведенная выше ссылка вызывает значение ImportError, перейдите сюда ; в настоящее время есть ошибка на официальной странице, и это временное решение от Maltysen . Эта ссылка может перестать работать после исправления официальной.

Эрик Outgolfer
источник
0

Forth (gforth) , 87 байтов

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

Попробуйте онлайн!

объяснение

  1. Игнорировать / усекать первый символ ввода (# )
  2. Установите переводчик в шестнадцатеричный режим
  3. Выход #
  4. Цикл 3 раза, в каждом цикле:
    1. Добавьте 2 к начальному адресу строки
    2. Преобразуйте следующие 2 символа в строке в шестнадцатеричное число
    3. Используйте деление и модуль на 17 (0x11 ), чтобы получить ближайшее значение для укороченного компонента
    4. Выход без предшествующего пробела
  5. Установите переводчик обратно в десятичный режим

Код Объяснение

: 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
reffu
источник
0

К4 , 39 байт

Решение:

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

Объяснение:

Использует ту же стратегию, что и многие из этих ответов (т.е. добавить 8, разделить на 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 "#"

Дополнительно:

  • "#",{x@*16\:a?&/a:abs(17*!16)-16/:x?y}[.Q.nA]@/:3 2#1_- моя оригинальная идея на 54 байта
streetster
источник