Rastrea un objeto en el espacio 2D

11

Descripción

La tarea de este desafío es diseñar un programa o función que rastree un objeto dado en un espacio n×n .

I / O

Su programa recibirá 3 entradas, que se pueden tomar de cualquier manera sensata :

nserá el tamaño del lado del avión. (entonces, para n=5 , su plano será 5×5 ). Puede suponer nque siempre será un número entero impar.

sserá la posición inicial del objeto, dada como un par de coordenadas (x,y) .

Dserá un vector de pares ordenados. Dseguirá el formato D=[(d0,t0),(d1,t1),...,(dn,tn)] , donde dk siempre será uno de 'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', para las direcciones cardinales e intercardinales primarias, y tk será un número entero para el número de 'ticks'.

Dadas estas entradas, su programa debe generar un seguimiento del objeto en el plano.

Reglas

La salida debe contener los límites del plano. P.ej:

- 21012 +
+ ┌─────┐
2│ │
1│ │
0│ │
1│ │
2│ │
-└─────┘

5×5

Puede usar cualquier carácter (s) para los límites, siempre que no sea un espacio en blanco (o se represente como un espacio en blanco). Los personajes que elijas deben delinear el plano completo, lo que significa que no puede haber espacios entre ellos.

Algunos planos aceptables incluyen:

┌──┐ .... ---- + - +
│ │. . El | El | El | El |
│ │. . El | El | El | El |
└──┘; ....; ----; + - +

Los aviones no aceptables incluyen:

      .... .... ++++. .
            . . + +. .
            . + +. .
    ; ....; ....; + +; . .

El objeto a rastrear puede ser cualquier personaje que elija, siempre que solo ocupe 1 espacio en el plano y sea diferente de los caracteres de límite.

La traza del objeto rastreado también puede ser cualquier personaje que elija, siempre que solo ocupe 1 espacio en el plano y sea diferente del objeto.

(dk,tk)Dtd

Si el objeto golpeara un límite, se reflejará. Si al objeto todavía le quedan movimientos, seguirá moviéndose en la dirección en que se reflejó.

Como referencia, estas instrucciones se reflejan entre sí:

NS

EW

El resultado final contendrá las trazas más nuevas posibles, es decir, si el objeto dejara una traza en un espacio donde ya hay una traza, el carácter de traza más nuevo sobrescribirá al anterior.

Como de costumbre, las lagunas estándar están prohibidas por defecto .

Puntuación:

Este es un desafío de .

Ejemplos:

n=5s=(0,0)D=[(NW,2),(S,2),(E,1)]

Arreglando el asunto:

t=0

    0 0
 ┌─────┐
 │ │
 │ │
0│ ○ │
 │ │
 │ │
 └─────┘

t=2

    0 0
 ┌─────┐
 │ ○ │
 │ \ │
0│ \ │
 │ │
 │ │
 └─────┘

t=4

    0 0
 ┌─────┐
 │∧ │
 │ | \ │
0│ ○ \ │
 │ │
 │ │
 └─────┘

t=5

    0 0
 ┌─────┐
 │∧ │
 │ | \ │
0│└ ○ \ │
 │ │
 │ │
 └─────┘

(Los 0 son solo para referencia, y no necesitan estar en la salida final).


n=9s=(3,1)D=[(N,2),(SW,8),(SE,3),(NE,8)]

t=10

      0 0     
 ┌─────────┐
 │ │
 │ │
 │ │
 │ ∧ │
0│ / | │
 │ ○ / | │
 │⟨ / │
 │ \ / │
 │ ∨ │
 └─────────┘

SWNWNWNE

t=21

      0 0     
 ┌─────────┐
 │ ○ │
 │ \ │
 │ \ │
 │ \ │
0│ / | ⟩│
 │ ∧ / / │
 │⟨ \ / / │
 │ \ \ / │
 │ ∨ ∨ │
 └─────────┘

Casos de prueba:

n=5s=(0,0)D=[(NW,2),(S,2),(E,1)]

Salida:

    0 0
 ┌─────┐
 │∧ │
 │ | \ │
0│└ ○ \ │
 │ │
 │ │
 └─────┘


Entrada: n=9 , s=(3,1) , D=[(N,2),(SW,8),(SE,3),(NE,8)]

Salida:

      0 0     
 ┌─────────┐
 │ ○ │
 │ \ │
 │ \ │
 │ \ │
0│ / | ⟩│
 │ ∧ / / │
 │⟨ \ / / │
 │ \ \ / │
 │ ∨ ∨ │
 └─────────┘


Entrada: n=3 , s=(1,1) , D=[(N,5),(W,5)]

Salida:

   0 0
 ┌───┐
 │ | │
0│- ○ ┐│
 │ | │
 └───┘


Entrada: n=11 , s=(3,5) , D=[(NW,8),(E,5),(SE,3),(SW,5),(N,6),(NE,10)]

Salida:

       0 0
 ┌───────────┐
 │ ∧ │
 │ / \ │
 │┌ - / - \ \ │
 │ \ | / \ \ │
 │ \ | \ \ │
0│ | / ⟩│
 │ | \ / / │
 │ | / ○ │
 │ | / \ │
 │ ∨ \ │
 │ \ │
 └───────────┘
J. Sallé
fuente
Olvidé mencionar que este desafío fue sandboxed .
J. Sallé
¿Podemos tomar 'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'como un entero indexado 0 (o indexado 1) en su lugar? Así se [('NW',2),('S',2),('E',1)]convierte [[7,2],[4,2],[2,1]]por ejemplo.
Kevin Cruijssen
@KevinCruijssen seguro, no hay problema. Solo asegúrate de señalar eso en la respuesta.
J. Sallé
1
@Arnauld sí, puedes usar un solo rastro. Usé más de uno, por lo que sería más fácil visualizar los casos de prueba, pero no es obligatorio. Solo asegúrese de que el carácter de rastreo sea diferente del carácter del objeto que se está rastreando.
J. Sallé
1
@Arnauld " El objeto a rastrear puede ser cualquier personaje que elija, siempre que solo ocupe 1 espacio en el plano y sea diferente de los caracteres de límite. La traza del objeto rastreado también puede ser cualquier carácter que elija, siempre que ya que solo ocupan 1 espacio en el avión y son diferentes del objeto " .
Kevin Cruijssen

Respuestas:

9

JavaScript (ES6), 228 bytes

(n,x,y,[[dir,len],[dir,len],...])07

Emite una cadena con 0un límite, 1una traza y 3la posición final.

(n,x,y,a)=>(g=X=>Y>n?'':(Y%n&&X%n&&a.map(([d,l],i)=>(M=H=>(h-X|v-Y||(k|=a[i+!l]?1:3),l--&&M(H=(h+H)%n?H:-H,h+=H,v+=V=(v+V)%n?V:-V)))(~-(D='12221')[d],V=~-D[d+2&7]),h=x+n/2,v=n/2-y,k=' ')&&k)+(X<n?'':`
`)+g(X++<n?X:!++Y))(Y=!++n)

Pruébalo en línea!

¿Cómo?

Inicializar y dibujar en un 'lienzo' (es decir, una matriz de caracteres) es un poco tedioso y extenso en JavaScript.

Este código está utilizando una estrategia diferente: en lugar de almacenar la salida en una matriz 2D, crea una cadena carácter por carácter, de izquierda a derecha y de arriba a abajo. En cada iteración:

  • Producimos un 0si estamos sobre un límite.
  • De lo contrario, simulamos el camino completo y vemos si está cruzando nuestra posición actual. Salimos ya sea 1o 3si lo hace, o un espacio de lo contrario.
  • Agregamos un salto de línea si hemos alcanzado el límite correcto.

Con todo, este puede no ser el enfoque más corto, pero pensé que valía la pena intentarlo.

Arnauld
fuente
9

Java 10, 350 343 340 336 bytes

(n,s,S,D)->{int N=n+2,x=N/2+s,y=N/2-S,i=N*N;var r=new char[N][N];for(;i-->0;)r[i/N][i%N]=i/N*(i%N)<1|i/N>n|i%N>n?'#':32;r[y][x]=42;for(var d:D)for(i=d[0];d[1]-->0;r[y+=i%7<2?1/y*2-1:i>2&i<6?y<n?1:-1:0][x+=i>0&i<4?x<n?1:-1:i>4?1/x*2-1:0]=42)i=y<2&i<2|y>=n&i>2&i<5?4-i:x<2&i>4|x>=n&i>0&i<4?8-i:y<2&i>6?5:y<n|i!=5?i:7;r[y][x]=79;return r;}

D es una matriz de enteros en 2D donde las direcciones son enteros indexados en 0: N=0, NE=1, E=2, SE=3, S=4, SW=5, W=6, NW=7 . Las x,ycoordenadas iniciales serán dos parámetros separados sy S. La salida es una matriz de caracteres.
Utiliza #como borde, *como rastro y Opara la posición final (pero puede ser que los tres sean caracteres ASCII en el rango unicode [33,99]para el mismo conteo de bytes si lo desea).

Pruébalo en línea.

-4 bytes gracias a @ceilingcat .
Definitivamente se puede jugar un poco más al simplificar los movimientos y en qué dirección estamos viajando un poco más.

Explicación:

(n,s,S,D)->{           // Method with `n`,`s,S`,`D` parameters & char-matrix return-type
  int N=n+2,           //  Set `N` to `n+2`, since we use it multiple times
      x=N/2+s,         //  Calculate the starting `x` coordinate
      y=N/2-S,         //  Calculate the starting `y` coordinate
      i=N*N;           //  Index integer
  var r=new char[N][N];//  Result char-matrix of size `N` by `N`
  for(;i-->0;)         //  Loop `i` in the range (`N**2`, 0]
    r[i/N][i%N]=       //    Set the cell at position `i` divmod-`N` to:
      i/N*(i%N)<1|i/N>n|i%N>n?
                       //     If we're at a border:
       '#'             //      Set the current cell to '#'
      :                //     Else:
       32;             //      Set the current cell to ' ' (a space) instead
  r[y][x]=42;          //  Then set the starting position `x,y` to a '*'
  for(var d:D)         //  Loop over the `D` input:
    for(i=d[0];        //   Set `i` to the current direction
        d[1]-->0       //   Inner loop the current `d` amount of times
        ;              //     After every iteration:
         r[y+=         //      Change `y` based on the current direction
            i%7<2?     //       If the current direction is N, NE, or NW
             1/y*2-1   //        If we're at the top border:
                       //         Go one row down
                       //        Else
                       //         Go one row up
            :i>2&i<6?  //       Else-if the current direction is S, SE, or SW
             y<n?      //        If we're at the bottom border
              1        //         Go one row up
             :         //        Else
              -1       //         Go one row down
            :          //       Else (directions E or W)
             0]        //        Stay in the same row
          [x+=         //      Change `x` based on the current direction
            i>0&i<4?   //       If the current direction is E, NE, or SE
             x<n?      //        If we're NOT at the right border
              1        //         Go one column to the right
             :         //        Else:
              -1       //         Go one column to the left
            :i>4?      //       Else-if the current direction is W, NW, or SW
             1/x*2-1   //        If we're NOT at the left border:
                       //         Go one column to the left
                       //        Else:
                       //         Go one column to the right
            :          //       Else (directions N or S)
             0]        //        Stay in the same column
               =42)    //      And fill this new `x,y` cell with a '*'
      i=               //    Determine the new direction
        y<2&i<2|y>=n&i>2&i<5?4-i:x<2&i>4|x>=n&i>0&i<4?8-i:y<2&i>6?5:y<n|i!=5?i:7;
                       //     (See loose explanation below)
  r[y][x]=79;          //  And finally set the last `x,y` cell to 'O'
  return r;}           //  And return the result-matrix

y<2&i<2|y>=n&i>2&i<5?4-i:x<2&i>4|x>=n&i>0&i<4?8-i:y<2&i>6?5:y<n|i!=5?i:7es una versión de golf de esto a continuación utilizando 4-iy 8-ipara la mayoría de los cambios de dirección:

y<2?     // If we're at the top border
 i==0?   //  If the current direction is N
  4      //   Change it to direction S
 :i==1?  //  Else-if the current direction is NE
  3      //   Change it to SE
 :i==7?  //  Else-if the current direction is NW
  5      //   Change it to SW
 :       //  Else
  i      //   Leave the direction the same
:x<2?    // Else-if we're at the left border
 i==7?   //  If the current direction is NW
  1      //   Change it to NE
 :i==6?  //  Else-if the current direction is W
  2      //   Change it to E
 :i==5?  //  Else-if the current direction is SW
  3      //   Change it to SE
 :       //  Else
  i      //   Leave the direction the same
:y>=n?   // Else-if we're at the bottom border
 i==3?   //  If the current direction is SE
  1      //   Change it to NE
 :i==4?  //  Else-if the current direction is S
  0      //   Change it to N
 :i==5?  //  Else-if the current direction is SW
  7      //   Change it to NW
 :       //  Else
  i      //   Leave the direction the same
:x>=n?   // Else-if we're at the right border
 i==1?   //  If the current direction is NE
  7      //   Change it to NW
 :i==2?  //  Else-if the current direction is E
  6      //   Change it to W
 :i==3?  //  Else-if the current direction is SE
  5      //   Change it to SW
 :       //  Else
  i      //   Leave the direction the same
:        // Else
 i       //  Leave the direction the same
Kevin Cruijssen
fuente
3

Carbón , 74 bytes

NθJ⊘⊕θ⊘⊕θUR±⊕⊕θJN±NFA«≔⊟ιζF⊟ι«≔ζδ↷δ¶F›⊗↔ⅈθ≦±ζF›⊗↔ⅉθ≦⁻⁴ζ≧﹪⁸ζ↷⁴¶↶⁴↶δ↷ζ*¶↶ζPo

Pruébalo en línea! El enlace es a la versión detallada del código. Toma la entrada en el formato n, x, y, d donde d es una matriz de matrices de [distancia, dirección] pares donde la dirección es una codificación numérica 0 = sur en sentido horario a 7 = sureste. Explicación:

NθJ⊘⊕θ⊘⊕θUR±⊕⊕θ

Ingrese ny dibuje un cuadro cuyo interior tenga ese tamaño centrado en el origen.

JN±N

Ingrese y salte hacia xy y(pero lo niega yporque el eje y del carbón aumenta cada vez más).

FA«

Recorre las entradas en d.

≔⊟ιζ

Extraer la dirección inicial.

F⊟ι«

Repita para la distancia deseada.

≔ζδ

Guarda la dirección.

↷δ¶

Haz un movimiento experimental en esa dirección.

F›⊗↔ⅈθ≦±ζ

Si esto sale por los lados, gire la dirección horizontalmente.

F›⊗↔ⅉθ≦⁻⁴ζ

Si esto sale de la parte superior o inferior, gire la dirección verticalmente.

≧﹪⁸ζ

Reduzca la dirección del módulo 8 (los comandos de pivote solo aceptan valores de 0 a 7).

↷⁴¶↶⁴

Deshacer el movimiento experimental.

↶δ↷ζ*¶

Mire hacia la dirección correcta, luego imprima un rastro y muévase.

↶ζPo

Vuelva a la dirección predeterminada e imprima el objeto en la posición actual.

Neil
fuente
2

JavaScript, 206 bytes

Toma la entrada como (n, x, y, [[dir, len], [dir, len], ...]) donde las direcciones se codifican con máscaras de bits:

S : 1  
N : 2   
E : 4  
W : 8  
SE: 5 (1|4)  
SW: 9 (1|8)
NE: 6 (2|4)
NW:10 (2|8)

Emite una cadena con

- 1 for top and bottom boundary
- 4 for left and right boundary 
- 5 for corners 
- 0 for trace
- 8 for the final position.

Los diferentes valores de los límites se utilizan para evaluar la siguiente dirección.

(n,x,y,d)=>(Q=[e=`
5`+'1'[R='repeat'](n)+5,o=n+3,-o,c=[...e+(`
4`+' '[R](n)+4)[R](n)+e],1,1+o,1-o,,-1,o-1,~o],p=1-o*(~n/2+y)-~n/2+x,c[d.map(([q,s])=>{for(a=q;s--;p+=Q[a^=c[p+Q[a]]*3])c[p]=0}),p]=8,c.join``)

Menos golf

F=(n,x,y,d) => (
  o = n+3, // vertical offset, accounting for boundaries and newline
  // Q = offsets for different directions, bitmask indexed 
  Q = [,  // 0000 no direction
     o,   // 0001 S
     -o,  // 0010 N
     ,    // 0011 NS - invalid
     1 ,  // 0100 E
     1+o, // 0101 SE
     1-o, // 0110 NE
     ,    // 0111 NSE - invalid
     -1,  // 1000 W
     o-1, // 1001 SW
    -o-1],// 1010 NW

  e = `\n5`+'1'.repeat(n)+5, // top and bottom boundary
  c = [...e + (`\n4` + ' '.repeat(n) + 4).repeat(n) + e], // canvas
  p = 1 - o*(~n/2+y) - ~n/2 + x, // start position
  d.map( ([q,s]) => { // repeat for each element in 'd'
    a = q; // starting offset pointer - will change when bounce
    while( s-- )
    {
      c[p] = 0; // trace
      b = c[p + Q[a]] // boundary value or 0 (space count 0)
      a ^= b * 3 // xor with 0 if no bounce, else 3 or 12 or 15
      p += Q[q]  // advance position
    }
  })
  c[p] = 8, // set end position
  c.join``
)

PRUEBA

var F=
(n,x,y,d)=>(Q=[e=`
5`+'1'[R='repeat'](n)+5,o=n+3,-o,c=[...e+(`
4`+' '[R](n)+4)[R](n)+e],1,1+o,1-o,,-1,o-1,~o],p=1-o*(~n/2+y)-~n/2+x,c[d.map(([q,s])=>{for(a=q;s--;p+=Q[a^=c[p+Q[a]]*3])c[p]=0}),p]=8,c.join``)

var out=x=>O.textContent+=x

var test=(n,x,y,d)=>{
  var dd = d.map(([d,s])=>[,'S','N',,'E','SE','NE',,'W','SW','NW'][d]+' '+s)
  out([n,x,y]+' ['+dd+']')
  out(F(n,x,y,d))
  out('\n\n')
}

test(5,0,0,[[10,2],[1,2],[4,1]])
test(9,3,-1,[[2,2],[9,8],[5,3],[6,8]])
test(11,3,-5,[[10,8],[4,5],[5,2],[9,5],[2,6],[6,10]])
<pre id=O></pre>

edc65
fuente
2

C (gcc) , 352323 bytes

Golfed 29 bytes gracias a ceilingcat.

#define G(x,a)x+=a=x<2|x>m-3?-a:a
#define A(p)atoi(v[p])
m,r,c,x,y,s,a,b;main(q,v)int**v;{m=A(1)+2;int f[r=m*m];for(x=A(2)+m/2;r--;f[r]=32);for(y=A(s=3)+m/2;++s<q;)for(a=cos(A(s)*.8)*2,b=sin(A(s)*.8)*2,c=A(++s);c--;G(y,b),f[y*m+x]=42)G(x,a);for(f[y*m+x]=64;++r<m;puts(""))for(c=0;c<m;c++)putchar(c%~-m&&r%~-m?f[r*m+c]:35);}

Pruébalo en línea!

El programa toma la entrada como argumentos de línea de comando (como a.out 10 1 1 3 5 0 4 7 2):

  • El primer argumento es el tamaño del campo,
  • (x,y) del actor,
  • (d,t)dEt

Explicación

// Update the coordinate AND simultaneously modify the direction (if needed)
#define G (x, a) x += a = x < 2 || x >= m - 2 ? -a : a

// Get the numeric value of an argument
#define A (p) atoi (v[p])

// variables
m, // width and height of the array with field data
r, c, // helpers
x, y, // current coordinates of the actor
s, // helper
a, b; // current direction of the movement

main (q, v) char **v;
{
    // array size is field size + 2 (for borders)
    m = A (1) + 2;

    // allocate the array
    int f[r = m * m];

    // fill the array with spaces,
    for
    (
        // but first get x of the actor
        x = A (2) + m / 2;

        r--;

        f[r] = 32
    );

    // trace: iterate over remaining commandline argument pairs
    for
    (
        // but first get y of the actor
        y = A (s = 3) + m / 2;

        ++s < q; // loop until no args left
    )
        // for each such pair
        for
        (
            a = cos (A (s) * .8) * 2,  // get the x-increment
            b = sin (A (s) * .8) * 2, // get the y-increment
            c = A (++s);  // then get the number of steps

            c--;

            // after each step:
            G (y, b), // update y and maybe the y-direction
            f[y * m + x] = 42 // draw the trail
        )
            G (x, a); // update x and maybe the x-direction

   // output
   for
   (
       f[x * m + y] = 64; // put a @ to the current position of the actor
       ++r < m; // r == -1 at the beginning of the loop so preincrement

       puts("") // terminate each row with newline
   )
       // iterate over columns in the row
       for (c = 0; c < m; c++)
           putchar
           (
               c % ~ -m && r % ~ -m ? // if it is not a border cell,
               f[r * m + c] // output the character from the array
               : 35 // otherwise output the #
           );
}
Max Yekhlakov
fuente
1
Creo que a su código le falta la salida del objeto en la posición final, ya que La traza del objeto rastreado también puede ser cualquier personaje que elija, siempre que solo ocupen 1 espacio en el plano y sean diferentes del objeto . Aparte de eso, me parece bien.
J. Sallé
Vaya, me lo perdí por completo, gracias por notar a J.Sallé. Afortunadamente, la corrección no hizo que el programa fuera más largo.
Max Yekhlakov