Naviguer avec succès dans un champ d'astéroïdes

36

introduction

Tout le monde sait que la possibilité de naviguer avec succès dans un champ d'astéroïdes est d'environ 3 720 à 1. Cependant, malgré votre avertissement, Han Solo est toujours disposé à tenter sa chance.

Craignant pour votre vie artificielle, vous décidez de coder, dans le dialecte spécifique du navire ( lisez: votre langue préférée de Code Golf ), un programme permettant d'éviter les astéroïdes qui décidera quel chemin emprunter dans un labyrinthe ASCII de champ d'astéroïdes.

Contribution

Le Millenium Falcon possède un programme de cartographie des astéroïdes qui fournit des données similaires à celles-ci:

|   #####           #########  |
| ######  #          ###   #   |
|   # #  #  #  ####   #        |
@              ##    ####       
|#   #   #       ###   ##      |
|##      ##      ####   #  #   |
|####           ##### #   ##   |

Les rangées supérieures sont à gauche du Falcon, les rangées inférieures à droite du Falcon et les colonnes représentent ce qui se trouve devant le vaisseau.

  • Chaque # est un obstacle.
  • Chaque espace est un espace vide dans lequel le navire peut voler.
  • L'entrée est toujours haute de 7 caractères. C'est la limite de largeur de mappage d'astéroïde.
  • La saisie comporte toujours 32 caractères (30 pour le champ et 2 pour les limites de début et de fin). C'est la limite de profondeur de cartographie d'astéroïde. Barres verticales| marquent le début et la fin du mappage.
  • @est le faucon. Il se trouve toujours dans la rangée du milieu (4ème rangée) et dans la première colonne de l'entrée.
  • L'espace laissé dans les barres verticales de la dernière colonne est l'endroit où le navire doit arriver. Il est toujours dans la rangée du milieu (4ème rangée) et dans la dernière colonne de l'entrée.

L'entrée peut être considérée comme une chaîne multiligne, un tableau de chaînes, à partir de paramètres STDIN ou d'une fonction, ou lue dans un fichier.

Manoeuvres possibles

TIE-Fighters vous poursuit, vous devez donc toujours aller de l'avant. Le navire peut donc voler à chaque étape de trois manières différentes:

  • - Vers l'avant

  • / Avancer et tourner à gauche

  • \ Avancer et tourner à droite

Par exemple, ce sont des chemins valides:

@---

  --
 /  \ /
@    -

   -
  / \
 /   \
@     \

Comme vous pouvez le constater, il y a toujours exactement un mouvement par colonne. Le Falcon est un morceau de ferraille, donc il ne peut pas faire de virages violents. Ce qui signifie des mouvements tels que /\ou \/sont interdits . Il doit y avoir au moins un pur attaquant- entre deux tours opposés. Comme indiqué ci-dessus, il est également possible de tourner dans un sens pour plusieurs étapes consécutives.

Le Falcon se bloque si un mouvement entraîne le navire dans un endroit où se trouve un obstacle. Par exemple, ces mouvements entraînent des accidents:

@-#

@
 \
  #

  #
 /
@

Notez que ce n'est pas un crash:

@-#
  \
   -

Sortie

Vous devez sortir le même champ astéroïde ASCII, avec un chemin valide à la fin. Le Falcon doit être imprimé au point final au lieu du point de départ.

Par exemple, une sortie valide pour l'exemple d'entrée donné ci-dessus serait:

|   #####           #########  |
| ######  #--------  ###   #   |
|   # #  #/ #  ####\  #        |
 ---------      ##  \ #### ----@
|#   #   #       ### \ ## /    |
|##      ##      #### \ #/ #   |
|####           ##### #-- ##   |

Votre chemin doit seulement ne pas écraser le faucon. Il n'est pas nécessaire que ce soit le chemin le plus court possible.

Vous pouvez supposer qu'il y aura toujours au moins un chemin possible vers la fin.

Vous pouvez exporter vers STDOUT, dans un fichier ou un équivalent, tant que le champ de l'astéroïde est imprimé exactement comme ils le sont dans cet article (par exemple, l'affichage d'une liste de coordonnées pour le chemin d'accès n'est pas valide).

Cas de test

  • Un champ d'astéroïdes normal

    |   #####           #########  |
    | ######  #          ###   #   |
    |   # #  #  #  ####   #        |
    @              ##    ####       
    |#   #   #       ###   ##      |
    |##      ##      ####   #  #   |
    |####           ##### #   ##   |
    

    Sortie possible

    |   #####           #########  |
    | ######  #--------  ###   #   |
    |   # #  #/ #  ####\  #        |
     ---------      ##  \ #### ----@
    |#   #   #       ### \ ## /    |
    |##      ##      #### \ #/ #   |
    |####           ##### #-- ##   |
    
  • Champ d'astéroïdes hyper-régulier

    |# # # # # # # # # # # # # # # |
    | # # # # # # # # # # # # # # #|
    |# # # # # # # # # # # # # # # |
    @ # # # # # # # # # # # # # #   
    |# # # # # # # # # # # # # # # |
    | # # # # # # # # # # # # # # #|
    |# # # # # # # # # # # # # # # |
    

    Sortie possible

    |# # # # # # # # # # # # # # # |
    | # # # # # # # # # # # # # # #|
    |# # # # # # # # # # # # # # # |
     -# #-# #-# #-# #-# #-# #-# #--@
    |#\#/#\#/#\#/#\#/#\#/#\#/#\#/# |
    | #-# #-# #-# #-# #-# #-# #-# #|
    |# # # # # # # # # # # # # # # |
    
  • Noyau de l'étoile de la mort

    |    #    #    #         #     |
    |         #    #    #          |
    |    #    #    #    #    #     |
    @    #    #    #    #    #      
    |    #    #         #    #     |
    |    #    #    #    #    #     |
    |    #         #    #    #     |
    

    Sortie possible

    |    #    #    #   --    #     |
    |  ---    #    #  / #\   -     |
    | /  #\   #    # /  # \ /#\    |
     -   # \  #    #/   #  - # ----@
    |    #  \ # ----    #    #     |
    |    #   \#/   #    #    #     |
    |    #    -    #    #    #     |
    
  • Tranchée étoile de la mort

    |##############################|
    |##############################|
    |##############################|
    @                               
    |##############################|
    |##############################|
    |##############################|
    

    Sortie

    |##############################|
    |##############################|
    |##############################|
     ------------------------------@
    |##############################|
    |##############################|
    |##############################|
    
  • Grotte d'astéroïdes

    |### ##########################|
    |## # ############### ## ######|
    |# ###  ######## ### ## # #####|
    @ ###### ###### ### ## ###      
    |########  ### ### ## #########|
    |########## # ### ## ##########|
    |###########              #####|
    

    Sortie possible

    |###-##########################|
    |##/#\############### ##-######|
    |#/###--######## ### ##/#\#####|
     -######\###### ### ##/###-----@
    |########--### ### ##/#########|
    |##########\# ### ##/##########|
    |###########--------      #####|
    

Notation

R2D2 est occupé à nager dans les marécages, vous devrez donc programmer vous-même le contrôleur du Falcon, ce qui est fastidieux. Par conséquent, le code le plus court gagne .

Fataliser
la source
@DJMcMayhem: Techniquement, la première ligne est "Introduction";)
Alex A.
2
Je comprends un peu comment les choses sont supposées être basées sur les exemples, mais l'encodage des mouvements me déroute toujours un peu. Si vous regardez par exemple à l'exemple "hyper-régulier", à l'exception du premier / dernier mouvement, vous vous déplacez toujours en diagonale. Pourtant, il a- , à chaque virage, un chemin qui se définit comme un coup «en avant». Mais les mouvements réels sont toujours deux diagonales à gauche suivies de deux diagonales à droite.
Reto Koradi
@RetoKoradi Je peux comprendre que ce n'est pas si évident, mais l'idée de base est que tous les mouvements vous font parcourir la largeur d'un caractère à droite. Le chemin doit être continu, raison pour laquelle le mouvement précédent / suivant après les virages à droite et à gauche correspond à une ligne au-dessus / au-dessous du précédent.
Fataliser
@apsillers Les deux sont valables, si je vous ai bien compris, votre réponse devrait être bonne
Fatalize

Réponses:

11

JavaScript (ES6), 186 201

f=([...s])=>(g=(i,l,c=k=" ")=>s[i]!=k&&s[i]!="@"?0:(i-130)?(s[i]=c,([..."/-\\"].some((c,j)=>!((--j&l&&j!=l)||!g(i+33*(l||j)+1,j,c)))||!(s[i]=k))):(s[i]="@",!console.log(s.join(""))))(99)

Snippet exécutable:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><textarea cols="33" rows="7" id="t"></textarea><br><button><b>Solve &gt;&gt;&gt;</b></button><hr><button id="1">Normal</button> <button id="2">Hyperregular</button> <button id="3">Death Star core</button> <button id="4">Death Star trench</button> <button id="5">Asteroid cave</button><script>f=(function($__0){var $__2,$__3,$__4,$__5;s = $__4 = $__0.split("");return (g = (function(i, l) {var c = arguments[2] !== (void 0) ? arguments[2] : k = " ";return s[i] != k && s[i] != "@" ? 0 : (i - 130) ? (s[i] = c, ("/-\\".split("").some((function(c, j) {return !((--j & l && j != l) || !g(i + 33 * (l || j) + 1, j, c));})) || !(s[i] = k))) : (s[i] = "@",$("#t").val(s.join("")));}))(99);});$("button").click(function() {this.id?$("#t").val(inputs[this.id]):f($("#t").val());});inputs = [,`|   #####           #########  |\n| ######  #          ###   #   |\n|   # #  #  #  ####   #        |\n@              ##    ####       \n|#   #   #       ###   ##      |\n|##      ##      ####   #  #   |\n|####           ##### #   ##   |`,`|# # # # # # # # # # # # # # # |\n| # # # # # # # # # # # # # # #|\n|# # # # # # # # # # # # # # # |\n@ # # # # # # # # # # # # # #   \n|# # # # # # # # # # # # # # # |\n| # # # # # # # # # # # # # # #|\n|# # # # # # # # # # # # # # # |`,`|    #    #    #         #     |\n|         #    #    #          |\n|    #    #    #    #    #     |\n@    #    #    #    #    #      \n|    #    #         #    #     |\n|    #    #    #    #    #     |\n|    #         #    #    #     |`,`|##############################|\n|##############################|\n|##############################|\n@                               \n|##############################|\n|##############################|\n|##############################|`,`|### ##########################|\n|## # ############### ## ######|\n|# ###  ######## ### ## # #####|\n@ ###### ###### ### ## ###      \n|########  ### ### ## #########|\n|########## # ### ## ##########|\n|###########              #####|`];$("#t").val(inputs[1]);</script

Cette fonction accepte une seule chaîne avec des nouvelles lignes. La fonction divise la chaîne en un tableau à l'aide de l' ...opérateur et obtient l'index des (x,y)coordonnées par (33 * y) + x.

La fonction s'exécute de manière récursive, testant différents mouvements possibles pour chaque espace. Lorsqu'il rencontre un obstacle, il renvoie une valeur de fausseté et lorsqu'il atteint l'espace de l'objectif final, il revient true. (Dans le code golfé, cela trueest créé par !console.log(...).)

Notez que ce code n'utilise pas de longs mouvements de mouvements à droite, mais les ponctue de mouvements droits. C'est la deuxième option ci-dessous, pas la première:

\                       \
 \   (<= not this!)      -   (<= yes this!)
  \                       \

Cela semble être légal, puisque - peut légalement venir avant ou après un tour, alors pourquoi pas les deux à la fois? Cela semble particulièrement étrange à la fin, quand le dernier coup est \mais est affiché comme @:

|  --#    #    #   ------#  -  |
| /  \    #    #  / #    \ / \ |
|/   #-   #    # /  #    #-   -|
     # \  #    #/   #    #     @
|    #  - # ----    #    #     |
|    #   \#/   #    #    #     |
|    #    -    #    #    #     |

Mon hack de golf méchant préféré ici est un abus d'argument par défaut avec c=k=" ". Les arguments (i,l,c=" ")diraient "utiliser la chaîne " "car cif fn'est pas fourni un troisième argument". Cependant, en faisant c=k=" ", on dit "sic n'est pas fourni, enregistrez " "dans la variable globale k, puis enregistrez cette valeur c". Comme la récursivité ne commence qu'avec un seul argument, elle kest toujours initialisée au premier appel de fonction.

Légèrement non-golfé:

// `i` - index in the string we're working on
// `l` - move character for this space (`/`, `\`, or `-`)
search = (i,l,c)=>{

  // not an open space; nip this recursive branch
  if(s[i]!=" "&&s[i]!="@") { return 0; }

  // we made it! the 130th space is (31,3)
  if(i==130) {
      s[i]="@";
      console.log(s.join(""));
      return true;
  }

  // fill in space with move character or a blank
  // (the space is only to blank out the initial `@`)
  s[i] = c || " ";

  // iterate through the 3 options and recursively explore the map
  return ['/','-','\\'].some((c,j)=>{
    --j;
    // if last move was sideways, and this is the opposite move, skip it
    if(l && j && j!=l) { return 0; }

    // recursively call search function on space pointed to by this move or the last move
    return search(i+33*(l||j)+1, j, c);
  })

  // if the `some` call is false (i.e. all options fail for this space)
  // then blank out this space and return false
  || !(s[i]=" ");

}
apsillers
la source
@ vihan1086 C'est vrai, j'ai totalement manqué ces espaces quand je suis golfeur. D: Et passer d'un tableau à une chaîne scindée est également un bon changement. Merci. :) J'ai également apporté quelques autres modifications (en transformant le caractère de déplacement actuel en un troisième argument au lieu d'être déterminé dans la fonction et en enregistrant " "une variable) qui a réduit mon score encore plus bas.
apsillers
7

C (programme complet), 249 247 235 octets

Il s’agit d’un programme complet qui lit l’entrée d’un fichier et affiche le résultat sur stdout. Le nom du fichier est transmis en tant que paramètre au programme.

char f[7][33];g(i,j,c){return(i<0|i>6|f[i][j]%32?0:j<31?c%45-2?g(i,j+1,c)||g(i+1,j+1,92)||g(i-1,j+1,47):g(i+c/30-2,j+1,c)||g(i+c/30-2,j+1,45):1)?f[i][j]=j?j-31?c:64:32:0;}main(int p,char**v){read(open(v[1],0),f,231);g(3,0,45);puts(f);}

Ungolfed:

/* the field */
char f[7][33];

/* i - row
 * j - col
 * c - movement
 */
g(i,j,c)
{
    return
            /* if we're in bounds and not on an obstacle */
            (i >= 0 & i<7 & f[i][j] % 32 == 0 ?
                    /* if we haven't reached the end */
                    j < 31 ?
                            /* are we going straight ahead? */
                            c%45-2 ?
                                    /* try to go straight */
                                    g(i,j+1,c)
                                    /* try to turn right */
                                    || g(i+1,j+1,92)
                                    /* try to turn left */
                                    || g(i-1,j+1,47)
                            /* turning */
                            :
                                    /* try to keep turning */
                                    g(i+c/30-2,j+1,c)
                                    /* try to go straight */
                                    || g(i+c/30-2,j+1,45)
                    /* done */
                    :1 /* replace this with c==45 to better represent the last move being a turn */
            /* invalid move, fail */
            :0)
            /* add the correct movement to the field */
            ? f[i][j] = j ? j - 31 ? c : 64 : 32
            /* no path, much sads :( */
            :0;
}

main(int p,char*v[])
{
    /* read input file */
    read(open(v[1],0),f,231);

    /* calculate the path */
    g(3,0,45);

    /* print it out */
    puts(f);
}

Sortie:

$ ./a.out test.inp
|   #####           #########  |
| ######  #          ###   #   |
|   # #  #  #  ####   #      --|
 ------------- ##----####   /  @
|#   #   #    \ /### \ ##  /   |
|##      ##    - #### \ # /#   |
|####           ##### #---##   |

$ ./a.out test2.inp
|# # # # #-# # # # # #-# # # # |
| # # # #/#\# # # # #/#\# # # #|
|# # # #/# #\# # # #/# #\# # # |
 -# # #/# # #\# # #/# # #\# #  @
|#\# #/# # # #\# #/# # # #\# #/|
| #\#/# # # # #\#/# # # # #\#/#|
|# #-# # # # # #-# # # # # #-# |

$ ./a.out test3.inp
|    #    #    #   ------#     |
|    -    #    #  / #    \     |
|   /#\   #    # /  #    #\    |
 --- # \  #    #/   #    # \   @
|    #  \ #    /    #    #  \ /|
|    #   \#   /#    #    #   - |
|    #    ---- #    #    #     |

$ ./a.out test4.inp
|##############################|
|##############################|
|##############################|
 ------------------------------@
|##############################|
|##############################|
|##############################|

$ ./a.out test5.inp
|###-##########################|
|##/#\############### ##-######|
|#/###--######## ### ##/#\#####|
 -######\###### ### ##/###-----@
|########--### ### ##/#########|
|##########\# ### ##/##########|
|###########--------      #####|
Cole Cameron
la source
On dirait que vous avez raté le point final du premier test.
Reto Koradi
@RetoKoradi C'est un -suivi par un \, mais le \est recouvert par le @. (Mon programme fait la même chose.)
apsillers
1
@RetoKoradi Les versions précédentes de cette question traitaient mieux cette affaire. C'est +4 octets. J'ai remarqué que la solution d'Apsillers se comportait de la même manière et j'ai donc choisi de gagner de la place.
Cole Cameron
Je vois. Cela ne me semble pas correct, mais c'est au PO de décider ce qui est autorisé. J'ai vu qu'ils ont donné une certaine liberté sur la façon dont les mouvements sont représentés. J'aurais aimé voir une définition claire et unique dès le début. Cela semblait être un problème amusant, mais l’ambiguïté n’est pas aussi intéressante.
Reto Koradi
3

Common Lisp, 303 octets

Je me suis bien amusé avec ce défi, c’est la première tâche que j’ai réalisée avec CodeGolf. En gros, il existe une fonction récursive simple qui essaie tous les mouvements viables jusqu'à atteindre la position finale.

Golfé / Minifié

(let((s(open "i"))(n nil)(f(make-string 231)))(read-sequence f s)(labels((r(p s u d)(and(< 0 p 224)(find(aref f p)" @")(setf(aref f p)(cond((= 130 p)#\@)((or(unless d(r(- p 32)#\/ t n))(unless u(r(+ p 34)#\\ n t))(r(+ p(cond(u -32)(d 34)(t 1)))#\- n n))s)((return-from r)))))))(r 99 #\- n n)(princ f)))

Lit les entrées d’un fichier i dans le répertoire de travail. Je suis sûr que des améliorations sont encore possibles.

Code simple

(defun run-test (file)
  (let ((stream (open file)) ;;should use with-open-file for autoclose..
        (no nil) ;; alias for brevity
        (field (make-string 231)))
    (read-sequence field stream)
    (labels ((doit (pos sym going-up going-down)
               (and
                 (< 0 pos 224)
                 (find (aref field pos) " @")
                 (setf (aref field pos)
                       (cond
                         ((= 130 pos) #\@)
                         ((or
                            (unless going-down (doit (- pos 32) #\/ t no))
                            (unless going-up (doit (+ pos 34) #\\ no t))
                            (doit (+ pos (cond (going-up -32)
                                               (going-down 34)
                                               (t 1)))
                                  #\- no no))
                          sym)
                         ((return-from doit)))))))
      (doit 99 #\- no no)
      (princ field)
      nil)))

Échantillon de sortie

|   #####       --  #########  |
| ######  #    /  \  ###   # - |
|   # #  #  # /####\  #     / \|
--   -       / ##   \####  /   @
|#\ /#\  #  /    ### \ ## /    |
|##-   \ ##/     #### \ #/ #   |
|####   ---     ##### #-- ##   |

|  --#    #    #   --    #-    |
| /  \    #    #  / #\   / \   |
|/   #\   #    # /  # \ /#  \  |
-    # \  #    #/   #  - #   \ @
|    #  \ # ----    #    #    -|
|    #   \#/   #    #    #     |
|    #    -    #    #    #     |

|# #-# # # # # #-# # # # # #-# |
| #/#\# # # # #/#\# # # # #/#\#|
|#/# #\# # # #/# #\# # # #/# #\|
--# # #\# # #/# # #\# # #/# #  @
|# # # #\# #/# # # #\# #/# # # |
| # # # #\#/# # # # #\#/# # # #|
|# # # # #-# # # # # #-# # # # |
Florian Patzl
la source
2

ActionScript 3, 364 octets

Je divise cela en deux fonctions; un pour changer le tableau en un tableau de tableaux et un autre pour calculer le chemin de vol.

function m(f){for(var i=0;i<f.length;i++){f[i]=f[i].split("");}n(f,0,3,0);return f;}function n(f,x,y,m){var P=f[y][x],X=x+1,A=y-1,B=y,C=y+1,T=true,F=false,E='-';if (y<0||y>6||P=='#'||P=='|')return F;if (x==31){f[y][x]='@';return T;}if(m<0&&y>0){B=A;C=9;E='/';}else if(m>0&&y<6){A=9;B=C;E='\\';}if (n(f,X,B,0)||n(f,X,A,-1)||n(f,X,C,1)){f[y][x]=E;return T;return F;}

Version non-golfée dans un programme avec un exemple de champ astéroïde défini:

package
{
    import flash.display.Sprite;

    public class AsteroidNavigator extends Sprite
    {
        var field:Array;
        public function AsteroidNavigator()
        {
            field = [
"|   #####           #########  |",
"| ######  #          ###   #   |",
"|   # #  #  #  ####   #        |",
"@              ##    ####       ",
"|#   #   #       ###   ##      |",
"|##      ##      ####   #  #   |",
"|####           ##### #   ##   |"];
            m(field);
            printField();
        }

        function m(f){
            for(var i=0;i<f.length;i++){
                f[i]=f[i].split("");\
            }
            n(f,0,3,0);
            return f;
        }

        private function n(field,x,y,m) {
            var C = field[y][x];
            if (x > 31 || C == '#' || C == '|') {
                return false;
            }
            if (x == 31 && y == 3) {
                field[y][x] = '@';
                return true;
            }
            if (m == 0) {
                if (n(x+1, y, 0) || ((y>0) && n(x+1, y-1, -1)) || ((y<6) && n(x+1, y+1, 1))) {
                field[y][x] = '-';
                return true;
                }
            } else if ((m<0) && (y>0)) {
                if ((n(x+1, y-1, -1) || n(x+1, y-1, 0))) {
                    field[y][x] = '/';
                    return true;
                }
            } else if ((m>0) && (y<6)) {
                if ((n(x+1, y+1, 1) || n(x+1, y+1, 0))) {
                    field[y][x] = '\\';
                    return true;
                }
            }
            return false;
        }

        private function printField() {
            var sb = "";
            for each (var row:Array in field) {
                sb += row.join("") + "\n";
            }
            trace(sb);
        }
    }
}
Brian
la source