Interprète RoboZZle

10

Votre tâche consiste à écrire un interpréteur RoboZZle. Si vous n'êtes pas familier avec le jeu, veuillez regarder la vidéo sur robozzle.com ou lire ma description ci-dessous.

Un robot vit sur une grille rectangulaire de carrés de couleur rouge, verte, bleue ou noire. Les carrés noirs sont inaccessibles. Les autres sont accessibles et certains contiennent une étoile. Le but est de collecter toutes les étoiles sans marcher sur les carrés noirs ni tomber de la carte. Le robot occupe une case et fait face à une direction particulière - gauche, droite, haut ou bas. Il suit les instructions de type assemblage regroupées en sous-programmes F1, F2, ..., F5. Une instruction est une paire de prédicats ("aucun", "si rouge", "si vert", "si bleu") et une action ("aller de l'avant", "tourner à gauche", "tourner à droite", "peindre le carré actuel en rouge", "peindre en vert", "peindre en bleu", "ne rien faire", "appeler F1", ..., "appeler F5"). Les appels aux sous-programmes utilisent une pile et peuvent être récursifs. Tout comme dans la programmation conventionnelle, une fois la dernière instruction d'un sous-programme terminée, l'exécution se poursuit à partir du point où le sous-programme a été appelé. L'exécution commence à partir de la première instruction de F1 et se poursuit jusqu'à ce que le robot ait visité toutes les cases avec des étoiles, ou lorsque le robot marche sur un carré noir ou à l'extérieur de la carte, ou que 1000 instructions aient été exécutées (prédicats en échec et actions "ne rien faire" ne compte pas), ou il n'y a plus d'instructions à exécuter (sous-dépassement de pile).

Contributions:

  • a- une matrice de 12x16 caractères (comme généralement représentée dans votre langue, par exemple un tableau de chaînes) qui code une carte - '#'pour les carrés inaccessibles (noirs), '*'pour les carrés avec une étoile, '.'pour le reste

  • c- une matrice de 12x16 caractères décrivant les couleurs des carrés accessibles - 'R'(rouge), 'G'(vert) ou 'B'(bleu). Les carrés inaccessibles seront représentés par une lettre arbitraire des trois.

  • yet x- la ligne et la colonne de base 0 du robot; a[y][x]est garanti d'être'.'

  • d- la direction du robot est tourné vers: 0 1 2 3pour la droite, vers le bas, à gauche, en haut, à savoir vers (y,x+1), (y+1,x), (y,x-1),(y-1,x)

  • f- une seule chaîne, les implémentations concaténées de F1 ... F5. Chaque implémentation est une séquence (éventuellement vide) de paires action-prédicat (au plus 10 paires par sous-programme), terminée par un '|'.

    • prédicats: '_'aucun, 'r'rouge, 'g'vert, 'b'bleu

    • actions: 'F'avancer, 'L'tourner à gauche, 'R'tourner à droite, 'r'peindre rouge, 'g'peindre vert, 'b'peindre bleu, '1'appeler F1, ..., '5'appeler F5, '_'ne rien faire

Vous n'avez pas besoin de nommer vos entrées comme ci-dessus, mais leurs valeurs doivent être telles que spécifiées.

Sortie: 1(ou true) si le robot recueille toutes les étoiles selon les règles, 0( false) sinon.

Exemple :

a=["################","################","##*....*...*#.##","##.####.#####.##","##.####.#####.##","##.####*...*#.##","##.########.####","##*........*#.##","################","################","################","################"]
c=["RRRRRRRRRRRRRRRR","RRRRRRRRRRRRRRRR","RRRBBBBRGGGGRRRR","RRBRRRRGRRRRRRRR","RRBRRRRGRRRRRRRR","RRBRRRRRGGGBRRRR","RRBRRRRRRRRGRRRR","RRRBBBBGGGGBRBRR","RRRRRRRRRRRRRRRR","RRRRRRRRRRRRRRRR","RRRRRRRRRRRRRRRR","RRRRRRRRRRRRRRRR"]
y=2; x=6; d=2

// and then depending on "f":
f="_FrLg2_1|_FbLrR_2||||" // result:1
f="_FrRg2_1|_FbLrR_2||||" // result:0 (stepped on a black square)
f="_FrLrL_1|_FbLrR_2||||" // result:0 (1000-step limit exceeded)
f="_FrLg2__|________||||" // result:0 (stack underflow)

Un autre exemple , impliquant des instructions de "peinture":

a=["#***************","#*###*###*###*##","#*###*###*###*##","***#***#***#***#","***#***#***#***#","*###*###*###*###","***#***#***#***#","***#***#***#***#","***#***#***#***#","*###*###*###*###","*.*#***#***#***#","***#***#***#***#"]
c=["RGGGGGGGGGGGGGGG","RBRRRGRRRGRRRGRR","RBRRRGRRRGRRRGRR","RBRRGGGRGGGRGGGR","BRRRGGGRGGGRGGGR","BRRRGRRRGRRRGRRR","BRRRGGGRGGGRGGGR","RBRRGGGRGGGRGGGR","BRRRGGGRGGGRGGGR","BRRRGRRRGRRRGRRR","BGRRGGGRGGGRGGGR","RBRRGGGRGGGRGGGR"]
y=10; x=1; d=0
f="_2_R_R_1|_FgRgFgFg3rRr4b2_Fgb|_F_F_R|_2_L_r||"
// result:1

Pour générer votre propre test, accédez à un puzzle de la liste sur robozzle.com , essayez de le résoudre (ou de ne pas le résoudre), appuyez sur F12 dans votre navigateur, tapez dans la console JS:

r=robozzle;s=JSON.stringify;with(r.level)console.log('a='+s(Items)+'\nc='+s(Colors)+'\ny='+RobotRow+'\nx='+RobotCol+'\nd='+RobotDir+'\nf='+s(r.encodeSolution()))

et reformatez le résultat pour votre langue.

Victoires les plus courtes. Pas de failles.

ngn
la source
1
Pouvons-nous utiliser des caractères distincts pour représenter les données au lieu de ceux fournis?
HyperNeutrino
1
Pour votre réponse APL au défi "Loop it", vous pouvez trier la dernière valeur d'angle en diminuant la magnitude complexe.
user202729
1
@ user202729 Euh, je ne m'attendais pas à un commentaire sur ce défi ici :) Votre idée fonctionne, merci! Je vais essayer de l'implémenter sans rendre le caractère trop honteux.
ngn
1
Pouvons-nous prendre les matrices de caractères comme une liste de paires d'emplacements et de caractères?
0
1
@ 0 'Le principe que j'ai suivi ici (voir aussi le commentaire d'HyperNeutrino) est de rester aussi proche que possible du format d'entrée réellement utilisé sur robozzle.com, donc je crains que ce ne soit pas une liste de paires.
ngn

Réponses:

5

Prolog (SWI) , 574 octets

Z*A:-findall(X^Y-D,(nth0(Y,Z,O),nth0(X,O,C),plus(32,C,D)),L),list_to_assoc(L,A).
N^C^G^[P,I|R]^F^X^Y^D:-map_assoc(\=(74),G);N<1e3,get_assoc(X^Y,G,J),J>67,put_assoc(X^Y,G,78,H),T=N+1,((I\=95,(P=95;get_assoc(X^Y,C,P)))->(between(49,53,I),plus(48,M,I),nth1(M,F,Q),append(Q,R,S),T^C^H^S^F^X^Y^D;member(I,`RL`),E is(D-I//3)mod 4,T^C^H^R^F^X^Y^E;I=70,(D=0,U is X+1;D=1,V is Y+1;D=2,U is X-1;D=3,V is Y-1),(U=X;V=Y),T^C^H^R^F^U^V^D;I>97,put_assoc(X^Y,C,I,W),T^W^H^R^F^X^Y^D);N^C^H^R^F^X^Y^D).
A+C+F+L:-A*G,C*B,split_string(F,"|","",P),maplist(string_codes,P,[M|N]),0^B^G^M^[M|N]^L.

Essayez-le en ligne!

Cela définit un prédicat qui, lorsqu'il est appelé, réussit si toutes les étoiles sont collectées avec succès et échoue autrement. Le prédicat prend les arguments en tant que tels: a+c+f+x^y^d.. aet cdoit être une liste de chaînes entre guillemets, tandis que fdoit être une chaîne entre guillemets doubles.

Explication

Ce programme contient trois prédicats, */2, ^/2et +/2. Les */2prédicats définis sur la première ligne sont responsables d'une partie du traitement d'entrée. Le ^/2prédicat calcule récursivement comment le robot se déplace pas à pas et réussit si le robot recueille légalement toutes les étoiles et échoue dans le cas contraire. Le +/2prédicat est le prédicat principal du programme et prépare l'entrée du ^/2prédicat avec l'aide du */2prédicat. Notez que chacun de ces prédicats ne prend techniquement que deux arguments, mais en utilisant des opérateurs et une correspondance de modèle, ils peuvent se comporter comme s'ils avaient plus d'arguments (je discute ce phénomène plus en détail ici ).

*/2

Z*A:-findall(X^Y-D,(nth0(Y,Z,O),nth0(X,O,C),plus(32,C,D)),L),list_to_assoc(L,A).

Ce prédicat prend deux arguments. Le premier est une liste de listes de codes de caractères (c'est ainsi que Prolog analyse les chaînes entre guillemets). La seconde est une carte associative des points de la carte 12x16 (représentée par X^Y) à 32 plus le code de caractère stocké à ce point dans la liste des listes de codes de caractère. Le 32 est ajouté à chacun des codes de caractères de sorte que pour la matrice de couleurs, il transformera les caractères de couleur majuscules en caractères de couleur minuscules.

Pour ce faire, il génère une liste de paires de points et les codes de caractères à ce point à l'aide findall/3. Il utilise ensuite list_to_assoc/2pour créer la carte associative correspondante des points au code de caractère à ce point.

Le findall/3prédicat est une fonction intégrée qui prend un "modèle" comme premier argument, un objectif comme deuxième argument et une liste comme troisième argument. Le prédicat remplit la liste avec toutes les valeurs possibles du modèle qui font réussir l'objectif. En raison de la priorité de l'opérateur, le modèle transmis à findall/3in */2est analysé comme (X^Y)-D. L' -opérateur représente une paire de deux valeurs dans Prolog, de sorte que le modèle représente l'emplacement du point ( X^Y) associé à 32 plus le code de caractère du point ( D). Notez que le ^utilisé pour représenter le point n'est en aucun cas connecté au ^/2prédicat.

Considérons le but qui est passé au findall/3prédicat.

nth0(Y,Z,O),nth0(X,O,C),plus(32,C,D) % Note that the O (oh) is not a 0 (zero)

L'objectif contient trois prédicats dont chacun doit réussir pour que l'objectif réussisse. Le nth0/3prédicat qui est utilisé deux fois est utilisé pour obtenir la valeur à un index particulier de la liste (le 0dans son nom indique qu'il est indexé zéro). Le premier appel à celui-ci stocke la Ye ligne de la matrice de caractères dans Otandis que le deuxième appel stocke le Xe caractère de cette ligne dans C. Le prédicat final plus/3réussit si ses deux premiers arguments résument son troisième argument. Ceci est utilisé pour rendre le code de caractères dans la paire est 32 supérieur au code de caractères dans la matrice de caractères qui, comme indiqué ci-dessus, transformera toutes les lettres majuscules en lettres minuscules.

Enfin, findall/3stocke toutes les X^Y-Dcombinaisons qui font réussir son objectif dans la liste à partir de Llaquelle la carte associative est construite.

Plus à venir bientôt...

0 '
la source
4

JavaScript (ES6), 298 276 264 octets

8 octets enregistrés grâce à @ngn

Prend l'entrée comme (a,c,x,y,d,f), où aet csont des tableaux de tableaux de caractères. Renvoie 0ou 1.

(a,c,x,y,d,f,k=1e3)=>(g=(F,p=0,s=f.split`|`[F],r=a[y])=>!k|!r|x&16||r[x]<'$'?2:/\*/.test(a)?(r[x]=o=0,(I=s[p+1],P=s[p])&&(P<'b'|P==c[y][x].toLowerCase()&&I!='_'&&k--?+I?o=g(I-1):I=='L'?d--:I=='R'?d++:I<'b'?y+=(d&=3,x-=~-d%2,2-d)%2:c[y][x]=I:0,o||g(F,p+2))):1)(0)&1

Cas de test

Commenté

(                                           // main function taking:
  a, c, x, y, d, f,                         //   - input variables
  k = 1e3                                   //   - k = instruction counter
) => (                                      //
  g = (                                     // g = recursive execution function, taking:
    F,                                      //   - F = subroutine id
    p = 0,                                  //   - p = instruction pointer
    s = f.split`|`[F],                      //   - s = instruction string
    r = a[y]                                //   - r = current row in a[]
  ) =>                                      //
    !k |                                    // if we've executed 1000 instructions
    !r | x & 16 ||                          // or we've felt out of the map
    r[x] < '$' ?                            // or we've reached a black square:
      2                                     //   exit with error code 2
    :                                       // else:
      /\*/.test(a) ? (                      //   if there are still some stars:
        r[x] = o = 0,                       //     mark the current cell as visited
        (I = s[p + 1], P = s[p]) &&         //     I = instruction, P = predicate
        (                                   //     if P is defined:
          P < 'b' |                         //       if the predicate is '_'
          P == c[y][x].toLowerCase()        //       or it matches the color of the cell
          && I != '_'                       //       and the instruction is not '_',
          && k-- ?                          //       then decrement k and:
            +I ?                            //         if I is '1' ... '5':
              o = g(I - 1)                  //           process call to subroutine
            :                               //         else:
              I == 'L' ?                    //           if I is 'L':
                d--                         //             turn left
              :                             //           else:
                I == 'R' ?                  //             if I is 'R':
                  d++                       //               turn right
                :                           //             else:
                  I < 'b' ? (               //               if I is not a color:
                    y += (                  //                 I must be 'F',
                      d &= 3,               //                 so make the bot advance
                      x -= ~-d % 2,         //                 by updating x
                      2 - d                 //                 and y
                    ) % 2                   //
                  ) :                       //               else:
                    c[y][x] = I             //                 paint the current cell
          :                                 //       else:
            0,                              //         do nothing
          o ||                              //       provided that o is equal to 0,
          g(F, p + 2)                       //       go on with the next instruction
        )                                   //     end of instruction execution
      ) :                                   //   else:
        1                                   //     success: return 1
  )(0) & 1                                  // initial call to the subroutine F1
Arnauld
la source
x+='2101'[d&3]-1,y+='1210'[d&3]-1->d&=3,x+=(1-d)%2,y+=(2-d)%2
ngn
1
xles changements par au plus 1, donc je pense que vous pouvez remplacer x&~15parx&16
ngn
1

APL (Dyalog Classic) , 236 233 octets

-3 grâce à Erik l'Outgolfer

Maintenant que j'ai donné le bonus, je publie un exemple de solution à mon propre défi. Il y a place à amélioration ici - n'hésitez pas à copier et à jouer au golf plus loin.

a c r d f←⎕⋄c819cF0,('|'1f)/⍳≢ftn0
{~(⊂r)∊⍳⍴a:0'#'=ra:0p q2f↓⍨⊃⌽t⋄(_p'|')∧×≢t:0_:∇t↓←¯1⋄(⊃⌽t)+←2⋄~p'_',rc:∇0n+←1n>999:0⋄(ra)←'.'⋄~'*'a:1r+←(q'F'11 90j1*dd+←4|'.R.L'qq'rgb':∇(rc)←qq∊⎕d:∇t,←F[⍎q]⋄∇0}0

Essayez-le en ligne!

Comme ci-dessus, développé avec des commentaires:

io0                    0-based indices (not counted in the score)
a c r d f←⎕              decompose eval'ed input (⎕) into variables
c←819⌶c                 ⍝ make c lowercase
F←0,('|'=¯1⌽f)/⍳≢f      ⍝ split f at the '|'-s
t←n←0                   ⍝ t:stack, n:step counter
{                       ⍝ lambda
  ~(⊂r)∊⍳⍴a:0           ⍝ if the robot is off the map, return 0
  '#'=r⌷a:0             ⍝ if the robot is on a wall, return 0
  p q2f↓⍨⊃⌽t           current instruction - p:predicate, q:action
  (_p'|')∧1≥≢t:0       if at end of func and stack is empty, return 0
  _:∇t↓←¯1               if at end of func, pop from stack and recurse
  (⊃⌽t)+←2               increment program counter (top of stack)
  ~p'_',rc:∇0          if predicate doesn't match cell colour, recurse
  n+←1⋄n>999:0          ⍝ if too meany steps, return 0
  (r⌷a)←'.'             ⍝ consume star
  ~'*'∊a:1              ⍝ if no more stars left, return 1
  r+←(q≡'F')×11 9○0j1*d ⍝ if action is F, move forward
  d+←4|'.R.L'⍳q         ⍝ if action is L or R, turn left or right
  q∊'rgb':∇(r⌷c)←q      ⍝ if action is paint (r,g,b), do it
  q∊⎕d:∇t,←F[⍎q]        ⍝ if action is F1...F5, push on stack and recurse
  ∇0                    ⍝ action is nop (_), recurse
}0                      ⍝ call the lambda (argument will be ignored)
ngn
la source
233 octets
Erik l'Outgolfer
@EriktheOutgolfer changement appliqué, merci
ngn