ทำลายพวกเขาด้วย Lazers


21

บทนำ

ที่เกิดเหตุเป็นที่ราบที่มีตึกระฟ้าสูงซึ่งศัตรูของคุณใช้เป็นที่กำบัง คุณและศัตรูของคุณยิงกันด้วยเลเซอร์ พวกคุณทุกคนพกชุดเจ็ทเพื่อให้สามารถบินได้

ศัตรูตัวไหนที่คุณสามารถยิงด้วยเลเซอร์และที่ซ่อนอยู่?

ปัญหา

ก่อนขนาดของเวทีที่ได้รับจากจำนวนเต็มnในบรรทัดเดียว nบรรทัดต่อไปนี้มีnจำนวนเต็มต่อบรรทัดคั่นด้วยช่องว่าง จำนวนเต็มแต่ละตัวแทนความสูงของสิ่งปลูกสร้างในตำแหน่งนั้น อาคารแต่ละหลังเป็นรูปสี่เหลี่ยมผืนผ้าที่เป็นของแข็ง 1 หน่วยต่อ 1 หน่วยโดยหน่วยความสูง

ถัดไปสถานที่ของคุณจะได้รับในบรรทัดเดียวสามตัวเลขทศนิยมx, ,yz

ในที่สุดจำนวนศัตรูจะได้รับจากจำนวนเต็มmในบรรทัดเดียว mบรรทัดต่อไปนี้มีหมายเลขทศนิยมสามตัวต่อบรรทัดคั่นด้วยช่องว่าง เหล่านี้เป็นตัวแทน 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 n<<100
  • 0 m<<100
  • 0 <= x<=n
  • 0 <= y<=n
  • 0 <= z<n
  • ผู้เล่นจะต้องไม่อยู่ในหรือภายในมุมห้องหรือด้านข้างของอาคาร
  • สายตาของคุณต่อศัตรูจะไม่มีการสัมผัสกับมุมขอบหรือด้านข้างของอาคาร
  • ผู้เล่นไม่ใช่สิ่งกีดขวาง

ดีใจที่ได้เห็นมันออกมาจากกล่องเครื่องมือ :)
Timtech

7
หากฉันไม่สามารถทำลายศัตรูได้ฉันจะเข้าร่วมกับพวกเขาได้ไหม
John Dvorak

@ user80551 ขออภัยฉันต้องย้อนกลับการแก้ไขของคุณไปที่ชื่อเพราะการสะกดผิดนั้นตั้งใจ Google มัน
Rainbolt

@Rusher โอ้ขอโทษ IDK นั้น
user80551

4
ที่เกี่ยวข้อง: youtube.com/watch?v=NKTpWi5itOM
qwr

คำตอบ:


5

Perl, 301 296 282

แก้ไข 2:จริง ๆ แล้วการแข่งขันหรือไม่ไม่มีเหตุผลที่จะตีกอล์ฟต่อไปอีกเล็กน้อย ทดสอบออนไลน์

แก้ไข:วงเล็บสองรายการหายไปทำให้ regex ง่ายขึ้นเพื่อตรวจสอบจำนวนเต็มที่ไม่เป็นศูนย์

ด้วยการขึ้นบรรทัดใหม่และการเยื้องเพื่อให้อ่านง่าย:

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เชื่อมต่อสองจุดในพื้นที่ 3 มิติ "ผู้เล่น" (X1Y1Z1) และ "ศัตรู" (X2Y2Z2) การฉายภาพบน(XY)ระนาบตัดบางส่วนของเส้นกริดเช่นจำนวนเต็มx = constหรือy = constเช่นX1 < x < X2หรือY1 < y < Y2(สมมติว่านี่เป็นเช่นX1 < X2นั้น แต่มันไม่สำคัญ) สามารถหาพิกัดx yของจุดตัดเหล่านี้ได้อย่างง่ายดายดังนั้นจึงสามารถzประสานจุดหนึ่งจุดบนPEเส้นได้เช่นกัน
2846289

(ต่อ)ในทางกลับกันสำหรับx yพิกัดใด ๆเราทราบความสูงhของอาคาร (ค่อนข้างสูงสูงสุดถึง 4 อาคารซึ่งเป็นx yจุดร่วม) ศัตรูสามารถถูกยิงได้หาก (และเฉพาะในกรณี) h < zสำหรับ "จุดตัด" ทั้งหมดที่กล่าวถึงข้างต้น การใช้งานเป็นอุปกรณ์ทางคณิตศาสตร์ขั้นพื้นฐานเช่นเดียวกับเทคนิคหลายอย่างกับ Perl สำหรับวัตถุประสงค์ของการเล่นกอล์ฟ การปฏิเสธรายละเอียดของวิธีที่ฉันทำเมื่อหนึ่งเดือนก่อนจะใช้เวลาสักครู่ตอนนี้ :-)
2846289

Argh ตามที่ฉันเห็นมีข้อผิดพลาดในการแก้ไขครั้งที่ (5) ล่าสุด: ดัชนีองค์ประกอบของ@aอาร์เรย์ในgrepนิพจน์ควรปรากฏขึ้นตามลำดับ0,3,0,4,1,5,2แทนที่จะ3,0,3,1,4,2,5- ขอโทษ
2846289

ตกลงดีกว่าไม่สายและเพื่อจบสิ่งนี้ทั้งหมดนี่คือความคิดเห็นของรุ่น
2846289

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)

สิ่งนี้น่าจะใช้ได้กับกรณีขอบและมุม (ไม่ได้ตั้งใจ) และค่อนข้างแข็ง Ouput สำหรับตัวอย่างที่ให้มา:

-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

ฉันคิดว่ามันเต็มไปด้วยข้อบกพร่อง แต่ฉันบันทึกตัวอักษรไว้ที่ซ้อน (ระดับแรกคือหนึ่งช่องว่างหนึ่งสองแท็บจากนั้นหนึ่งแท็บและช่องว่าง ... ) ฉันหวังว่าหลังจากคำตอบทั้งหมดนี้สามารถชี้ไปที่วิธีการทำ


ฉันเพิ่งรู้ว่าตัวอย่างอินพุตนั้นไม่ถูกต้องเพราะหนึ่งในศัตรูตั้งอยู่บนพื้นดินซึ่งเป็นเทคนิคด้านบนสุดของอาคารที่มีความสูงเป็นศูนย์ซึ่งฉันสัญญาว่าจะไม่เกิดขึ้น การส่งของคุณผ่านการทดสอบกรณีการแก้ไข แต่ก็ล้มเหลวนี้ - ideone.com/8qn3sv คุณสามารถตรวจสอบกรณีทดสอบของฉันได้ไหม ฉันอาจจะพลาดบางสิ่งบางอย่างหรือระบบพิกัดอาจไม่ชัดเจน
Rainbolt

ไม่มันเป็นเพียงเวกเตอร์กำลังแล่นผ่านมุม ... ตอนนี้ฉันรู้แล้วว่าทำไมคุณถึงสัญญากับอัสสัมชัญ 6 & 7 :)
WorldSEnder

btw ฉันส่งทลอยเชิงลบ แต่สามารถแก้ไขได้ด้วย 2 ตัวอักษรพิเศษ ( print 1-2*...แทนprint.5-...) ดังนั้นมันจึงไม่ใช่ความแตกต่างที่ยิ่งใหญ่ฉันเดา
WorldSEnder

คุณผ่านการทดสอบสองสามข้อที่ฉันพบ งานที่ดี! คุณยังควรดำเนินการต่อและกำหนดให้พิมพ์จำนวนเต็มเพื่อให้สอดคล้องกับข้อมูลจำเพาะ
Rainbolt

1
ยอมรับคำตอบของคุณจนกว่าจะมีคนคิดวิธีแก้ปัญหาที่ดีกว่า ฉันไม่คิดว่าพวกเขาจะ ไม่ค่อยมีใครเข้ามาแก้ไขความท้าทายที่เก่ามาก คุณควรตีกอล์ฟเพิ่ม! ดูเหมือนว่าคุณรู้เนื้อหาของคุณ :)
Rainbolt

2

C - 2468

ไม่ได้เล่นกอล์ฟเลย แต่หวังว่ามันจะเป็นจุดเริ่มต้นสำหรับการใช้งานที่น่าสนใจยิ่งขึ้น การดำเนินการintersectมี cribbed อย่างหนักจากเอเดรียโบอิ้ง รหัสหลอกของเขาไม่สมบูรณ์ แต่คำอธิบายของคณิตศาสตร์นั้นมีค่า แนวคิดพื้นฐานคือคุณนำเส้นจากเครื่องเล่นไปยังเป้าหมายและตัดกับผนังทั้งหมดของแต่ละอาคารอัปเดตความยาวสำหรับแต่ละกำแพง ความยาวที่เหลือคือส่วนภายในอาคารดังนั้นถ้าเป็นศูนย์จะไม่มีทางแยก

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