Schrödingers Laser


24

Der Nobelpreisträger Erwin Schrödinger hat es satt, mit winzigen Haustieren zu experimentieren , und hat sich entschlossen, den nächsten Laser zu finden und auf Dinge zu schießen. Weil ... Wissenschaft!

Beschreibung

Sie erhalten zwei Punkte, die der Laser durchläuft, und die Größe eines Laserstrahls, und Sie müssen bestimmen, wohin der Laserstrahl gegangen sein muss , hätte gehen können und hätte nicht gehen können.

Der Laserstrahl kann horizontal, vertikal oder diagonal sein. Für einen Laserstrahl der Größe 1 sehen sie jeweils folgendermaßen aus:

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

Der diagonale Laserstrahl kann auch gekippt werden. Laserstrahlen der Größe 2 sehen folgendermaßen aus:

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

Um einen Laserstrahl der Größe (n) zu erhalten, nehmen Sie im Allgemeinen einfach den Laserstrahl der Größe (n-1) und fügen Sie auf beiden Seiten einen Laserstrahl der Größe (1) hinzu. Als letztes Beispiel sind hier alle möglichen Laserstrahlen der Größe 3 auf derselben "Tafel" dargestellt:

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

Diese "Tafel" hat immer Abmessungen von 20x20 (in Zeichen).

Eingang

Ihr Programm erhält fünf Ganzzahlen als Eingabe. Sie sind in der Reihenfolge x 1 , y 1 , x 2 , y 2 und der Größe des Laserstrahls. Sie müssen genau in dieser Reihenfolge genommen werden. Wenn Sie möchten, können Sie die geordneten (x, y) Paare als Array, Tupel, Liste oder anderen integrierten Datentyp verwenden, der zwei Werte speichert.

Beide als Eingabe angegebenen Punkte befinden sich innerhalb der Tafel und sind garantiert unterschiedlich (dh die beiden Punkte sind niemals gleich). Die Größe des Laserstrahls ist gebunden an 1 ≤ size < 20. Es wird immer mindestens einen möglichen Laserstrahl geben, der beide Punkte passiert.

Ausgabe

Ihr Programm muss ein 20x20-Raster mit den folgenden Zeichen ausgeben:

  • # wenn jeder mögliche Laserstrahl, der die beiden Punkte passiert, auch diesen Punkt passiert.
  • . wenn es keinen Laserstrahl gibt, der durch die beiden Punkte und diesen Punkt geht.
  • ? wenn einige, aber nicht alle der möglichen Laserstrahlen diesen Punkt passieren.
  • XWenn dies einer der beiden ursprünglichen Eingabepunkte ist (dies überschreibt den #).

Testfälle

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

Die Testfälle wurden mit dem folgenden Ruby-Skript generiert, das sich in einem Stack-Snippet befindet, um vertikalen Platz zu sparen.

Regeln

  • Ihr Programm muss in der Lage sein, jeden der Testfälle in weniger als 30 Sekunden (auf einem vernünftigen Computer) zu lösen. Dies ist eher eine Überprüfung der geistigen Gesundheit, da mein Ruby-Testprogramm alle Testfälle nahezu augenblicklich löste.

  • Das ist , also gewinnt die kürzeste Lösung.


2
Die hier verwendete Terminologie hat mich anfangs auf den Kopf gestellt. Ich glaube, Laser bezieht sich normalerweise auf ein Gerät, das Laserstrahlen erzeugt . Was Sie hier repräsentieren, sind wirklich die Strahlen, richtig? Dies soll keine Darstellung des tatsächlichen Lasers sein. Welches Gerät erzeugt die Strahlen?
Reto Koradi

2
Der letzte Testfall sieht falsch aus. Ein Laser der Größe 4 sollte 9 Pixel breit sein. Die vertikale Spur sollte mindestens so breit sein, ist aber tatsächlich schmaler.
Level River St

1
@steveverrill Größe 4 ist 7 Pixel breit. Die Breite in Pixel beträgt 2 * size - 1. Größe 1 ist 1 Pixel, Größe 2 ist 3 Pixel, Größe 3 ist 5 Pixel (siehe Beispiel oben), Größe 4 ist 7 Pixel.
Reto Koradi

2
Ich verstehe nicht, wie Schrödinger mit dieser Herausforderung zusammenhängt.
user12205

1
@JonasDralle Auch hier ist das Zeitlimit meist nur eine Plausibilitätsprüfung, und es wird erwartet, dass fast jede Einreichung in viel kürzerer Zeit abgeschlossen wird.
Türklinke

Antworten:


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

Kann kompiliert / ausgeführt werden mit:

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

Unten derselbe Code mit Leerzeichen und erklärenden Kommentaren:

// 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 18.06.15

Gute Argumente. Ich würde stimmen, wenn ich könnte!
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("");}

Die Eingabe erfolgt von stdin und liest die 5 Zahlen in der festgelegten Reihenfolge.

Vor dem letzten Zerkleinerungsschritt:

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

Einige Erklärungen zu den wichtigsten Schritten:

  • Array benthält den Zustand / das Ergebnis. Bit 0 wird für alle Pixel gesetzt, die von einem Strahl erreicht werden können. Bit 1 wird für alle Pixel gesetzt, die nicht von allen Strahlen abgedeckt werden.
  • Die Funktion fwird für alle 4 Richtungen aufgerufen (vertikal, horizontal, beide Diagonalen). Ihre Argumente geben den Normalenvektor der Richtung an.
  • In Funktion f:
    • Der Abstand beider Eingabepunkte zur Richtung wird ( dund e) als Skalarprodukt des Punktes mit dem übergebenen Normalenvektor berechnet .
    • Die Abstände werden bei Bedarf vertauscht, so dass dimmer kleiner oder gleich ist e.
    • Ist der Unterschied zwischen d und egrößer als die Breite des Strahls, sind in dieser Richtung keine Strahlen möglich.
    • Andernfalls durchlaufen Sie alle Pixel. Setzen Sie Bit 0, wenn das Pixel von einem Strahl erreicht werden kann, und Bit 1, wenn es nicht von allen Strahlen abgedeckt wird.
  • Markieren Sie die beiden Eingabepunkte mit dem Wert 4. Da wir zur Verfolgung des Zustands die Bits 0 und 1 verwendet haben, was zu den Werten 0 bis 3 führt, ist dies der kleinste nicht verwendete Wert.
  • Durchlaufen Sie die Pixel in bund konvertieren Sie die Werte im Bereich von 0 bis 4 in die entsprechenden Zeichen, während Sie sie ausdrucken.

Sie können wahrscheinlich ein wenig sparen, indem Sie die letzte Codezeile in den Inkrementierer in dieser forSchleife einfügen
nicht diesen Charles
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.