Láser de Schrödinger


24

Harto de experimentar con pequeños animales domésticos , el ganador del premio Nobel Erwin Schrödinger ha decidido encontrar el láser más cercano y dispararlo a las cosas. Porque ... ¡ciencia!

Descripción

Se le darán dos puntos por los que pasa el láser y el tamaño de un rayo láser, y debe determinar a dónde debe haber ido el rayo láser, dónde podría haber ido y dónde no .

El rayo láser puede ser horizontal, vertical o diagonal. Para un rayo láser de tamaño 1, se ven así respectivamente:

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

El rayo láser diagonal también se puede voltear. Los rayos láser de tamaño 2 se ven así:

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

En general, para obtener un rayo láser de tamaño (n), simplemente tome el rayo láser de tamaño (n-1) y agregue un rayo láser de tamaño (1) en ambos lados. Como ejemplo final, aquí están todos los rayos láser posibles de tamaño 3, que se muestran en el mismo "tablero":

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

Este "tablero" siempre tendrá dimensiones de 20x20 (en caracteres).

Entrada

Su programa recibirá cinco enteros como entrada. Son, en orden, x 1 , y 1 , x 2 , y 2 , y el tamaño del rayo láser. Deben tomarse exactamente en ese orden. Si lo desea, puede tomar los pares ordenados (x, y) como una matriz, tupla, lista u otro tipo de datos incorporado que almacena dos valores.

Los dos puntos dados como entrada estarán dentro del tablero, y se garantiza que serán distintos (es decir, los dos puntos nunca serán los mismos). El tamaño del rayo láser está vinculado a 1 ≤ size < 20. Siempre habrá al menos un posible rayo láser que atraviese ambos puntos.

Salida

Su programa debe generar una cuadrícula de 20x20 de los siguientes caracteres:

  • # si cada posible rayo láser que pasa por los dos puntos también pasa por este punto.
  • . si no hay un rayo láser que pase por los dos puntos y este punto.
  • ? si algunos, pero no todos, los posibles rayos láser pasan por este punto.
  • Xsi este es uno de los dos puntos de entrada originales (esto anula el #).

Casos de prueba

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

Los casos de prueba se generaron con el siguiente script de Ruby, ubicado dentro de un Fragmento de pila para conservar el espacio vertical.

Reglas

  • Su programa debe poder resolver cada uno de los casos de prueba en menos de 30 segundos (en una máquina razonable). Esto es más una comprobación de cordura, ya que mi programa de prueba Ruby resolvió todos los casos de prueba casi instantáneamente.

  • Este es el , por lo que gana la solución más corta.


2
La terminología utilizada aquí me hizo tropezar inicialmente. Creo que el láser normalmente se refiere a un dispositivo que produce rayos láser . Lo que estás representando aquí son realmente las vigas, ¿verdad? Se supone que esto no es una representación del láser real, ¿cuál sería el dispositivo que genera los rayos?
Reto Koradi

2
El último caso de prueba se ve mal. Un láser de tamaño 4 debe tener 9 píxeles de ancho. La pista vertical debe ser al menos tan ancha, pero de hecho es más estrecha.
Level River St

1
@steveverrill El tamaño 4 tiene 7 píxeles de ancho. El ancho en píxeles es 2 * size - 1. El tamaño 1 es 1 píxel, el tamaño 2 es 3 píxeles, el tamaño 3 es 5 píxeles (ver ejemplo anterior), el tamaño 4 es 7 píxeles.
Reto Koradi

2
No veo cómo Schrodinger está relacionado con este desafío.
user12205

1
@JonasDralle Nuevamente, el límite de tiempo es principalmente solo una verificación de cordura, y se espera que casi todas las presentaciones se completen en mucho menos tiempo que eso.
Pomo de la puerta

Respuestas:


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

Se puede compilar / ejecutar usando:

gcc laser.c -o laser && echo "10 10 11 10 3" | ./láser

A continuación, el mismo código con espacios en blanco y comentarios 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);
}

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

1
k<=0->k<1
user12205

Buenos puntos. ¡Votaría si pudiera!
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("");}

La entrada se toma de stdin, leyendo los 5 números en el orden definido.

Antes del paso final de reducción de tamaño:

#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("");
  }
}

Alguna explicación de los pasos clave:

  • La matriz bcontiene el estado / resultado. El bit 0 se establecerá para todos los píxeles a los que puede llegar un haz. El bit 1 se establecerá para todos los píxeles que no están cubiertos por todos los haces.
  • fSe llama a la función para las 4 direcciones (vertical, horizontal, ambas diagonales). Sus argumentos especifican el vector normal de la dirección.
  • En función f:
    • La distancia de ambos puntos de entrada con respecto a la dirección se calcula ( dy e) como el producto escalar del punto con el vector normal pasado.
    • Las distancias se intercambian si es necesario para que dsiempre sea menor o igual que e.
    • Si la diferencia entre dy ees mayor que el ancho de la viga, no son posibles en esta dirección.
    • De lo contrario, repita todos los píxeles. Establezca el bit 0 si el haz es accesible por cualquier haz, y el bit 1 si no está cubierto por todos los haces.
  • Marque los dos puntos de entrada con el valor 4. Dado que usamos los bits 0 y 1 para rastrear el estado, que da como resultado los valores 0 a 3, este es el valor más pequeño no utilizado.
  • Recorra los píxeles by convierta los valores en el rango de 0 a 4 a su carácter correspondiente mientras los imprime.

es probable que pueda ahorrar un poco poniendo la última línea de código en el incrementador en ese forbucle
No es que Charles
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.