Обертати камеру; врятувати космонавта


23

Примітка. Невисокі спойлери для марсіанів стоять перед цим викликом. Прочитайте вперед з обережністю


Марсіанець - це науково-фантастичний роман про космонавта та ботаністського екстраординарника Марка Уотні , який випадково опинився на Марсі. У один момент книги Марк намагається спілкуватися з НАСА, але єдиним засобом спілкування у них є камера. Марк надсилає повідомлення, записуючи на індексні картки, і, оскільки NASA може обертати камеру на 360 градусів, NASA надсилає відповіді назад, вказуючи камеру на картки з написом "Так" або "Ні".

Оскільки єдині дані, які NASA може надсилати, - це напрямок, з яким стикається камера, Марк створює систему, де вони можуть вказувати на картки з символами алфавіту для введення повідомлень. Але використовувати букви «аз» було б недоцільно. Цитуючи книгу (з цієї відповіді , на scifi.se):

Нам потрібно буде говорити швидше, ніж так / ні питань кожні півгодини. Камера може обертатися на 360 градусів, і у мене є багато антенних частин. Час скласти алфавіт. Але я не можу просто використовувати літери від A до Z. Двадцять шість листів плюс моя карта запитань буде двадцять сім карток навколо приземлення. Кожен би отримав лише 13 градусних дуг. Навіть якщо JPL ідеально вказує на камеру, є хороший шанс, що я не буду знати, яку букву вони мали на увазі.

Тому мені доведеться використовувати ASCII. Ось як комп’ютери управляють персонажами. Кожен символ має числовий код від 0 до 255. Значення між 0 і 255 можна виразити двома шістнадцятковими цифрами. Надаючи мені пари шістнадцяткових цифр, вони можуть надсилати будь-який символ, який їм подобається, включаючи цифри, пунктуацію тощо.

...

Тож я зроблю картки від 0 до 9, і від A до F. Це робить 16 карт для розміщення навколо камери, плюс карта запитань. Сімнадцять карток означає понад 21 градус. Набагато простіше впоратися.

Ваша мета сьогодні, як одного з найкращих інженерів програмного забезпечення NASA, - написати програму для кодування різних кутів камери. Сімнадцять карток, які Марк має на вас вказати, є (по порядку):

?0123456789ABCDEF

і кожна з цих карт становить 21 градусів друг від друга, так , щоб обертати камеру від ?до 0, ви повинні поверніть камеру 21 градусів, а 2в 1це -21 градусів. (Це не точно 21 рік, але ми обернемось, щоб зробити його простіше) Це обгортання, так що для переходу Fдо 3- це 105 градусів (5 витків, 5 * 21 = 105). Це більш ефективно, ніж їхати -252, оскільки камері не доведеться рухатись так далеко.

Ось що ваша програма чи функція повинна робити.

  1. Візьміть рядок як вхідний. Ми будемо називати цей рядок s . Щоб зробити це просто, ми скажемо, що вхід буде надрукованим лише ASCII. Для нашого прикладу скажімо, що вхід бувSTATUS

  2. Перетворіть кожен символ у його шістнадцяткове зображення. Це перетвориться STATUSна 53 54 41 54 55 53.

  3. Роздрукувати або повернути послідовні обороти, які потрібно зробити камерою, щоб вказати на кожну карту і повернутися до "Карти запитань". Для нашого прикладу це:

    6  * 21 = 126   (?-5)
    -2 * 21 = -42   (5-3)
    2  * 21 = 42    (3-5)
    -1 * 21 = -21   (5-4)
    0  * 21 = 0     (4-4)
    -3 * 21 = -63   (4-1)
    4  * 21 = 84    (1-5)
    -1 * 21 = -21   (5-4)
    1  * 21 = 21    (4-4)
    0  * 21 = 0     (5-5)
    0  * 21 = 0     (5-5)
    -2 * 21 = -42   (5-3)
    -4 * 21 = -84   (3-?)
    

    Або у форматі масиву:

    [126, -42, 42, -21, 0, -63, 84, -21, 21, 0, 0, -42, -84]
    

Зауважте, що ви завжди повинні приймати найменші з можливих обертань. Отже, якщо вхід був NO, який є 4E 4F, слід вивести:

5    * 21 = 105
-7   * 21 = -147
7    * 21 = 147
-6   * 21 = -126
1    * 21 = 21

Замість:

 5   * 21 = 105
 10  * 21 = 210
 -10 * 21 = -210
 11  * 21 = 231
 -16 * 21 = -336

Ось ще кілька опрацьованих прикладів:

Input: CROPS?
ASCII: 43 52 4F 50 53 3F
Worked Example:

5  * 21 = 105
-1 * 21 = -21
2  * 21 = 42
-3 * 21 = -63
2  * 21 = 42
-6 * 21 = -126
7  * 21 = 147
-5 * 21 = -105
5  * 21 = 105
-2 * 21 = -42
0  * 21 = 0
-5  * 21 = -105
1 * 21 = 21

Result: [105 -21 42 -63 42 -126 147 -105 105 -42 0 -105 21]


Input: DDD
ASCII: 44 44 44
Worked Example:

5   * 21 = 105
0   * 21 = 0
0   * 21 = 0
0   * 21 = 0
0   * 21 = 0
0   * 21 = 0
-5  * 21 = -105

Result: [105, 0, 0, 0, 0, 0, -105]


Input: Hello world!
ASCII: 48 65 6c 6c 6f 20 77 6f 72 6c 64 21
Worked example:

5   * 21 = 105
4   * 21 = 84
-2  * 21 = -42
-1  * 21 = -21
1   * 21 = 21
6   * 21 = 126
-6  * 21 = -126
6   * 21 = 126
-6  * 21 = -126
-8  * 21 = -168
4   * 21 = 84
-2  * 21 = -42
7   * 21 = 147
0   * 21 = 0
-1  * 21 = -21
-8  * 21 = -168
-8  * 21 = -168
-5  * 21 = -105
4   * 21 = 84
6   * 21 = 126
-6  * 21 = -126
-2  * 21 = -42
-2  * 21 = -42
-1  * 21 = -21
-2  * 21 = -42

Result: [105 84 -42 -21 21 126 -126 126 -126 -168 84 -42 147 0 -21 -168 -168 -105 84 126 -126 -42 -42 -21 -42]

Оскільки NASA пишається своєю ефективністю, ваша мета - написати найкоротший можливий код. Застосовуються стандартні лазівки. Тепер приведи його додому!


Побічна примітка: Ці тестові справи були зроблені вручну, і вони були болем, тому можуть бути незначні неточності. Будь ласка, дайте мені знати, якщо щось виглядає не так. :)
DJMcMayhem

Відповіді:


5

JavaScript (ES6), 103 99 байт

s=>[...s.replace(/./g,c=>c.charCodeAt().toString(16)),10].map(n=>((24-p-~(p='0x'+n))%17-8)*21,p=-1)

Тестові справи


Це би спрацювало? s.replace(/./g,->[...s].map(
Лука

@Luke Nope, оскільки нам потрібно відокремити кожну шістнадцяткову цифру. ...s.replace(/./g,дає, наприклад "4","8","6","5","6","c"..., поки. ...[...s.map(дав би"48","65","6c",...
ETHproductions

4

C, 212 202 199 187 байт

3 байти збережено завдяки @KritixiLithos!

i;f(a,b){i=abs(a-b);i=8>i?i:17-i;i=a<b&a>b-8?i:a<b&a<b-8?-i:b<a&b>a-8?-i:i;i*=21;}v;g(char*s){for(v=0;*s;s+=v++%2)printf("%d ",v?v%2?f(*s%16,s[1]?s[1]/16:-1):f(*s/16,*s%16):f(-1,*s/16));}

Спробуйте в Інтернеті!


1
Я думаю, що ви можете зробити це 8>i?i:17-iзамість17-i>i?...
Kritixi Lithos

@KritixiLithos так, дякую.
betseg

3

Пітон, 187 178 байт

def g(x):w,z=map('?0123456789abcdef'.index,x);d=w-z;return min(d,d+17*(d<=0 or -1),key=abs)*21
def f(s):s=''.join(map('{:2x}'.format,s.encode()));return[*map(g,zip(s+'?','?'+s))]

Тестові справи

for k in ['STATUS', 'NO', 'CROPS?', 'DDD', 'Hello world!']:
    print('Input:  {}\nOutput: {}'.format(k, f(k)))


1

Желе , 21 19 байт

Ob⁴F-;;-I+8%17_8×21

Спробуйте в Інтернеті!

Як?

Ob⁴F-;;-I+8%17_8×21 - Main link: string s        e.g. 'e.g.'
O                   - cast to ordinals            [101,     46,       103,      46]
 b                  - convert to base
  ⁴                 -     16                   [[6,   5], [2,  14], [6,   7], [2,  14]]
   F                - flatten                   [6,   5,   2,  14,   6,   7,   2,  14]
    -;              - -1 concatenate      [-1,   6,   5,   2,  14,   6,   7,   2,  14]
      ;-            - concatenate -1      [-1,   6,   5,   2,  14,   6,   7,   2,  14,  -1]
        I           - increments            [  7,  -1,  -3,  12,  -8,   1,  -5,  12, -15]
         +8         - add 8                 [ 15,   7,   5,  20,   0,   9,   3,  20,  -7]
           %17      - mod 17                [ 15,   7,   5,   3,   0,   9,   3,   3,  10]
              _8    - subtract 8            [  7,  -1,  -3,  -5,  -8,   1,  -5,  -5,   2]
                ×21 - multiply by 21        [147, -21, -63,-105,-168,  21,-105,-105,  42]

1

Ом , 20 19 байт (CP437), не конкуруючи

EDIT : Збережено 1 байт, змінивши блок карт на повторні однокомпонентні карти.

Напевно, було б трохи коротше, якби у мене була неявна векторизація.

`»x»}{»úΓXΓHδ▓_~21*

Пояснення:

`»x»}{»úΓXΓHδ▓_~21*    Main wire, arguments: s

`»x                    Convert char codes of s to hex
   »}                  Split digit pairs
     {                 Flatten
      »ú               Convert digits back to base 10
        ΓXΓH           Append and prepend with -1
            δ          Get deltas between each element of array
             ▓         Map array over...
              _~21*      Negate, multiply by 21

0

PHP, 125 116 байт:

function m($i){static$a;$a+=$d=($i-$a+10)%17-9;echo$d*21,"
";}for(;$c=ord($argv[1][$i++]);m($c%16))m($c/16|0);m(-1);

зламатися

function m($i)              // function to turn camera:
{
    static$a;                   // remember angle
    $a+=                        // add delta to angle
    $d=($i-$a+10)%17-9;         // delta: target=nibble value+1-current angle
                                // add 9, modulo 17, -9 -> shortest movement
    echo$d*21,"\n";                 // print delta * 21 and a linebreak
}
for(;$c=ord($argv[1][$i++]);// loop through input characters
    m($c%16))                   // 2. move to low nibble value
    m($c/16|0)                  // 1. move to high nibble value
;
m(-1);                      // move back to "?"

Звичайно, 21є досить неточним і може вийти з ладу для рядків довше 14 символів; але тоді ... 360/17було б на чотири байти довше.

Альтернативним рішенням було б приєднання до камери лазерного вказівника;
ми могли використати всі друковані символи ascii та карту «питання» при 3,75 градусів кожна з цим.

Інша альтернатива: Використовуйте 16 карт (при 22,5 градусах) по 6 символів кожна:
реалізуйте якийсь T9, і ми можемо опустити високий кусок. ;)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.