Laser de Schrödinger


24

Farto de experimentar minúsculos animais domésticos , o premiado com o Nobel Erwin Schrödinger decidiu encontrar o laser mais próximo e atirar nele. Porque ... ciência!

Descrição

Você receberá dois pontos pelos quais o laser passa e o tamanho de um raio laser, além de determinar para onde o raio laser deve ter ido, poderia ter ido e não poderia ter ido.

O raio laser pode ser horizontal, vertical ou diagonal. Para um raio laser tamanho 1, eles se parecem com isso, respectivamente:

       #  #
       #   #
#####  #    #
       #     #
       #      #

O raio laser diagonal também pode ser invertido. Os raios laser tamanho 2 são assim:

       ###  ##
#####  ###  ###
#####  ###   ###
#####  ###    ###
       ###     ##

Em geral, para obter um raio laser de tamanho (n), basta pegar o raio laser de tamanho (n-1) e adicionar um raio laser de tamanho (1) nos dois lados. Como exemplo final, aqui estão todos os raios laser possíveis do tamanho 3, mostrados na mesma "placa":

###.....#####.....##
####....#####....###
#####...#####...####
.#####..#####..#####
..#####.#####.#####.
...###############..
....#############...
.....###########....
####################
####################
####################
####################
####################
.....###########....
....#############...
...###############..
..#####.#####.#####.
.#####..#####..#####
#####...#####...####
####....#####....###

Este "quadro" sempre terá dimensões de 20x20 (em caracteres).

Entrada

Seu programa receberá cinco números inteiros como entrada. Eles são, em ordem, x 1 , y 1 , x 2 , y 2 e o tamanho do feixe de laser. Eles devem ser tomados exatamente nessa ordem. Se desejar, você pode usar os pares ordenados (x, y) como uma matriz, tupla, lista ou outro tipo de dados interno que armazena dois valores.

Ambos os dois pontos dados como entrada estarão dentro do quadro e são garantidos para serem distintos (ou seja, os dois pontos nunca serão os mesmos). O tamanho do feixe de laser está vinculado 1 ≤ size < 20. Sempre haverá pelo menos um feixe de laser possível que passa pelos dois pontos.

Saída

Seu programa deve gerar uma grade 20x20 dos seguintes caracteres:

  • # se todo raio laser possível que passa pelos dois pontos também passa por esse ponto.
  • . se não houver raio laser que atravesse os dois pontos e este ponto.
  • ? se alguns, mas não todos, os possíveis raios laser passarem por esse ponto.
  • Xse esse for um dos dois pontos de entrada originais (isso substitui o #).

Casos de teste

7, 7, 11, 3, 1

..............#.....
.............#......
............#.......
...........X........
..........#.........
.........#..........
........#...........
.......X............
......#.............
.....#..............
....#...............
...#................
..#.................
.#..................
#...................
....................
....................
....................
....................
....................

18, 18, 1, 1, 2

#??.................
?X??................
??#??...............
.??#??..............
..??#??.............
...??#??............
....??#??...........
.....??#??..........
......??#??.........
.......??#??........
........??#??.......
.........??#??......
..........??#??.....
...........??#??....
............??#??...
.............??#??..
..............??#??.
...............??#??
................??X?
.................??#

10, 10, 11, 10, 3

?????..????????..???
??????.????????.????
????????????????????
????????????????????
.???????????????????
..??????????????????
????????????????????
????????????????????
????????????????????
????????????????????
??????????XX????????
????????????????????
????????????????????
????????????????????
????????????????????
..??????????????????
.???????????????????
????????????????????
????????????????????
??????.????????.????

3, 3, 8, 10, 4

??????????..........
??????????..........
??????????..........
???X??????..........
???##?????..........
???###????..........
????###????.........
.????###????........
..????###????.......
..?????##?????......
..??????X??????.....
..??????????????....
..???????????????...
..????????????????..
..?????????????????.
..??????????????????
..??????????????????
..????????.?????????
..????????..????????
..????????...???????

Os casos de teste foram gerados com o seguinte script Ruby, localizado dentro de um snippet de pilha para economizar espaço vertical.

Regras

  • Seu programa deve ser capaz de resolver cada um dos casos de teste em menos de 30 segundos (em uma máquina razoável). Isso é mais uma verificação de integridade, pois meu programa Ruby de teste resolveu todos os casos de teste quase instantaneamente.

  • Isso é , então a solução mais curta vence.


2
A terminologia usada aqui me fez tropeçar inicialmente. Eu acredito que o laser normalmente se refere a um dispositivo que produz raios laser . O que você está representando aqui são realmente as vigas, certo? Isso não deveria ser uma representação do laser real, qual seria o dispositivo que geraria os feixes?
Reto Koradi

2
O último caso de teste parece errado. Um laser tamanho 4 deve ter 9 pixels de largura. A pista vertical deve ter pelo menos essa largura, mas na verdade é mais estreita.
Level River St

11
@steveverrill O tamanho 4 tem 7 pixels de largura. A largura em pixels é 2 * size - 1. O tamanho 1 é 1 pixel, o tamanho 2 é 3 pixels, o tamanho 3 é 5 pixels (veja o exemplo acima), o tamanho 4 é 7 pixels.
Reto Koradi

2
Não vejo como Schrodinger está relacionado a esse desafio.
user12205

11
@JonasDralle Novamente, o limite de tempo é basicamente apenas uma verificação de sanidade e espera-se que quase todos os envios sejam concluídos em muito menos tempo que isso.
Maçaneta

Respostas:


5

C, 291 280 277 265 bytes

x,y,A,C,B,D,a,c,b,d,w,s,t;T(i){return abs(i)<2*w-1;}U(j,k){s+=T(j-k)*T(j)*T(k);t*=T(j-k)*j*k<1;}main(){for(scanf("%i%i%i%i%i",&a,&b,&c,&d,&w);y<20;y+=!x)s=0,t=1,U(A=a-x,C=c-x),U(B=b-y,D=d-y),U(A-B,C-D),U(A+B,C+D),putchar((x=++x%21)?".?#x"[!!s+t+(!A*!B+!C*!D)]:10);}

Pode ser compilado / executado usando:

gcc laser.c -o laser && eco "10 10 11 10 3" | ./laser

Abaixo, o mesmo código com espaço em branco e comentários explicativos:

// Integers...
x,y,A,C,B,D,a,c,b,d,w,s,t;

// Is true if i is in range (of something)
T(i){return abs(i)<2*w-1;}

// Tests if lasers (horizontal, vertical, diagonal, etc) can/must exist at this point
// T(j-k) == 0 iff the laser of this direction can exist
// s += 1 iff this laser direction can pass through this point
// t *= 1 iff this laser direction must pass through this point
U(j,k){
    s+=T(j-k)*T(j)*T(k);
    t*=T(j-k)*j*k<1;
}

main(){ 
    // Read input; p0=(a,b), p1=(c,d)
    for(scanf("%i%i%i%i%i",&a,&b,&c,&d,&w); y<20; y+=!x)

        // A, B, C and D represent delta-x and delta-y for each points
        // e.g.: if we're processing (2,3), and p0=(4,5), A=4-2, B=5-3
        // s != 0 iff (x,y) can have some laser through it
        // t == 1 iff all lasers pass through (x,y)
        // (!A*!B+!C*!D) == 1 iff (x,y) is either p0 or p1  
        s=0,t=1,U(A=a-x,C=c-x),U(B=b-y,D=d-y),U(A-B,C-D),U(A+B,C+D),
        putchar((x=++x%21)?".?#x"[!!s+t+(!A*!B+!C*!D)]:10);
}

11
U(int j,int k)-> U(j,k); '\n'-> 10.
user12205

11
k<=0->k<1
user12205

Bons pontos. Eu votaria se pudesse!
André Harder

4

C, 302 bytes

b[400],x,y,s,t,w,d,e,g,k;f(u,v){d=u*x+v*y;e=u*s+v*t;if(e<d)k=e,e=d,d=k;for(k=0;k<400&d+w>e;++k)g=k%20*u+k/20*v,b[k]|=g>e-w&g<d+w|(g<d|g>e)*2;}main(){scanf("%d%d%d%d%d",&x,&y,&s,&t,&w);w=2*w-1;f(1,0);f(0,1);f(1,1);f(1,-1);b[y*20+x]=4;b[t*20+s]=4;for(k=0;k<400;)putchar(".#.?X"[b[k]]),++k%20?0:puts("");}

A entrada é obtida do stdin, lendo os 5 números na ordem definida.

Antes da etapa final de redução de tamanho:

#include <stdio.h>
#include <stdlib.h>

int b[400], x, y, s, t, w, d, e, g, k;

void f(int u, int v) {
  d = u * x + v * y;
  e = u * s + v * t;
  if (e < d) k = e, e = d, d = k;
  if (d + w > e) {
    for (k = 0; k < 400; ++k) {
      g = u * (k % 20) + v * (k / 20);
      if (g > e - w && g < d + w) b[k] |= 1;
      if (g < d || g > e) b[k] |= 2;
    }
  }
}

int main() {
  scanf("%d%d%d%d%d", &x, &y, &s, &t, &w);
  w = 2 * w - 1;
  f(1, 0); f(0, 1); f(1, 1); f(1, -1);
  b[y * 20 + x] = 4;
  b[t * 20 + s] = 4;
  for (k = 0; k < 400; ) {
     putchar(".#.?X"[b[k]]);
     ++k % 20 ? 0 : puts("");
  }
}

Algumas explicações sobre os principais passos:

  • A matriz bmantém o estado / resultado. O bit 0 será definido para todos os pixels que podem ser alcançados por um feixe. O bit 1 será definido para todos os pixels que não são cobertos por todos os feixes.
  • A função fé chamada para todas as 4 direções (vertical, horizontal, ambas as diagonais). Seus argumentos especificam o vetor normal da direção.
  • Em função f:
    • A distância de ambos os pontos de entrada em relação à direção é calculada ( de e) como o produto escalar do ponto com o vetor normal passado.
    • As distâncias são trocadas, se necessário, para que dseja sempre menor ou igual a e.
    • Se a diferença entre de efor maior que a largura da viga, nenhuma viga será possível nessa direção.
    • Caso contrário, faça um loop sobre todos os pixels. Defina o bit 0 se o pixel estiver acessível por qualquer feixe e o bit 1 se não for coberto por todos os feixes.
  • Marque os dois pontos de entrada com o valor 4. Como usamos os bits 0 e 1 para rastrear o estado, que resulta nos valores de 0 a 3, esse é o menor valor não utilizado.
  • Faça um loop sobre os pixels be converta os valores no intervalo de 0 a 4 no caractere correspondente enquanto os imprime.

você provavelmente pode economizar um pouco, colocando a última linha de código para o incrementador nesse forciclo
Não que Charles
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.