レーザーでそれらを破壊する


21

前書き

アリーナは、敵がカバーするために使用する高層ビルが点在する平地です。あなたとあなたの敵はレーザーでお互いを撃ちます。全員がジェットパックを携帯し、飛行を許可します。

どの敵にレーザーを当てることができ、どの敵に隠れていますか?

問題

最初に、アリーナのサイズは、n1行の整数で指定されます。次のn行にはn、行ごとにスペースで区切られた整数が含まれています。各整数は、その場所の建物の高さを表します。各建物は長方形の固体で、1単位×1単位、高さ単位です。

次に、あなたの場所は、3つの浮動小数点数として単一の行に与えられていますxyz

最後に、敵の数はm1行の整数で与えられます。次のm行には、行ごとにスペースで区切られた3つの浮動小数点数が含まれています。これらは表し xyz敵の座標を。座標系は次のように定義されます。

  • 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
敵を破壊できない場合、それらに参加できますか?
ジョンドヴォルザーク

@ user80551申し訳ありませんが、スペルミスは意図的なものであるため、タイトルの編集をロールバックする必要がありました。Google it。
レインボルト

@Rusherああ、申し訳ありませんが、IDKは
user80551

4
v

回答:


5

Perl、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空間の2つのポイント「Player」(X1Y1Z1)と「Enemy」(X2Y2Z2)を接続します。上のその投影(XY)面は、グリッド線の一部が整数すなわち交差するx = consty = constのようなX1 < x < X2またはY1 < y < Y2(例えばことを、ここで仮定しX1 < X2、それは重要ではありませんが)。x yこれらの交点の座標は簡単に見つけることができるためzPEライン上のポイントの座標も簡単に見つけることができます。
user2846289 14年

(続き)一方、x y座標についてhは、建物の高さ(むしろ、x yポイントを共有する最大4つの建物の最大高さ)がわかります。敵は、h < z上記のすべての「交点」の場合(およびその場合にのみ)撃つことができます。実装は、ゴルフの目的のためのPerlのいくつかのトリックと同様に、いくつかの基本的な算術です。1か月前にどのようにそれを行ったかの詳細を解読するには、今しばらく時間がかかります:-)。
user2846289

Argh、私が見るように、最後の(5番目の)リビジョンにはバグがあります:式の@a配列の要素へのインデックスは、代わりにgrep順番0,3,0,4,1,5,2に表示されるはずです3,0,3,1,4,2,5-ごめんなさい。
user2846289 14年

OK、遅くない方が良い、そしてこれをすべて終えるために、ここにコメント版があります。
user2846289 14

3

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

これには欠陥があると思います。ところで、ネスト時に文字を保存しました(最初のレベルは1つのスペース、2番目は1つのタブ、1つのタブと1つのスペースです...)。結局、この答えがそれを行う方法を指し示すことを願っています。


敵の1人が地面に直接位置しているため、サンプル入力が無効であることに気付きました。これは技術的には高さゼロの建物の最上部であり、これは起こらないと約束しました。あなたの提出は修正されたテストケースに合格しますが、これは失敗します-ideone.com/8qn3sv。テストケースを確認できますか?何かが足りないか、座標系が不明確かもしれません。
レインボルト

いいえ、ベクターが隅々まで進んでいるだけです...今、私はあなたが仮定6&7を約束した理由を知っています:)
WorldSEnder

ところで、I出力負のフロートが、それは2つの余分な文字(で固定することができますprint 1-2*...代わりにprint.5-...、それは私が推測違いの大きなではありませんので)
WorldSEnder

あなたは私が思いついたいくつかのテストに合格しました。良くやった!まだ先に進んで、仕様に合わせて整数を出力する必要があります。
レインボルト

1
誰かがより良い解決策を思い付くまであなたの答えを受け入れます。私は彼らがそうなるとは思わない。解決済みの古い課題を再検討する人はほとんどいません。もっとゴルフをするべきです!あなたは自分のものを知っているようです。:)
Rainbolt

2

C-2468

まったくゴルフではありませんが、より興味深い実装の出発点になることを願っています。の実装はintersectAdrian Boeingから大きく制限されています。彼の擬似コードは不完全でしたが、数学の彼の説明は非常に貴重でした。基本的な考え方は、プレイヤーからターゲットまで線を引き、それを各建物のすべての壁に対してクリップし、各壁の長さを更新することです。残りの長さは建物内の部分であるため、ゼロの場合、交差点はありません。

#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がある- ideone.com/MTXpzF
Rainbolt
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.