Onları Lazerlerle Yok Et


21

Giriş

Arena, düşmanlarınızın örtbas etmek için kullandığı gökdelenlerle dolu bir düzlüktür. Siz ve düşmanlarınız birbirinizi lazerlerle vuruyor. Hepiniz jet paketleri taşıyorsunuz, uçuşa izin veriyorsunuz.

Lazerinle hangi düşmanları vurabilirsin, hangileri saklanıyor?

Sorun

İlk olarak, bir arenanın büyüklüğü, ntek bir satırda bir tamsayı tarafından verilir . Aşağıdaki nsatırlar satır nbaşına boşlukla ayrılmış tam sayıları içerir . Her bir tam sayı, binanın oradaki yüksekliğini gösterir. Her bina dikdörtgen bir katı, 1 birim yüksekliğinde 1 birim.

Ardından, konum üç kayan nokta numaraları gibi tek bir satırda verilmiştir x, y, z.

Son olarak, düşman sayısı mtek bir satırda bir tamsayı tarafından verilir . Aşağıdaki msatırlar, satır başına boşlukla ayrılmış üç kayan nokta sayısı içerir. Bunlar temsil x, yve zbir düşman koordinatlarını. Koordinat sistemi şu şekilde tanımlanmıştır:

  • x şehir girişinde soldan sağa doğru ölçülür
  • y üstten alta ölçülür
  • z sıfırdan ölçülür

Her düşman için, sizden bu düşmana engellenmemiş bir çizgi çizilebiliyorsa, pozitif bir tamsayı elde edin. Aksi takdirde, negatif bir tamsayı üretin. Çıktıları yeni bir satırla ayırın.

Örnek giriş

'#' İle gösterilen yorumlar, her satırın ne yaptığını hızlı bir şekilde görmenize yardımcı olmak için hazırdır. Gerçek girdide bulunmayacaklar.

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

Örnek çıktı

Yukarıdaki örnek giriş için, aşağıdakileri çıkarırız:

-1
1
1

Varsayımlar

  • 0 n<<100
  • 0 m<<100
  • 0 <= x<=n
  • 0 <= y<=n
  • 0 <= z<n
  • Oyuncular binanın bir köşesine, kenarına veya yanına yerleştirilmeyecek
  • Bir düşmana bakış açınız asla bir binanın köşesine, kenarına veya tarafına teğet olmaz
  • Bir oyuncu engel değildir

Kum havuzundan gördüğüme sevindim :)
Timtech

7
Bir düşmanı yok edemezsem onlara katılabilir miyim?
John Dvorak

@ user80551 Maalesef, hatalı yazım kasıtlı olduğu için düzenlemenizi başlığa geri almak zorunda kaldım. Google'da Ara.
Rainbolt

@Rusher Oh, üzgünüm, IDK ki
user80551 15

Yanıtlar:


5

Perl, 301 296 282

Düzenleme 2: Aslında, rekabet olsun ya da olmasın, biraz daha fazla golf oynamanın bir nedeni yoktur. Çevrimiçi olarak test edin .

Düzenleme: Parantez birkaç gitti, sıfır olmayan tamsayı kontrol etmek için basit regex.

Okunabilirlik için yeni satırlara ve girintiye sahip:

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

Bu gerektirir 5.14çünkü skalar (dizi referans) argüman pop.


Çözümünüzü biraz açıklayabilir misiniz? Test etmedim ve henüz Perl'i kaçırmadım, bu yüzden bazı yorumlar iyi olurdu.
WorldSEnder

@WorldSEnder, algoritmanın ana hatları aşağıdaki gibidir. Düz çizgi PE, 3B uzayda, "Oyuncu" (X1Y1Z1) ve "Düşman" (X2Y2Z2) içindeki iki noktayı birleştirir. Onun projeksiyon (XY)düzlemine şebekeye hatlarının bazı tamsayılar yani kesişiyor x = constya y = constgibi X1 < x < X2ya Y1 < y < Y2(yani örneğin burada varsayarak X1 < X2, ama önemli değil). x yBu kesişme noktalarının koordinatları kolayca bulunabilir ve bu nedenle zon- PEline bir noktayı da koordine edebilir .
user2846289

(devam) Öte yandan, herhangi bir x ykoordinat için, hbinanın yüksekliğini biliyoruz (bunun yerine, paylaşan 4 binaya kadar olan maksimum yükseklik x y). Düşman, h < zyukarıda belirtilen tüm "kesişme noktaları" için eğer (ve sadece eğer) vurulabilir . Uygulama bazı temel aritmetiklerin yanı sıra golf oynamak için Perl ile yapılan birkaç püf noktasıdır. Bir ay önce nasıl yaptığımın ayrıntılarını deşifre etmek biraz zaman alacak :-).
user2846289

Argh, gördüğüm gibi son (5) revizyonda bir hata var: ifadedeki @adizinin elemanlarına ilişkin indeksler yerine - grepsıralı görünmeli - üzgünüm. 0,3,0,4,1,5,23,0,3,1,4,2,5
user2846289

Tamam, hiç olmadığı kadar iyi geç, ve tüm bu bitirmek için, burada yorumlanan yorum.
user2846289

3

Python 2.7 - 429 420 308 308 karakter

Bu meydan okumayı bir kod golf probleminden çok bir matematik problemi olarak düşündüm, bu yüzden bazı açık optimizasyonları kaçırdıysam bana çok sert davranma. Neyse, işte 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)

Bu, kenar ve köşe kasaları için çalışmalıdır (istenmeden pun) ve oldukça sağlamdır. Verilen örnek için çıktı:

-1
1
1

Ve işte "kısa" bir açıklama:

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

Sanırım bu kusurlarla dolu. BTW Karakterleri yuvalamada sakladım (ilk seviye bir boşluk, ikinci bir sekme, sonra bir sekme ve bir boşluk ...). İnşallah tüm bu cevaplar bunu yapmanın yolunu gösterebilir.


Sadece örnek girişinin geçersiz olduğunu fark ettim çünkü düşmanlardan biri doğrudan zemine yerleştirilmişti, teknik olarak sıfır yükseklikte bir binanın tepesinde olacaktı. Gönderdiğiniz düzeltilmiş test durumda geçer, ancak bu bir başarısız - ideone.com/8qn3sv . Test davamı kontrol edebilir misin? Bir şey eksik olabilir veya belki koordinat sistemim belirsiz.
Rainbolt

Hayır, sadece vektör köşelere doğru gidiyor ... şimdi neden Varsayım 6 & 7'ye söz verdiğini biliyorum :)
WorldSEnder

btw, negatif bir kayan nokta çıktım ama bu 2 ekstra karakterle ( print 1-2*...bunun yerine print.5-...) sabitlenebilir . Bu yüzden sanırım o kadar büyük bir fark değil
WorldSEnder

Geldiğim birkaç testten geçtin. İyi iş! Hala devam etmeli ve teknik özelliklere uymasını sağlamak için tamsayıları yazdırmalısınız.
Rainbolt

1
Daha iyi bir çözüm bulana kadar cevabınızı kabul etmek. Onların olacağını sanmıyorum. Çok nadiren kimse eski çözülmüş zorlukları tekrar ziyaret eder. Daha çok golf oynamalısın! Eşyalarını biliyor gibisin. :)
Rainbolt

2

C - 2468

Hiç golf oynamayın, ama umarım daha ilginç uygulamalar için bir başlangıç ​​noktasıdır. Uygulaması intersectyoğun olarak Adrian Boeing'den alınmıştır . Sahte kodu eksikti, ancak matematiğe olan açıklaması paha biçilmezdi. Temel fikir, oyuncudan hedefe doğru bir çizgi çekip her bir binanın duvarlarına klipsleyerek her duvarın uzunluğunu güncellemektir. Kalan uzunluk binanın içindeki kısımdır, yani sıfırsa kesişme olmazdı.

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

Birkaç test davası denedim ve hepsini geçtin. İşte başkalarının doğrulamak için kullanabileceği ideone
ideone.com/MTXpzF
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.