Suivre un objet dans un espace 2D

11

La description

La tâche de ce défi est de concevoir un programme ou une fonction qui suit un objet donné dans un espace .n×n

E / S

Votre programme recevra 3 entrées, qui peuvent être prises de n'importe quelle manière sensée :

nsera la taille du côté de l'avion. (donc, pour , votre avion sera ). Vous pouvez supposer que ce sera toujours un entier impair.n=55×5n

ssera la position de départ de l'objet, donnée sous la forme d'une paire de .(X,y)

Dsera un vecteur de paires ordonnées. Dsuivra le format , où sera toujours l' un des , pour les directions cardinale et primaire intercardinale, et sera un entier pour le nombre de «ticks».=[(0,t0),(1,t1),...,(n,tn)]k'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'tk

Compte tenu de ces entrées, votre programme doit générer un suivi de l'objet dans l'avion.

Règles

La sortie doit contenir les limites de l'avion. Par exemple:

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

serait un exemple d'un avion vide . Les chiffres au-dessus et sur le côté sont pour référence seulement et n'ont pas besoin d'être imprimés.5×5

Vous pouvez utiliser n'importe quel caractère pour les limites, tant qu'il ne s'agit pas d'espaces (ou s'affiche en tant qu'espaces). Les caractères que vous choisissez doivent délimiter le plan complet, ce qui signifie qu'il ne peut y avoir aucun espace entre eux.

Certains avions acceptables comprennent:

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

Les avions non acceptables comprennent:

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

L'objet à suivre peut être le personnage que vous choisissez, tant qu'il n'occupe qu'un espace dans l'avion et est différent des caractères de limite.

La trace de l'objet suivi peut également être celle des personnages que vous choisissez, tant qu'ils n'occupent qu'un espace dans l'avion et sont différents de l'objet.

Pour chaque élément (k,tk) de , l'objet doit déplacer t espaces vers , et laisser une trace derrière.

Si l'objet heurte une limite, il sera reflété. Si l'objet a encore des mouvements à gauche, il continuera à se déplacer dans la direction à laquelle il a été réfléchi.

Pour référence, ces directions se reflètent mutuellement:

NS → lorsque la limite supérieure ou inférieure est respectée;

EW → lorsqu'une limite latérale est rencontrée;

La sortie finale contiendra les traces les plus récentes possibles, c'est-à-dire que si l'objet laisse une trace dans un espace où il y a déjà une trace, le caractère de trace le plus récent remplacera l'ancienne.

Comme d'habitude, les failles standard sont interdites par défaut .

Notation:

Il s'agit d'un défi de .

Exemples:

Entrée: n=5 , s=(0,0) , =[(NW,2),(S,2),(E,1)]

Élaborer:

t=0

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

t=2

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

t=4

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

t=5 , qui sera la sortie.

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

(Les 0 sont juste pour référence, et ils n'ont pas besoin d'être dans la sortie finale.)


Entrée: n=9 , s=(3,-1) , =[(N,2),(SW,8),(SE,3),(NE,8)]

Notez que, lorsque t=dix :

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

L'objet a été réfléchi deux fois : une fois en atteignant le bas de l'avion en allant vers le SW , où il se réfléchit vers le NW ; puis une nouvelle fois en atteignant le côté gauche de l'avion, où NW correspond à NE .

La sortie finale arrive à t=21 :

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

Cas de test:

Entrée: n = 5 , s = ( 0 , 0 ) , D = [ ( ′ N W ′ , 2 ) , ( ′ S ′ , 2 ) , ( ′ E ′ , 1 ) n=5s=(0,0)=[(NW,2),(S,2),(E,1)]

Production:

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


Entrée: n=9 , s=(3,-1) , =[(N,2),(SW,8),(SE,3),(NE,8)]

Production:

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


Entrée: n=3 , s=(1,1) , =[(N,5),(W,5)]

Production:

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


Entrée: n=11 , s=(3,-5) , =[(NW,8),(E,5),(SE,3),(SW,5),(N,6),(NE,dix)]

Production:

       0
 ┌───────────┐
 │ ∧ │
 │ / \ │
 │┌ - / - \ \ │
 │ \ | / \ \ │
 │ \ | \ \ │
0│ | / ⟩│
 │ | \ / / │
 │ | / ○ │
 │ | / \ │
 │ ∨ \ │
 │ \ │
 └───────────┘
J. Sallé
la source
J'ai oublié de mentionner que ce défi était en bac à sable .
J.Sallé
Pouvons-nous 'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'plutôt prendre comme un entier indexé 0 (ou indexé 1)? Ainsi [('NW',2),('S',2),('E',1)]devient [[7,2],[4,2],[2,1]]par exemple.
Kevin Cruijssen
@KevinCruijssen bien sûr, pas de problème. Assurez-vous simplement de le signaler dans la réponse.
J.Sallé
1
@Arnauld oui, vous êtes autorisé à utiliser un seul caractère de trace. J'en ai utilisé plusieurs pour qu'il soit plus facile de visualiser les cas de test, mais ce n'est pas obligatoire. Assurez-vous simplement que le caractère de trace est différent du caractère de l'objet tracé.
J. Sallé
1
@Arnauld " L'objet à suivre peut être le caractère que vous choisissez, tant qu'il n'occupe que 1 espace sur le plan et est différent des caractères de limite. La trace de l'objet suivi peut également être les caractères que vous choisissez, tant que car ils n'occupent qu'un espace dans l'avion et sont différents de l'objet. "
Kevin Cruijssen

Réponses:

9

JavaScript (ES6), 228 octets

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

Génère une chaîne avec 0pour une limite, 1une trace et 3la position finale.

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

Essayez-le en ligne!

Comment?

L'initialisation et le dessin dans une «toile» (c'est-à-dire une matrice de caractères) est un peu fastidieux et long en JavaScript.

Ce code utilise une stratégie différente: au lieu de stocker la sortie dans un tableau 2D, il construit une chaîne caractère par caractère, de gauche à droite et de haut en bas. À chaque itération:

  • Nous sortons un 0si nous dépassons une limite.
  • Sinon, nous simulons le chemin complet et voyons s'il croise notre position actuelle. Nous sortons soit 1ou 3si c'est le cas, soit un espace sinon.
  • Nous ajoutons un saut de ligne si nous avons atteint la limite droite.

Dans l'ensemble, ce n'est peut-être pas l'approche la plus courte, mais j'ai pensé que cela valait la peine d'essayer.

Arnauld
la source
9

Java 10, 350 343 340 336 octets

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

Dest un nombre entier 2D-réseau dans lequel les directions sont des nombres entiers 0 indexées: N=0, NE=1, E=2, SE=3, S=4, SW=5, W=6, NW=7. Les x,ycoordonnées de départ seront deux paramètres séparés set S. La sortie est une matrice de caractères.
Il utilise #comme bordure, *comme piste et Opour la position de fin (mais il peut s'agir de trois caractères ASCII dans la plage unicode [33,99]pour le même nombre d'octets si vous le souhaitez).

Essayez-le en ligne.

-4 octets grâce à @ceilingcat .
Peut certainement être joué un peu plus en simplifiant les mouvements et dans quelle direction nous voyageons un peu plus.

Explication:

(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:7est une version golfée de ceci ci-dessous en utilisant 4-iet 8-ipour la plupart des changements de direction:

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
la source
3

Fusain , 74 octets

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

Essayez-le en ligne! Le lien est vers la version détaillée du code. Prend l'entrée au format n, x, y, d où d est un tableau de tableaux de [distance, direction] paires où la direction est un codage numérique 0 = sud dans le sens horaire à 7 = sud-est. Explication:

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

Saisissez net dessinez une boîte dont l'intérieur est cette taille centrée sur l'origine.

JN±N

Entrez et passez à xet y(mais annulez ycar l'axe Y du charbon de bois augmente vers le bas).

FA«

Parcourez les entrées dans d.

≔⊟ιζ

Extraire la direction initiale.

F⊟ι«

Répétez l'opération pour la distance souhaitée.

≔ζδ

Enregistrez la direction.

↷δ¶

Faites un mouvement expérimental dans cette direction.

F›⊗↔ⅈθ≦±ζ

Si cela sort des côtés, inversez la direction horizontalement.

F›⊗↔ⅉθ≦⁻⁴ζ

Si cela sort du haut ou du bas, inversez la direction verticalement.

≧﹪⁸ζ

Réduisez la direction modulo 8 (les commandes de pivot acceptent uniquement les valeurs de 0 à 7).

↷⁴¶↶⁴

Annulez le mouvement expérimental.

↶δ↷ζ*¶

Faites face à la bonne direction, puis imprimez une trace et déplacez-vous.

↶ζPo

Revenez dans la direction par défaut et imprimez l'objet dans la position actuelle.

Neil
la source
2

JavaScript, 206 octets

Prend l'entrée comme (n, x, y, [[dir, len], [dir, len], ...]) où les directions sont codées à l'aide de masques de bit:

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

Sort une chaîne avec

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

Les différentes valeurs des limites sont utilisées pour évaluer la prochaine direction

(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``)

Moins 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``
)

TESTER

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
la source
2

C (gcc) , 352 323 octets

Golfé en bas de 29 octets grâce au plafond.

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

Essayez-le en ligne!

Le programme prend l'entrée comme arguments de ligne de commande (comme a.out 10 1 1 3 5 0 4 7 2):

  • le premier argument est la taille du champ,
  • les deux suivants sont les coordonnées initiales (X,y) de l'acteur,
  • toutes les paires d'arguments à partir du quatrième sont (,t) paires où est la direction (représentée par un nombre 0..7, en partant de 0 = Eet en tournant dans le sens horaire) ett est le nombre d'étapes.

Explication

// 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
la source
1
Je crois que votre code ne contient pas la sortie de l'objet à la position finale, car la trace de l'objet suivi peut également être les caractères que vous choisissez, tant qu'ils n'occupent qu'un espace dans l'avion et sont différents de l'objet . A part ça, ça me semble bien.
J. Sallé
Oups, j'ai totalement raté ça, merci d'avoir remarqué J.Sallé. Heureusement, la correction n'a pas allongé le programme.
Max Yekhlakov