Gire uma câmera; salvar um astronauta


23

Nota: Pequenos spoilers de The Marciano estão neste desafio. Leia com cautela


Marciano é um romance de ficção científica sobre o astronauta e botânico extraordinário, Mark Watney , que foi acidentalmente preso em Marte. Em um ponto do livro, Mark tenta se comunicar com a NASA, mas o único meio de comunicação que eles têm é uma câmera. Mark envia mensagens escrevendo em cartões de índice e, como a NASA pode girar a câmera em 360 graus, a NASA envia respostas apontando a câmera para os cartões "Sim" ou "Não".

Como os únicos dados que a NASA pode enviar é a direção para a câmera, Mark cria um sistema no qual eles podem apontar para cartões com caracteres do alfabeto para digitar mensagens. Mas usar as letras 'az' seria impraticável. Para citar o livro ( desta resposta , em scifi.se):

Precisamos conversar mais rápido do que perguntas sim / não a cada meia hora. A câmera pode girar 360 graus, e eu tenho muitas peças de antena. Hora de fazer um alfabeto. Mas não posso simplesmente usar as letras de A a Z. Vinte e seis letras, mais o meu cartão de perguntas, seriam vinte e sete cartões ao redor do terminal. Cada um teria apenas 13 graus de arco. Mesmo que o JPL aponte a câmera perfeitamente, há uma boa chance de eu não saber qual letra eles significaram.

Então eu vou ter que usar ASCII. É assim que os computadores gerenciam caracteres. Cada caractere tem um código numérico entre 0 e 255. Valores entre 0 e 255 podem ser expressos como 2 dígitos hexadecimais. Ao me fornecer pares de dígitos hexadecimais, eles podem enviar qualquer caractere que desejar, incluindo números, pontuação etc.

...

Então, eu faço cartões de 0 a 9 e de A a F. Isso faz com que 16 cartões sejam colocados ao redor da câmera, mais o cartão de perguntas. Dezessete cartas significa mais de 21 graus cada. Muito mais fácil de lidar.

Seu objetivo hoje, como um dos principais engenheiros de software da NASA, é escrever um programa para codificar os vários ângulos da câmera. As dezessete cartas que Mark tem para você apontar são (em ordem):

?0123456789ABCDEF

e cada um desses cartões estiver a 21 graus de distância, para girar a câmera de ?para 0, você deve girar a câmera em 21 graus e 2para 1-21 graus. (Não são exatamente 21, mas vamos arredondar para simplificar) Isso envolve, portanto, passar de Fpara 3105 graus (5 turnos, 5 * 21 = 105). Isso é mais eficiente do que chegar a -252, já que a câmera não precisará se mover tão longe.

Aqui está o que seu programa ou função deve fazer.

  1. Pegue uma string como entrada. Vamos chamar essa string de s . Para simplificar, diremos que a entrada só será impressa em ASCII. Para o nosso exemplo, digamos que a entrada foiSTATUS

  2. Converta cada caractere em sua representação hexadecimal. Isso seria convertido STATUSpara 53 54 41 54 55 53.

  3. Imprima ou retorne o grau consecutivo que a câmera precisará fazer para apontar para cada cartão e retornar ao "Cartão de perguntas". Para o nosso exemplo, isso seria:

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

    Ou, no formato de matriz:

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

Observe que você sempre deve fazer a menor das rotações possíveis. Portanto, se a entrada foi NO, ou seja 4E 4F, você deve gerar:

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

Ao invés de:

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

Aqui estão mais alguns exemplos trabalhados:

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]

Como a NASA se orgulha da eficiência, seu objetivo é escrever o código mais curto possível. Aplicam-se brechas padrão. Agora traga-o para casa!


Nota lateral: esses casos de teste foram feitos à mão e foram uma espécie de dor, portanto, pode haver algumas pequenas imprecisões. Informe-me se algo parecer errado. :)
DJMcMayhem

Respostas:


5

JavaScript (ES6), 103 99 bytes

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

Casos de teste


Isso funcionaria? s.replace(/./g,->[...s].map(
Luke

@ Lucas Nope, porque precisamos separar cada dígito hexadecimal. ...s.replace(/./g,dá por exemplo "4","8","6","5","6","c"..., enquanto. ...[...s.map(daria"48","65","6c",...
ETHproductions

4

C, 212 202 199 187 bytes

3 bytes salvos graças ao @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));}

Experimente online!


1
Eu acho que você pode fazer em 8>i?i:17-ivez de17-i>i?...
Kritixi Lithos 2/17/17

@KritixiLithos yup, obrigado.
precisa saber é

3

Python, 187 178 bytes

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

Casos de teste

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


1

Geléia , 21 19 bytes

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

Experimente online!

Quão?

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 bytes (CP437), não concorrente

EDIT : economizou 1 byte alterando um bloco de mapa para mapas de componente único repetidos.

Provavelmente seria um pouco menor se eu tivesse vetorização implícita.

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

Explicação:

`»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 bytes:

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

demolir

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

Obviamente, 21é bastante impreciso e pode falhar em cadeias com mais de 14 caracteres; mas então ... 360/17seria quatro bytes mais.

Uma solução alternativa teria sido conectar um ponteiro laser à câmera;
poderíamos usar todos os caracteres ascii imprimíveis e um cartão de "pergunta" a 3,75 graus cada um com isso.

Outra alternativa: use 16 cartões (a 22,5 graus) com 6 caracteres cada:
implemente algum tipo de T9 e podemos omitir a mordidela alta. ;)

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.