Distruggili con Lazers


21

introduzione

L'arena è una pianura punteggiata di grattacieli, che i tuoi nemici usano come copertura. Tu e i tuoi nemici vi sparate a vicenda con i laser. Tutti voi trasportate jet pack, permettendo il volo.

Quali nemici puoi colpire con il tuo laser e quali si nascondono?

Problema

Innanzitutto, la dimensione di un'arena è data da un numero intero nsu una sola riga. Le seguenti nrighe contengono nnumeri interi per riga separati da uno spazio. Ogni numero intero rappresenta l'altezza dell'edificio in quella posizione. Ogni edificio è un solido rettangolare, 1 unità per 1 unità per unità di altezza.

Successivamente, la tua posizione è dato su una sola riga di tre numeri in virgola mobile x, y, z.

Infine, il numero di nemici è dato da un numero intero msu una sola riga. Le seguenti mrighe contengono tre numeri in virgola mobile per riga separati da uno spazio. Questi rappresentano il x, ye le zcoordinate di un nemico. Il sistema di coordinate è definito come segue:

  • x viene misurato da sinistra a destra nell'input della città
  • y viene misurato dall'alto verso il basso
  • z viene misurato da zero

Per ogni nemico, se una linea libera può essere tracciata da te a quel nemico, genera un numero intero positivo . Altrimenti, genera un numero intero negativo . Separare le uscite con una nuova linea.

Input di esempio

I commenti, indicati con '#', sono presenti per aiutarti a vedere rapidamente cosa fa ogni riga. Non saranno presenti nell'input effettivo.

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

Uscita campione

Per l'input di esempio sopra riportato, produciamo quanto segue:

-1
1
1

ipotesi

  • 0 n<<100
  • 0 m<<100
  • 0 <= x<=n
  • 0 <= y<=n
  • 0 <= z<n
  • I giocatori non saranno posizionati sopra o all'interno di un angolo, bordo o lato di un edificio
  • La tua visuale per un nemico non sarà mai tangente all'angolo, al bordo o al lato di un edificio
  • Un giocatore non è un ostacolo

Sono contento di vederlo fuori dalla sandbox :)
Timtech,

7
Se non riesco a distruggere un nemico, posso unirmi a loro?
John Dvorak,

@ user80551 Spiacenti, ho dovuto ripristinare la modifica al titolo perché l'ortografia era intenzionale. Google esso.
Rainbolt,

@Rusher Oh, scusa, IDK che
user80551

Risposte:


5

Perl, 301 296 282

Modifica 2: In realtà, competizione o no, non c'è motivo di non giocare un po 'più avanti. Provalo online .

Modifica: coppia di parentesi scomparse, regex più semplice per verificare la presenza di numeri interi diversi da zero.

Con newline e rientro per la leggibilità:

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

Richiede a 5.14causa dell'argomento scalare (riferimento di matrice) a pop.


Puoi spiegare un po 'la tua soluzione? Non l'ho provato e non ho ancora appoggiato Perl, quindi alcuni commenti sarebbero graditi.
WorldSEnder,

@WorldSEnder, la struttura dell'algoritmo è la seguente. La linea retta PEcollega due punti nello spazio 3D, "Giocatore" (X1Y1Z1) e "Enemy" (X2Y2Z2). La sua proiezione sul (XY)piano interseca alcune delle linee della griglia, cioè numeri interi x = consto y = constcome X1 < x < X2o Y1 < y < Y2(assumendo qui che ad es. X1 < X2, Ma non è importante). x yÈ possibile trovare facilmente le coordinate di queste intersezioni e quindi anche le zcoordinate di un punto sulla PElinea.
user2846289,

(continua) D'altra parte, per tutte le x ycoordinate, conosciamo l'altezza hdell'edificio (piuttosto, l'altezza massima di un massimo di 4 edifici che condividono il x ypunto). Il nemico può essere sparato se (e solo se) h < zper tutti i "punti di intersezione" menzionati sopra. L'implementazione prevede alcune aritmetiche di base, oltre a diversi trucchi con Perl ai fini del golf. Decifrare i dettagli di come l'ho fatto un mese fa richiederà del tempo ora :-).
user2846289

Argh, come vedo, c'è un bug nell'ultima (quinta) revisione: gli indici degli elementi @adell'array in grepespressione dovrebbero apparire nell'ordine 0,3,0,4,1,5,2invece di 3,0,3,1,4,2,5- scusa.
user2846289,

OK, meglio tardi che mai, e per finire con tutto questo, ecco la versione commentata.
user2846289

3

Python 2.7 - 429 420 308 308 caratteri

Ho pensato a questa sfida più come un problema di matematica che come un problema di codice golf, quindi non essere troppo duro con me se ho perso alcune ovvie ottimizzazioni. Comunque, ecco il codice:

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)

Questo dovrebbe funzionare per casi limite e angolari (gioco di parole non intenzionale) ed è piuttosto solido. Uscita per l'esempio fornito:

-1
1
1

Ed ecco una spiegazione "breve":

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

Immagino che sia pieno di difetti. Tra parentesi ho salvato i caratteri in annidamento (il primo livello è uno spazio, la seconda una scheda, quindi una scheda e uno spazio ...). Spero che dopo tutta questa risposta possa indicare il modo di farlo.


Mi sono appena reso conto che l'input del campione non era valido perché uno dei nemici si trovava direttamente sul terreno, che è tecnicamente la cima di un edificio di altezza zero, che avevo promesso che non sarebbe accaduto. Il tuo invio supera il caso di prova corretto, ma fallisce questo - ideone.com/8qn3sv . Puoi controllare il mio caso di prova? Potrei mancare qualcosa o forse il mio sistema di coordinate non è chiaro.
Rainbolt,

No, è solo che il vettore sta attraversando gli angoli ... ora so perché hai promesso Assunzione 6 e 7 :)
WorldSEnder

tra l'altro, ho prodotto un float negativo ma che può essere risolto con 2 caratteri extra ( print 1-2*...invece di print.5-...) Quindi non è una grande differenza credo
WorldSEnder

Hai superato i pochi test che mi sono venuti in mente. Bel lavoro! Dovresti comunque andare avanti e farlo stampare numeri interi per rimanere in linea con le specifiche.
Rainbolt,

1
Accettare la tua risposta fino a quando qualcuno non troverà una soluzione migliore. Non penso che lo faranno. Molto raramente qualcuno rivisita le vecchie sfide risolte. Dovresti golf di più! Sembra che tu sappia le tue cose. :)
Rainbolt,

2

C - 2468

Non giocare a golf, ma si spera sia un punto di partenza per implementazioni più interessanti. L'implementazione di intersectè paralizzata pesantemente da Adrian Boeing . Il suo pseudo-codice era incompleto, ma la sua spiegazione della matematica era inestimabile. L'idea di base è quella di prendere una linea dal giocatore al bersaglio e agganciarla a tutte le pareti di ogni edificio, aggiornando la lunghezza per ogni parete. La lunghezza rimanente è la porzione all'interno dell'edificio, quindi se è zero, non vi era intersezione.

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

Ho provato alcuni casi di test e li hai superati tutti. Ecco l'ideone che chiunque può usare per verificare - ideone.com/MTXpzF
Rainbolt
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.