Obróć kamerę; uratować astronautę


23

Uwaga: w tym wyzwaniu są mniejsze spoilery dla Marsjanina . Czytaj dalej ostrożnie


Marsjanin to powieść science fiction na temat astronauty i botanika, Marka Watneya , który przypadkowo został wyrzucony na Marsa. W pewnym momencie książki Mark próbuje komunikować się z NASA, ale jedynym dostępnym środkiem komunikacji jest kamera. Mark wysyła wiadomości, pisząc na kartach indeksowych, a ponieważ NASA może obracać kamerę o 360 stopni, NASA wysyła odpowiedzi, kierując aparat na karty oznaczone „Tak” lub „Nie”.

Ponieważ jedyne dane, które NASA może wysyłać, to kierunek, w którym skierowana jest kamera, Mark wymyślił system, w którym mogą wskazywać karty z literami alfabetu, aby pisać wiadomości. Ale użycie liter „az” byłoby niepraktyczne. Aby zacytować książkę (od tej odpowiedzi na scifi.se):

Będziemy musieli rozmawiać szybciej niż tak / nie pytania co pół godziny. Kamera może obracać się o 360 stopni, a ja mam mnóstwo części antenowych. Czas na alfabet. Ale nie mogę po prostu użyć liter od A do Z. Dwadzieścia sześć liter plus moja karta pytań to dwadzieścia siedem kart wokół lądownika. Każdy uzyskałby tylko 13 stopni łuku. Nawet jeśli JPL doskonale wskazuje aparat, istnieje duża szansa, że ​​nie będę wiedział, o którą literę chodziło.

Więc będę musiał użyć ASCII. W ten sposób komputery zarządzają postaciami. Każdy znak ma kod numeryczny od 0 do 255. Wartości od 0 do 255 mogą być wyrażone jako 2 cyfry szesnastkowe. Podając mi pary cyfr szesnastkowych, mogą wysyłać dowolne znaki, które im się podobają, w tym cyfry, znaki interpunkcyjne itp.

...

Zrobię więc karty od 0 do 9 oraz od A do F. To daje 16 kart do umieszczenia wokół kamery, plus kartę pytań. Siedemnaście kart oznacza ponad 21 stopni każda. O wiele łatwiej sobie poradzić.

Twoim celem dzisiaj, jako jednego z najlepszych inżynierów oprogramowania w NASA, jest napisanie programu do kodowania różnych ujęć kamery. Siedemnaście kart, które Mark ma dla ciebie wskazać, to (w kolejności):

?0123456789ABCDEF

a każda z tych kart jest oddalona o 21 stopni, więc aby obrócić kamerę od ?do 0, należy obrócić kamerę o 21 stopni i 2do 1-21 stopni. (To nie jest dokładnie 21, ale zaokrąglimy, aby było prostsze) To się zawija, więc przejście od Fdo 3wynosi 105 stopni (5 obrotów, 5 * 21 = 105). Jest to bardziej wydajne niż przejście do -252, ponieważ kamera nie będzie musiała się poruszać tak daleko.

Oto, co musi zrobić Twój program lub funkcja.

  1. Weź ciąg jako dane wejściowe. Nazwiemy ten ciąg s . Mówiąc prościej, powiemy, że wejście będzie zawsze możliwe do wydrukowania w formacie ASCII. W naszym przykładzie powiedzmy, że dane wejściowe byłySTATUS

  2. Konwertuj każdy znak na jego reprezentację szesnastkową. Przekształci się STATUSto w 53 54 41 54 55 53.

  3. Wydrukuj lub zwróć kolejne obroty, które aparat będzie musiał wykonać, aby wskazać każdą kartę i powrócić do „Karty pytań”. W naszym przykładzie byłoby to:

    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-?)
    

    Lub w formacie tablicowym:

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

Pamiętaj, że zawsze musisz wykonywać najmniejsze możliwe obroty. Więc jeśli wejście było NO, to znaczy 4E 4F, powinieneś wypisać:

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

Zamiast:

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

Oto kilka sprawdzonych przykładów:

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]

Ponieważ NASA szczyci się wydajnością, Twoim celem jest napisanie możliwie najkrótszego kodu. Obowiązują standardowe luki. Teraz przyprowadź go do domu!


Uwaga dodatkowa: te przypadki testowe zostały wykonane ręcznie i były rodzajem bólu, więc mogą występować drobne niedokładności. Daj mi znać, jeśli coś wygląda nie tak. :)
DJMcMayhem

Odpowiedzi:


5

JavaScript (ES6), 103 99 bajtów

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

Przypadki testowe


Czy to zadziała? s.replace(/./g,->[...s].map(
Łukasz

@Luke Nope, ponieważ musimy oddzielić każdą cyfrę szesnastkową. ...s.replace(/./g,daje np "4","8","6","5","6","c".... while. ...[...s.map(dałby"48","65","6c",...
ETHproductions

4

C, 212 202 199 187 bajtów

3 bajty zapisane dzięki @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));}

Wypróbuj online!


1
Myślę, że możesz to zrobić 8>i?i:17-izamiast17-i>i?...
Kritixi Lithos

@KritixiLithos tak, dzięki.
betseg

3

Python, 187 178 bajtów

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

Przypadki testowe

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


1

Galaretka , 21 19 bajtów

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

Wypróbuj online!

W jaki sposób?

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

Ohm , 20 19 bajtów (CP437), niekonkurujące

EDYCJA : Zapisano 1 bajt, zmieniając blok mapy na powtarzające się mapy jednoskładnikowe.

Byłbym prawdopodobnie nieco krótszy, gdybym miał w domyśle wektoryzację.

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

Wyjaśnienie:

`»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 bajtów:

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

awaria

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 "?"

Oczywiście 21jest dość niedokładny i może zawieść w przypadku ciągów dłuższych niż 14 znaków; ale wtedy ... 360/17byłyby cztery bajty dłużej.

Alternatywnym rozwiązaniem byłoby przymocowanie wskaźnika laserowego do kamery;
z tym moglibyśmy użyć wszystkich drukowalnych znaków ascii i karty „pytania” przy 3,75 stopnia.

Inna alternatywa: użyj 16 kart (o 22,5 stopnia) z 6 znakami każda:
zaimplementuj coś w rodzaju T9, a my możemy pominąć wysokie skubanie. ;)

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.