레이저로 그들을 파괴


21

소개

경기장은 고층 건물이 점재되어있는 평지입니다. 당신과 당신의 적들은 레이저로 서로를 쏴. 여러분 모두는 제트 팩을 가지고 다니므로 비행이 가능합니다.

레이저로 어떤 적을 공격 할 수 있습니까?

문제

먼저, 경기장의 크기 n는 한 줄에 정수 로 표시됩니다. 다음 nn은 공백으로 구분 된 줄당 정수를 포함 합니다. 각 정수는 해당 위치의 건물 높이를 나타냅니다. 각 건물은 직사각형 단위로 1 단위 x 1 단위의 높이 단위입니다.

다음으로, 당신의 위치가 세 개의 부동 소수점 숫자로 한 줄에 기재되어 있습니다 x, y, z.

마지막으로 적의 수 m는 한 줄에 정수 로 표시됩니다. 다음 m줄은 한 줄에 공백으로 구분 된 3 개의 부동 소수점 숫자를 포함합니다. 이들은 대표 x, y그리고 z적의 좌표를. 좌표계는 다음과 같이 정의됩니다.

  • x 도시 입력에서 왼쪽에서 오른쪽으로 측정됩니다
  • y 위에서 아래로 측정
  • z 처음부터 측정

각각의 적에 대해 방해받지 않는 선을 그 적에게 끌 수 있다면 양의 정수를 출력합니다 . 그렇지 않으면 음수를 출력합니다 . 출력을 새 줄로 분리하십시오.

샘플 입력

'#'으로 표시된 주석은 각 행의 기능을 빠르게 볼 수 있도록 도와줍니다. 실제 입력에는 나타나지 않습니다.

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

샘플 출력

위의 샘플 입력에 대해 다음을 출력합니다.

-1
1
1

가정

  • 0 << n100
  • 0 << m100
  • 0 <= x<=n
  • 0 <= y<=n
  • 0 <= z<n
  • 플레이어는 건물의 모서리, 가장자리 또는 측면에 위치하지 않습니다
  • 적의 시선은 건물의 모서리, 모서리 또는 측면에 접하지 않습니다.
  • 플레이어는 장애물이 아닙니다

샌드 박스
보니 기쁘다

7
적을 파괴 할 수 없다면 그들과 합류 할 수 있습니까?
John Dvorak

@ user80551 죄송합니다. 맞춤법이 틀렸으므로 제목으로 수정 사항을 롤백해야했습니다. 구글 그것.
Rainbolt

@Rusher 오, 죄송합니다, IDK는
user80551 2016 년

답변:


5

펄, 301 296 282

편집 2 : 실제로 경쟁 여부에 관계없이 골프를 조금 더하지 않을 이유는 없습니다. 온라인으로 테스트하십시오 .

편집 : 괄호가 사라지고 정수가 아닌 정수를 확인하는 간단한 정규식.

가독성을위한 줄 바꿈과 들여 쓰기

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

5.14대한 스칼라 (배열 참조) 인수 때문에 필요 합니다 pop.


솔루션을 조금 설명해 주시겠습니까? 나는 그것을 테스트하지 않았고 Perl을 빌려주지 않았으므로 일부 의견은 좋을 것입니다.
WorldSEnder

@WorldSEnder에서 알고리즘의 개요는 다음과 같습니다. 직선 PE은 3D 공간에서 "플레이어"(X1Y1Z1)와 "적"(X2Y2Z2)의 두 점을 연결합니다. 에 미치는 투사 (XY)평면은 그리드 라인의 일부는 정수, 즉 교차 x = const또는 y = const같은 X1 < x < X2Y1 < y < Y2(즉, 예를 들어, 여기에 가정을 X1 < X2, 그러나 그것은 중요하지 않습니다). x y이러한 교차점의 좌표 를 쉽게 찾을 수 있으므로 z점의 좌표도 쉽게 찾을 수 있습니다 PE.
user2846289

(계속) 다른 x y좌표 h의 경우 건물의 높이 ( x y점 을 공유하는 최대 4 개의 건물의 최대 높이)를 알고 있습니다. h < z위에서 언급 한 모든 "교차점"에 대해 적을 사격 할 수 있습니다 . 구현은 기본적인 산술과 펄을 이용한 몇 가지 트릭으로 골프를 목적으로합니다. 한 달 전에 내가 한 일의 세부 사항을 해독하는 데는 약간의 시간이 걸립니다.
user2846289

내가 마지막 (5) 개정에 버그가 보는 바와 같이 아아, :의 요소 인덱스 @a의 배열 grep표현은 순서대로 표시한다 0,3,0,4,1,5,2대신 3,0,3,1,4,2,5- 죄송합니다.
user2846289

좋아, 결코 늦지 않는 것이 낫고,이 모든 것을 끝내려면 여기 에 주석이 달린 버전이 있습니다.
user2846289

3

파이썬 2.7 - (429 개) 420 308 308 문자

나는이 도전을 코드 골프 문제보다 수학 문제라고 생각했기 때문에 명확한 최적화를 놓친 경우 나에게 너무 가혹하지 마십시오. 어쨌든, 여기 코드가 있습니다 :

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)

이것은 가장자리와 모서리의 경우 (의도하지 않은 방향으로) 작동하며 꽤 견고합니다. 제공된 예제의 출력 :

-1
1
1

그리고 여기에 "짧은"설명이 있습니다 :

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

나는 이것이 결함으로 가득 찬 것 같아요. Btw 나는 중첩시 문자를 저장했습니다 (첫 번째 레벨은 한 칸, 두 번째는 탭, 한 개의 탭과 공백입니다 ...). 나는이 모든 대답이 그것을 할 수있는 길을 가리킬 수 있기를 바랍니다.


방금 적 중 하나가 지상에 직접 위치했기 때문에 샘플 입력이 유효하지 않다는 것을 깨달았습니다. 기술적으로 는 높이가 0 인 건물의 꼭대기에 있습니다. 제출 한 내용이 수정 된 테스트 사례를 통과했지만이 one-ideone.com/8qn3sv에 실패합니다 . 내 테스트 케이스를 확인할 수 있습니까? 무언가가 없거나 좌표계가 명확하지 않을 수 있습니다.
Rainbolt

아니, 그것은 단지 벡터가 모퉁이를 가로 질러 가고 있다는 것입니다 ... 이제 나는 당신이 가정 6 & 7을 약속 한 이유를 알고 있습니다 :)
WorldSEnder

BTW, I 출력 음의 플로트하지만 2 개 여분의 문자 (고정 할 수 있습니다 print 1-2*...대신 print.5-...그 차이의 큰 내가 생각하는 것이 아니다 그래서)
WorldSEnder

내가 만든 몇 가지 테스트를 통과했습니다. 좋은 작업! 계속해서 스펙과 일치하도록 정수를 인쇄해야합니다.
Rainbolt

1
누군가 더 나은 해결책을 제시 할 때까지 답변을 받아들입니다. 나는 그들이 할 것이라고 생각하지 않습니다. 구식 해결 과제를 다시 방문하는 사람은 거의 없습니다. 당신은 더 골프해야합니다! 당신이 당신의 물건을 알고있는 것 같습니다. :)
Rainbolt

2

C-2468

전혀 골프는 아니지만 더 흥미로운 구현을위한 출발점이되기를 바랍니다. 의 구현은 Adrian Boeingintersect 으로부터 심하게 구부러져있다 . 그의 의사 코드는 불완전했지만 수학에 대한 그의 설명은 매우 귀중했습니다. 기본 아이디어는 플레이어에서 대상까지 한 줄을 가져와 각 건물의 모든 벽에 클립하여 각 벽의 길이를 업데이트하는 것입니다. 나머지 길이는 건물 내부의 부분이므로 0이면 교차점이 없었습니다.

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

몇 가지 테스트 사례를 시도했으며 모두 통과했습니다. 다른 사람이 사용할 수있는 아이디어는 다음과 같습니다.- ideone.com
MTXpzF
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.