Лазер Шредінгера


24

Наситившись експериментами над крихітними домашніми тваринами , Нобелівський призер Ервін Шрьодінгер вирішив знайти найближчий лазер і замість цього вистрілити в речі. Тому що ... наука!

Опис

Вам дадуть дві точки, через які проходить лазер, і розмір лазерного променя, і ви повинні визначити, куди повинен був піти лазерний промінь , міг піти, а не міг піти.

Лазерний промінь може бути горизонтальним, вертикальним або діагональним. Для лазерного променя розміром 1 вони виглядають приблизно так:

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

Діагональний лазерний промінь також можна перевернути. Лазерні промені розміром 2 виглядають так:

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

Загалом, щоб отримати лазерний промінь розміром (n), просто візьміть лазерний промінь розміром (n-1) і додайте лазерний промінь розміром (1) з обох сторін. Як остаточний приклад, ось усі можливі лазерні промені розміром 3, показані на одній "дошці":

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

Ця "дошка" завжди матиме розміри 20х20 (у символах).

Вхідні дані

Вашій програмі буде введено п'ять цілих чисел. Вони, по порядку, х 1 , у 1 , х 2 , у 2 , і розмір лазерного променя. Їх треба приймати саме в тому порядку. За бажанням ви можете взяти впорядковані (x, y) пари як масив, кортеж, список чи інший вбудований тип даних, який зберігає два значення.

Обидві точки, подані як вхідні дані, будуть знаходитись у дошці, і вони гарантовано будуть різними (тобто два бали ніколи не будуть однаковими). Розмір лазерного променя пов'язаний з1 ≤ size < 20 . Завжди знайдеться хоча б один можливий лазерний промінь, який проходить через обидві точки.

Вихідні дані

Ваша програма повинна вивести сітку 20х20 таких символів:

  • # якщо кожен можливий лазерний промінь, який проходить через дві точки, також проходить через цю точку.
  • . якщо немає лазерного променя, який проходить через дві точки і цю точку.
  • ? якщо деякі, але не всі, можливі лазерні промені проходять через цю точку.
  • Xякщо це одна з двох початкових вхідних точок (це перевищує значення #).

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

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

Тестові приклади були створені за допомогою наступного сценарію Ruby, розташованого всередині фрагмента стека для збереження вертикального простору.

Правила

  • Ваша програма повинна мати можливість вирішувати кожен тестовий випадок за 30 секунд (на розумній машині). Це більше перевірка здоровості, оскільки моя тестова програма Ruby вирішила всі тестові випадки майже миттєво.

  • Це , тому найкоротше рішення виграє.


2
Термінологія, яка тут використовується, спочатку мене спонукала. Я вважаю, що лазер зазвичай відноситься до пристрою, який виробляє лазерні промені . Те, що ви тут представляєте, насправді балки, правда? Це не повинно бути поданням фактичного лазера, яким був би пристрій, що генерує промені?
Рето Коради

2
Останній тестовий вигляд виглядає неправильно. Лазер розміром 4 повинен бути шириною 9 пікселів. Вертикальна доріжка повинна бути принаймні такою широкою, але насправді вужча.
Рівень Св. Св.

1
@steveverrill Розмір 4 - 7 пікселів. Ширина в пікселях дорівнює 2 * size - 1. Розмір 1 - 1 піксель, розмір 2 - 3 пікселі, розмір 3 - 5 пікселів (див. Приклад вище), розмір 4 - 7 пікселів.
Рето Коради

2
Я не бачу, як Schrodinger пов'язаний з цим викликом.
користувач12205

1
@JonasDralle Знову ж таки, обмеження в часі - це лише перевірка обґрунтованості, і майже кожне подання, як очікується, завершиться за набагато менше часу, ніж це.
Дверна ручка

Відповіді:


5

C, 291 280 277 265 байт

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

Можна скласти / запустити за допомогою:

gcc laser.c -o laser && echo "10 10 11 10 3" | ./лазер

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

// 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.
користувач12205


Хороші бали. Я б схвалив, якби міг!
Андре Хардер

4

C, 302 байти

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

Введення береться зі stdin, читаючи 5 чисел у визначеному порядку.

Перед завершальним кроком зменшення розміру:

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

Деякі пояснення основних кроків:

  • Масив bутримує стан / результат. Біт 0 буде встановлений для всіх пікселів, до яких можна дістатись променем. Біт 1 буде встановлений для всіх пікселів, яких немає охоплені всіма променями.
  • Функція fвикликається для всіх 4 напрямків (вертикальний, горизонтальний, обидві діагоналі). Його аргументи вказують нормальний вектор напрямку.
  • У функції f:
    • Відстань обох вхідних точок відносно напрямку обчислюється ( dі e) як крапковий добуток точки з пройденим нормальним вектором.
    • При необхідності відстані змінюються так, щоб dзавжди було менше або дорівнює e.
    • Якщо різниця між d і eбільша за ширину променя, жодні балки в цьому напрямку не можливі.
    • В іншому випадку переведіть цикл на всі пікселі. Встановіть біт 0, якщо піксель досягається будь-яким променем, і біт 1, якщо він не охоплений усіма променями.
  • Позначте дві вхідні точки значенням 4. Оскільки ми використовували біти 0 і 1 для відстеження стану, в результаті чого отримували значення від 0 до 3, це найменше невикористане значення.
  • Переведіть петлю на пікселі bта перетворять значення в діапазоні від 0 до 4 у відповідний символ, друкуючи їх.

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