Hancurkan Mereka Dengan Lazers

21

pengantar

Arena ini adalah dataran datar yang dipenuhi gedung pencakar langit, yang digunakan musuh untuk berlindung. Anda dan musuh Anda saling menembak dengan laser. Anda semua membawa paket jet, memungkinkan penerbangan.

Musuh mana yang bisa Anda pukul dengan laser, dan yang bersembunyi?

Masalah

Pertama, ukuran arena diberikan oleh integer npada satu baris. Baris berikut nberisi nbilangan bulat per baris yang dipisahkan oleh spasi. Setiap bilangan bulat mewakili ketinggian bangunan di lokasi itu. Setiap bangunan adalah benda padat persegi panjang, 1 unit kali 1 unit dengan unit tinggi.

Berikutnya, lokasi Anda diberikan pada satu baris tiga angka floating point x, y, z.

Akhirnya, jumlah musuh diberikan oleh integer mpada satu baris. Baris berikut mberisi tiga angka floating point per baris yang dipisahkan oleh spasi. Ini mewakili x, ydan zkoordinat musuh. Sistem koordinat didefinisikan sebagai berikut:

  • x diukur dari kiri ke kanan di input kota
  • y diukur dari atas ke bawah
  • z diukur dari bawah ke atas

Untuk setiap musuh, jika garis yang tidak terhalang dapat ditarik dari Anda ke musuh itu, berikan bilangan bulat positif . Jika tidak, hasilkan bilangan bulat negatif . Pisahkan output dengan baris baru.

Input Sampel

Komentar, dilambangkan dengan '#', hadir untuk membantu Anda dengan cepat melihat apa yang dilakukan setiap baris. Mereka tidak akan hadir dalam input aktual.

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

Output sampel

Untuk input sampel di atas, kami menampilkan yang berikut:

-1
1
1

Asumsi

  • 0 n<<100
  • 0 m<<100
  • 0 <= x<=n
  • 0 <= y<=n
  • 0 <= z<n
  • Pemain tidak akan berlokasi di atau di dalam sudut, tepi, atau sisi bangunan
  • Garis pandang Anda kepada musuh tidak akan pernah bersinggungan dengan sudut, tepi, atau sisi bangunan
  • Seorang pemain bukan halangan
Rainbolt
sumber
Senang melihatnya keluar dari kotak pasir :)
Timtech
7
Jika saya tidak dapat menghancurkan musuh, bolehkah saya bergabung dengan mereka?
John Dvorak
@ user80551 Maaf, saya harus memutar kembali edit Anda ke judul karena kesalahan mengeja disengaja. Google itu.
Rainbolt
@Rusher Oh, maaf, IDK itu
user80551

Jawaban:

5

Perl, 301 296 282

Sunting 2: Sebenarnya, kompetisi atau tidak, tidak ada alasan untuk tidak bermain golf sedikit lebih jauh. Uji secara online .

Sunting: Beberapa tanda kurung hilang, regex sederhana untuk memeriksa bilangan bulat tidak nol.

Dengan baris baru dan lekukan agar mudah dibaca:

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

Ini membutuhkan 5.14argumen skalar (referensi array) untuk pop.

pengguna2846289
sumber
Bisakah Anda menjelaskan sedikit solusi Anda? Saya belum mengujinya dan belum mencondongkan Perl, jadi beberapa komentar akan menyenangkan.
WorldSEnder
@WorldSEnder, garis besar algoritme adalah sebagai berikut. Garis lurus PEmenghubungkan dua titik dalam ruang 3-D, "Player" (X1Y1Z1) dan "Musuh" (X2Y2Z2). Proyeksi pada (XY)bidang memotong beberapa garis grid yaitu bilangan bulat x = constatau y = constseperti X1 < x < X2atau Y1 < y < Y2(dengan asumsi di sini misalnya X1 < X2, tetapi tidak penting). Koordinat x ypersimpangan ini dapat dengan mudah ditemukan, dan karenanya zmengkoordinasikan titik pada PEgaris juga.
user2846289
(lanjutan) Di sisi lain, untuk x ykoordinat apa pun , kita mengetahui ketinggian hbangunan (lebih tepatnya, ketinggian maksimum hingga 4 bangunan yang memiliki x ytitik berbagi ). Musuh dapat ditembak jika (dan hanya jika) h < zuntuk semua "titik persimpangan" yang disebutkan di atas. Implementasi adalah beberapa aritmatika dasar, serta beberapa trik dengan Perl untuk tujuan bermain golf. Menguraikan detail bagaimana saya melakukannya sebulan yang lalu akan memakan waktu sekarang :-).
user2846289
Argh, seperti yang saya lihat ada bug di revisi (5) terakhir: indeks ke elemen @aarray dalam grepekspresi harus muncul dalam urutan 0,3,0,4,1,5,2alih-alih 3,0,3,1,4,2,5- maaf.
user2846289
OK, lebih baik terlambat daripada tidak pernah, dan untuk menyelesaikan ini semua, di sini adalah versi komentar.
user2846289
3

Python 2.7 - 429 420 308 308 karakter

Saya menganggap tantangan ini lebih sebagai masalah matematika daripada masalah golf kode, jadi jangan terlalu keras bagi saya jika saya melewatkan beberapa optimasi yang jelas. Bagaimanapun, ini kodenya:

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)

Ini harus bekerja untuk kasus tepi dan sudut (pun tidak diinginkan) dan cukup solid. Ouput untuk contoh yang diberikan:

-1
1
1

Dan inilah penjelasan "singkat":

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

Saya kira ini penuh dengan kekurangan. Btw saya menyimpan karakter di nesting (level pertama adalah satu spasi, tab kedua, lalu satu tab dan spasi ...). Saya berharap setelah semua jawaban ini dapat menunjukkan cara untuk melakukannya.

WorldSEnder
sumber
Saya baru menyadari bahwa input sampel tidak valid karena salah satu musuh terletak tepat di tanah, yang secara teknis bagian atas bangunan dengan ketinggian nol, yang saya janjikan tidak akan terjadi. Kiriman Anda lolos dari test case yang dikoreksi, tetapi gagal yang satu ini - ideone.com/8qn3sv . Bisakah Anda memeriksa test case saya? Saya mungkin kehilangan sesuatu atau mungkin sistem koordinat saya tidak jelas.
Rainbolt
Tidak, hanya saja vektornya menembus sudut ... sekarang saya tahu mengapa Anda berjanji Asumsi 6 & 7 :)
WorldSEnder
btw, saya menghasilkan float negatif tapi itu bisa diperbaiki dengan 2 karakter tambahan ( print 1-2*...bukan print.5-...) Jadi saya kira tidak ada perbedaan besar
WorldSEnder
Anda melewati beberapa tes yang saya buat. Pekerjaan yang baik! Anda harus tetap melanjutkan dan membuatnya mencetak bilangan bulat agar sesuai dengan spesifikasi.
Rainbolt
1
Menerima jawaban Anda sampai seseorang menemukan solusi yang lebih baik. Saya tidak berpikir mereka akan melakukannya. Sangat jarang ada orang yang melihat kembali tantangan lama yang sudah terpecahkan. Anda harus bermain golf lebih banyak! Sepertinya Anda tahu barang-barang Anda. :)
Rainbolt
2

C - 2468

Tidak bermain golf sama sekali, tapi mudah-mudahan ini merupakan titik awal untuk implementasi yang lebih menarik. Implementasi intersectini banyak dikutip dari Adrian Boeing . Pseudo-code-nya tidak lengkap, tetapi penjelasannya tentang matematika sangat berharga. Ide dasarnya adalah Anda mengambil garis dari pemain ke target dan menempelkannya ke semua dinding di setiap bangunan, memperbarui panjang untuk setiap dinding. Panjang yang tersisa adalah bagian di dalam gedung, jadi jika nol, tidak ada persimpangan.

#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
sumber
Sudah mencoba beberapa test case dan kamu lulus semuanya. Berikut adalah ideone bahwa orang lain dapat digunakan untuk memverifikasi - ideone.com/MTXpzF
Rainbolt