Zniszcz je Lazers

21

Wprowadzenie

Arena to równina usiana wieżowcami, które twoi wrogowie wykorzystują jako schronienie. Ty i twoi wrogowie strzelacie do siebie za pomocą laserów. Wszyscy nosicie plecaki odrzutowe, pozwalające na lot.

Których wrogów możesz trafić laserem, a którzy ukrywają się?

Problem

Po pierwsze, rozmiar areny jest podawany przez liczbę całkowitą nw jednym wierszu. Następujące nwiersze zawierają nliczby całkowite w wierszu oddzielone spacją. Każda liczba całkowita reprezentuje wysokość budynku w tym miejscu. Każdy budynek jest prostokątną bryłą, 1 jednostka na 1 jednostkę według jednostek wysokości.

Następnie Twoja lokalizacja podana jest na jednej linii, co trzech liczb zmiennoprzecinkowych x, y, z.

Na koniec liczbę wrogów podaje liczba całkowita mw jednym wierszu. Następne mlinie zawierają trzy liczby zmiennoprzecinkowe na linię oddzielone spacją. Te reprezentują x, yoraz zwspółrzędne wroga. Układ współrzędnych jest zdefiniowany następująco:

  • x jest mierzony od lewej do prawej na wejściu miasta
  • y mierzy się od góry do dołu
  • z jest mierzony od podstaw

Jeśli dla każdego wroga można narysować od niego niezakłóconą linię, wypisz dodatnią liczbę całkowitą. W przeciwnym razie wypisz ujemną liczbę całkowitą. Oddziel wyjścia za pomocą nowej linii.

Przykładowe dane wejściowe

Komentarze oznaczone jako „#” są obecne, aby pomóc Ci szybko zobaczyć, co robi każda linia. Nie będą one obecne w rzeczywistych danych wejściowych.

5              # Size of the map
0 0 0 0 0      # Buildings
0 0 0 0 0      # Buildings
4 4 4 4 4      # Buildings
0 0 0 0 0      # Buildings
0 0 0 0 0      # Buildings
2.5 0.0 4.0    # Your location
3              # Number of enemies
2.5 5.0 0.1    # Enemy location
2.5 5.0 5.0    # Enemy location
0.0 2.7 4.5    # Enemy location

Próbka wyjściowa

Dla powyższego przykładowego danych wyjściowych wyprowadzamy następujące dane:

-1
1
1

Założenia

  • 0 n<<100
  • 0 m<<100
  • 0 <= x<=n
  • 0 <= y<=n
  • 0 <= z<n
  • Gracze nie będą znajdować się na ani wewnątrz narożnika, krawędzi ani boku budynku
  • Twoja linia wzroku do wroga nigdy nie będzie styczna do rogu, krawędzi lub boku budynku
  • Gracz nie jest przeszkodą
Rainbolt
źródło
Cieszę się, że widzę to z piaskownicy :)
Timtech
7
Jeśli nie mogę zniszczyć wroga, czy mogę do niego dołączyć?
John Dvorak
@ user80551 Przepraszam, musiałem przywrócić edycję do tytułu, ponieważ błędne pisanie było celowe. Wygoogluj to.
Rainbolt
@ Rusher Och, przepraszam, IDK że
użytkownik80551

Odpowiedzi:

5

Perl, 301 296 282

Edycja 2: Właściwie, konkurencja czy nie, nie ma powodu, aby nie grać w nią trochę dalej. Przetestuj online .

Edycja: Kilka nawiasów zniknęło, prostsze wyrażenie regularne, aby sprawdzić niezerową liczbę całkowitą.

Z nowymi liniami i wcięciem dla czytelności:

sub i{<>=~/\S+/g}
@b=map[i],@r=0..<>-1;
print.1<=>(map{
    @a[1,0,2,4,3]=@a;
    @b=map{$i=$_;[map$b[$_][$i],@r]}@r;
    grep$a[3]
        &&($k=(($x=$_)-$a[0])/$a[3])**2<=$k
        &&pop[sort map@{$b[$_]}[$x-!!$x,$x],
                   ($_=$a[1]+$k*$a[4]),$_-/^\d+$/]
           >=$a[2]+$k*$a[5]
    ,@R=@r
}@a=map$_-shift@v,i,@u=@v=@$_),$/for([i])x<>

Wymaga 5.14to argumentu skalarnego (odwołanie do tablicy) pop.

użytkownik 2846289
źródło
Czy możesz trochę wyjaśnić swoje rozwiązanie? Nie testowałem tego i nie opieram się jeszcze na Perlu, więc niektóre komentarze byłyby miłe.
WorldSEnder
@WorldSEnder, zarys algorytmu jest następujący. Linia prosta PEłączy dwa punkty w przestrzeni trójwymiarowej: „Player” (X1Y1Z1) i „Enemy” (X2Y2Z2). Jego rzut na (XY)płaszczyznę przecina niektóre linie siatki, tj. Liczby całkowite x = constlub y = consttakie jak X1 < x < X2lub Y1 < y < Y2(zakładając, że np. X1 < X2Ale nie jest to ważne). x yMożna łatwo znaleźć współrzędne tych skrzyżowań, a zatem także zwspółrzędne punktu na PElinii.
user2846289
(ciąg dalszy) Z drugiej strony, dla dowolnych x ywspółrzędnych znamy wysokość hbudynku (raczej maksymalną wysokość maksymalnie 4 budynków, które dzielą x ypunkt). Wróg może zostać zastrzelony, jeśli (i tylko wtedy) h < zdla wszystkich „punktów przecięcia” wymienionych powyżej. Implementacja to podstawowa arytmetyka, a także kilka sztuczek z Perlem na potrzeby gry w golfa. Rozszyfrowanie szczegółów, jak to zrobiłem miesiąc temu, zajmie teraz trochę czasu :-).
user2846289
Argh, jak widzę, w ostatniej (5.) wersji jest błąd: indeksy elementów @atablicy w grepwyrażeniu powinny pojawiać się w kolejności 0,3,0,4,1,5,2zamiast 3,0,3,1,4,2,5- przepraszam.
user2846289
OK, lepiej późno niż wcale, a na koniec wszystko to, tutaj jest skomentowana wersja.
user2846289,
3

Python 2.7 - 429 420 308 308 znaków

Pomyślałem o tym wyzwaniu bardziej jako problem matematyczny niż problem z golfem, więc nie bądź dla mnie zbyt surowy, jeśli przegapię jakieś oczywiste optymalizacje. Tak czy inaczej, oto kod:

b=lambda:raw_input().split()
m=map
d=range(input())
h=[m(int,b())for _ in d]
x,y,z=m(float,b())
for e,f,g in[m(float,b())for _ in[1]*input()]:o=lambda x,y,u,v,i,j:i<=x+u/v*(j+1-y)<=i+1<[]>z+(g-z)/v*(j+1-y)<=max(h[i][j:j+2])if v else 0;print 1-2*any(o(x,y,e-x,f-y,j,i)+o(y,x,f-y,e-x,i,j)for j in d for i in d)

Powinno to działać w przypadku krawędzi i narożników (niezamierzone kalambur) i jest dość solidne. Ouput dla podanego przykładu:

-1
1
1

A oto „krótkie” wyjaśnienie:

fast_read = lambda : raw_input().split() # define a helper
# m = map another helper
grid_range = range(input())
houses = [map(int, fast_read()) for _ in grid_range]
# 'map(int,...)' is a shorter version of '[int(a) for a in ...]'
pos_x,pos_y,pos_z = map(float, fast_read()) # read the player position
# the following loops through all enemy coordinates
for ene_x, ene_y, ene_z in [map(float,fast_read()) for _ in[1]*input()]:
    vec_z = ene_z - pos_z
    # is_hit macro uses vector math to detemine whether we hit a specific wall
    # wallhit -> 1
    # no wallhit -> 0
    is_hit = lambda pos_x, pos_y, vec_x, vec_y, co_x, co_y:\
        (co_x <= pos_x + vec_x/vec_y * (co_y + 1 - pos_y) <= co_x + 1 # check if hit_x is good
        < [] > # an effective and
        pos_z + (ene_z - pos_z)/vec_y * (co_y + 1 - pos_y) <= max(houses[co_x][co_y:co_y + 2]) # check if hit_z is good
        if vec_y else 0) # if vec_y is 0 we can't hit the wall parallel to y
    print (.5 - # can hit -> 0.5 - 0 = 0.5, hit -> 0.5 - 1 = -0.5
            any( # if we hit any wall
                # we swap x and y-coordinate because we read them "incorrect"
                is_hit(pos_x, pos_y, ene_x-pos_x, ene_y-pos_y, cur_y, cur_x) # check for hit in x-direction
                + # effective 'or'
                is_hit(pos_y, pos_x, ene_y-pos_y, ene_x-pos_x, cur_x, cur_y) # check for hit in y-direction
                    for cur_y in grid_range # loop y
                for cur_x in grid_range)) # loop x

Myślę, że to jest pełne wad. Przy okazji zapisałem znaki podczas zagnieżdżania (pierwszy poziom to jedna spacja, druga jedna tabulacja, następnie jedna tabulacja i spacja ...). Mam nadzieję, że mimo wszystko ta odpowiedź może wskazać sposób na zrobienie tego.

WorldSEnder
źródło
Właśnie zdałem sobie sprawę, że przykładowe dane wejściowe były nieprawidłowe, ponieważ jeden z wrogów znajdował się bezpośrednio na ziemi, co technicznie jest szczytem budynku o zerowej wysokości, co, jak obiecałem, nie nastąpi. Twoje zgłoszenie przechodzi poprawiony przypadek testowy, ale nie spełnia tego - ideone.com/8qn3sv . Czy możesz sprawdzić mój przypadek testowy? Być może czegoś mi brakuje, a może mój układ współrzędnych jest niejasny.
Rainbolt
Nie, po prostu wektor przechodzi przez rogi ... teraz wiem, dlaczego obiecałeś Wniebowzięcie 6 i 7 :)
WorldSEnder
btw, wyprowadzam ujemną print 1-2*...liczbę zmiennoprzecinkową, ale można to naprawić za pomocą 2 dodatkowych znaków ( zamiast print.5-...) Więc nie jest to duża różnica, tak sądzę
WorldSEnder
Zdałeś kilka testów, które wymyśliłem. Dobra robota! Nadal powinieneś iść naprzód i sprawić, aby drukował liczby całkowite, aby zachować zgodność ze specyfikacją.
Rainbolt
1
Przyjmowanie odpowiedzi, dopóki ktoś nie wymyśli lepszego rozwiązania. Nie sądzę, że będą. Bardzo rzadko ktoś powraca do starych rozwiązanych problemów. Powinieneś więcej grać w golfa! Wygląda na to, że znasz swoje rzeczy. :)
Rainbolt
2

C - 2468

W ogóle nie grałem w golfa, ale mam nadzieję, że jest to punkt wyjścia do ciekawszych wdrożeń. Implementacja intersectjest w dużej mierze szopowana przez Adriana Boeinga . Jego pseudokod był niekompletny, ale wyjaśnienie matematyki było bezcenne. Podstawową ideą jest przeniesienie linii od gracza do celu i przypięcie jej do wszystkich ścian każdego budynku, aktualizując długość każdej ściany. Pozostała długość to część wewnątrz budynku, więc jeśli wynosi zero, nie było przecięcia.

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

typedef struct
{
    float x;
    float y;
    float z;
} vec3;

float
dot(vec3 a, vec3 b)
{
    return a.x * b.x + a.y * b.y + a.z * b.z;
}

vec3
scale(float s, vec3 a)
{
    vec3 r;
    r.x = s * a.x;
    r.y = s * a.y;
    r.z = s * a.z;
    return r;
}

vec3
add(vec3 a, vec3 b)
{
    vec3 r;
    r.x = a.x + b.x;
    r.y = a.y + b.y;
    r.z = a.z + b.z;
    return r;
}

int
intersect(vec3 a, vec3 b, vec3 *normals, vec3 *points, int nnormals)
{
    vec3 ab = add(b, scale(-1, a));
    float tfirst = 0;
    float tlast = 1;
    int i;
    for(i = 0; i < nnormals; i++)
    {
        float d = dot(normals[i], points[i]);
        float denom = dot(normals[i], ab);
        float dist = d - dot(normals[i], a);
        float t = dist / denom;
        if(denom > 0 && t > tfirst)
        {
            tfirst = t;
        }
        else if(denom < 0 && t < tlast)
        {
            tlast = t;
        }
    }
    return tfirst < tlast ? 1 : 0;
}

const vec3 N = {0,-1,0};
const vec3 S = {0,1,0};
const vec3 W = {-1,0,0};
const vec3 E = {1,0,0};
const vec3 D = {0,0,-1};

int
main(void)
{
    vec3 normals[5];
    vec3 player;
    vec3 *targets;
    int i;
    int j;
    vec3 *buildings;
    vec3 *b;
    int nbuildings = 0;
    int n;
    int m;
    char line[300];
    normals[0] = N;
    normals[1] = S;
    normals[2] = W;
    normals[3] = E;
    normals[4] = D;
    fgets(line, 300, stdin);
    n = atoi(line);
    /*5 sides for each building*/
    buildings = calloc(n * n * 5, sizeof(*buildings));
    b = buildings;
    for(i = 0; i < n; i++)
    {
        char *z;
        fgets(line, 300, stdin);
        for(j = 0; j < n && (z = strtok(j ? NULL : line, " \n")) != NULL; j++)
        {
            vec3 bottom;
            vec3 top;
            if(z[0] == '0') continue;
            nbuildings++;
            bottom.x = j;
            bottom.y = i;
            bottom.z = 0;
            top.x = j + 1;
            top.y = i + 1;
            top.z = atoi(z);
            b[0] = top;
            b[1] = bottom;
            b[2] = top;
            b[3] = bottom;
            b[4] = top;
            b += 5;
        }
    }
    fgets(line, 300, stdin);
    player.x = atof(strtok(line, " "));
    player.y = atof(strtok(NULL, " "));
    player.z = atof(strtok(NULL, " \n"));
    fgets(line, 300, stdin);
    m = atoi(line);
    targets = calloc(m, sizeof(*targets));
    for(i = 0; i < m; i++)
    {
        int hit = 1;
        fgets(line, 300, stdin);
        targets[i].x = atof(strtok(line, " "));
        targets[i].y = atof(strtok(NULL, " "));
        targets[i].z = atof(strtok(NULL, " \n"));
        for(j = 0; j < nbuildings; j++)
        {
            b = &buildings[j * 5];
            if(intersect(player, targets[i], normals, b, 5) == 1)
            {
                hit = 0;
                break;
            }
        }
        printf("%d\n", hit ? 1 : -1);
    }
    free(buildings);
    free(targets);
    return 0;
}
laindir
źródło
Wypróbowałem kilka przypadków testowych i zdałeś wszystkie. Oto ideone, których każdy może użyć do weryfikacji - ideone.com/MTXpzF
Rainbolt