Des sceaux scientifiques échoués sur un iceberg

17

introduction

Une famille de phoques est échouée sur un iceberg dans le cercle arctique. Il y a un émetteur radio situé sur l'iceberg que les phoques peuvent utiliser pour appeler à l'aide. Cependant, seul le sceau de papa sait comment faire fonctionner l'émetteur radio. Et pire encore, la glace est très glissante à cette période de l'année, de sorte que les phoques glisseront de manière incontrôlable jusqu'à ce qu'ils heurtent un autre phoque ou glissent du bord de l'iceberg, ce qui rend très difficile pour le phoque papa d'atteindre l'émetteur radio. Heureusement, l'un des sceaux est un informaticien, alors elle décide d'écrire un programme pour comprendre comment manoeuvrer le sceau de papa vers l'émetteur radio. Comme il n'y a pas beaucoup d'espace sur la glace pour écrire un programme, elle décide de faire en sorte que le programme utilise le moins d'octets possible.

Description de l'entrée

Le programme du sceau accepte les entrées de STDIN, les arguments de ligne de commande ou les fonctions d'entrée utilisateur (comme raw_input()). Il ne peut pas être initialisé dans une variable (par exemple "Ce programme attend l'entrée dans une variable x").

La première ligne de l'entrée se compose de deux entiers séparés par des virgules sous la forme

A,B

Ce qui suit est des Blignes composées deA caractères chacune. Chaque ligne ne peut contenir que des caractères parmi les suivants:

  • .: Le froid, le froid, l'océan. La carte aura toujours ceci comme frontière.
  • #: Une partie de l'iceberg.
  • a...z : Un phoque qui n'est pas le phoque papa de l'iceberg.
  • D: Le phoque papa sur l'iceberg.
  • *: L'émetteur radio.

(Notez que le sceau de papa est toujours noté avec une majuscule D. Un minusculed est tout simplement un sceau ordinaire.)

Description de la sortie

Selon les règles suivantes concernant la façon dont les scellés peuvent se déplacer, affichez une liste d'instructions pour les scellés sur la façon dont ils doivent se déplacer pour amener le scellé papa à l'émetteur radio.

  1. Règle: tous les sceaux peuvent se déplacer vers le haut ( U), le bas ( D), la gauche ( L) et la droite ( R). Ils ne peuvent pas glisser en diagonale.
  2. Règle: En se déplaçant, un phoque continuera de se déplacer dans la même direction jusqu'à ce qu'il entre en collision avec un autre phoque ou tombe dans la mer.
    1. Si un joint entre en collision avec un autre joint, il cessera de bouger. Le sceau avec lequel il est entré en collision ne bougera pas .
    2. Si un phoque tombe dans la mer, il se noiera et disparaîtra de la carte. Autrement dit, il n'agit pas comme un collisionneur pour d'autres phoques et il ne peut plus être déplacé.
  3. Règle: Deux sceaux ne peuvent pas bouger en même temps, pas plus qu'un sceau ne peut être déplacé pendant qu'un autre est toujours en mouvement. Le sceau suivant ne peut être déplacé que lorsque le sceau précédent a cessé de bouger.
  4. Règle: Il n'y a aucune restriction concernant le déplacement d'un phoque plusieurs fois ou le nombre de phoques qui se noient.
  5. Règle: Une solution correcte aura l' extrémité du joint papa à l'émetteur radio. Le sceau de papa ne peut pas simplement passer l'émetteur en glissant.

La sortie sera composée de plusieurs lignes, chacune sous la forme

A,B

Aest le sceau de se déplacer ( Dpour le sceau papa, a... zpour les autres), et Best la direction pour déplacer le joint (soit U, D, Lou R). Notez que vous n'avez pas besoin de trouver l'itinéraire le plus court. Tout itinéraire qui obtient le sceau de papa vers l'objectif est une sortie acceptable.

Exemples d'entrées et de sorties

Contribution:

25,5
.........................
.#######################.
.####D#############*k###.
.#######################.
.........................

Production:

D,R

Contribution:

9,7
.........
.a#####b.
.#####d#.
.##l*###.
.###m#p#.
.#D#.#c#.
.........

Sortie (une sortie possible sur plusieurs):

m,R
b,L
D,U
D,R
D,D
D,L

Contribution:

26,5
..........................
.###..................###.
.l*##########v#########D#.
.###..................###.
..........................

Sortie (une sortie possible sur plusieurs):

v,D
D,L

Si vous avez d'autres questions, veuillez les poser dans les commentaires.

Absinthe
la source
Toutes les entrées auront-elles une solution valide? Sinon, quel est le résultat / comportement attendu?
Geobits
@Geobits Toutes les entrées auront une solution valide. Les entrées sans solutions sont considérées comme non valides et votre programme peut faire quoi que ce soit avec elles.
absinthe
Est-il permis de terminer le programme en lançant une exception?
DLosc
2
Que se passe-t-il si un phoque non papa frappe l'émetteur radio? Va-t-il s'arrêter ou se déplacer?
Reto Koradi
1
Cela invalide ma solution. :(
DLosc

Réponses:

6

Python 3, 520 octets

R=range
g=[list(input())for i in R(int(input().split(',')[1]))]
f=set(sum(g,[]))-set(".#*")
L=8
def P(p,g):
 if len(p)>L:return
 for s in f:
  c=sum(y.index(s)for y in g if s in y)
  if c<1:continue
  r,=[n for n in R(len(g))if s in g[n]]
  for d in R(4):
   m=p+s+",%s\n"%"LURD"[d];G=[y[:]for y in g];o="#";i,j=I,J=r,c
   while"#"==o:G[i][j]="#";G[I][J]=s;i,j=I,J;I,J=i+d%2*(d-2),j+(~d%-2&d-1);o=G[I][J]
   if"."==o:G[i][j]="#"
   if"D"==s:
    if"."==o:continue
    if"*"==o:print(m);1/0
   P(m,G)
while 1:P("",g);L+=4

Je peux faire une explication plus détaillée plus tard si les gens le souhaitent, mais en gros, cela exécute une recherche en profondeur d'abord avec un approfondissement itératif sur l'espace d'état des mouvements possibles. Si un mouvement fait tomber le sceau de papa, il est immédiatement rejeté. Si le papa se retrouve à côté de l'émetteur, la séquence de mouvements est imprimée et le programme se divise par zéro pour forcer une sortie.

Je peux faire exécuter le code beaucoup plus rapidement en ajoutant if G!=g:au début de l'avant-dernière ligne, pour 8 octets supplémentaires - cela rejette les mouvements qui ne changent rien, tels quek,L dans le premier cas de test.

Le temps d'exécution varie sensiblement d'un cycle à l'autre, même avec la même entrée, ce qui est évidemment dû au fait que je choisis le prochain sceau à déplacer en itérant sur un set , qui est un type non ordonné. J'ai chronométré le deuxième cas de test à 5 minutes 30 secondes, même si cela ne semblait pas si long la première fois que je l'ai exécuté. Avec l'optimisation mentionnée ci-dessus, cela ressemble plus à 40 secondes.

DLosc
la source
1
Fait intéressant, en Python 2, il devrait donner le même ordre à chaque fois. Je pense qu'ils ont changé Python 3 pour donner des hachages aléatoires à chaque exécution pour les mêmes objets afin d'éviter certains exploits: "La randomisation par hachage est activée par défaut. Définissez la variable d'environnement PYTHONHASHSEED sur 0 pour désactiver la randomisation par hachage. Voir aussi l'objet .__ hachage __ () méthode."
Claudiu
4

JavaScript (ES6) 322 334 323

Modifier2 Ajout d'animation dans l'extrait de

Modifier la correction de bogue, rappelez-vous la position initiale de '*', donc je le trouve même quand un sceau glisse dessus et l'efface.

Implémenté en tant que fonction avec la chaîne d'entrée en paramètre (probablement invalide mais en attente d'une clarification). Sortie via popup.
Le problème avec l'entrée de chaîne multiligne en JavaScript est queprompt ne la gère pas bien.

Quant à l'algorithme: un BFS, devrait trouver une solution optimale. Je garde une file d'attente du statut du jeu en variable l, le statut étant la grille des personnages get la séquence de mouvements jusqu'à présents . En outre, il existe un ensemble de grilles obtenues jusqu'à présent en variable k, pour éviter d'explorer la même grille encore et encore.

La boucle principale est

  • retirer un statut de jeu
  • essayez tous les mouvements possibles, mettez le statut en file d'attente après chaque mouvement valide (IIF la grille résultante n'est pas déjà présente)
  • si la solution est trouvée, quittez la boucle
F=s=>{
  o=~s.match(/\d+/),g=[...z=s.replace(/.*/,'')];
  for(l=[[g,'']],k=[];[g,s]=l.shift(),!g.some((c,p)=>
      c>'A'&&[-1,1,o,-o].some((d,j)=>{
        t=s+' '+[c,'LRUD'[j]];
        for(q=p;(u=g[q+d])<'.';)q+=d;
        return(c<'a'&z[q]=='*')||
        c>'D'|u>'.'&&!(
          f=[...g],u=='.'?0:f[q]=c,f[p]='#',
          k[h=f.map(v=>v>'D'?0:v)]||(k[h]=l.push([f,t]))
        )
      })
    ););
  alert(t)
}

Exécutez l'extrait de code pour tester dans FireFox

edc65
la source
1

C ++, 628 octets

Eh bien, cela n'a pas été très court:

#include <set>
#include <iostream>
using namespace std;struct R{string b,m;bool operator<(R r)const{return b<r.b;}};int w,h,t,j,k,z=1;char c,f;set<R> p,q;int m(R r,int x,int d,char a){for(j=x,c=r.b[x];(f=r.b[j+=d])==35;);if(c-68||f-46){r.b[x]=35;if(f-46)r.b[j-d]=c;r.m+=c;r.m+=44;r.m+=a;r.m+=10;if(c==68&j-d==t){cout<<r.m;z=0;}if(p.count(r)+q.count(r)==0){q.insert(r);}}}int main(){cin>>w>>c>>h>>c;R r;string l;for(;k++<h;){getline(cin,l);r.b+=l;}t=r.b.find(42);r.b[t]=35;q.insert(r);for(;z;){r=*q.begin();q.erase(q.begin());p.insert(r);for(k=0;z&&k<w*h;++k){if(r.b[k]>64){m(r,k,-1,76);m(r,k,1,82);m(r,k,-w,85);m(r,k,w,68);}}}}

J'ai choisi C ++ parce que je voulais utiliser les structures de données ( set, string), mais c'est intrinsèquement assez verbeux. La solution fait assez bien sur les performances, résolvant le test 2 en un peu plus de 2 secondes sur un MacBook Pro, même s'il n'est pas optimisé pour l'exécution.

Code avant de commencer à éliminer les espaces blancs et une autre réduction de longueur:

#include <set>
#include <iostream>

using namespace std;

struct R {
    string b, m;
    bool operator<(R r) const {return b < r.b; }
};

int w, h, t;
set<R> p, q;
bool z = true;

void m(R r, int k, int d, char a) {
    int j = k;
    char s = r.b[k], f;
    for (; (f = r.b[j += d]) == 35;);
    if (s - 68 || f - 46) {
        r.b[k] = 35;
        if (f - 46) {
            r.b[j - d] = s;
        }
        r.m += s;
        r.m += 44;
        r.m += a;
        r.m += 10;
        if (s == 68 && j - d == t) {
            cout << r.m;
            z = false;
        }
        if (p.count(r) + q.count(r) == 0) {
            q.insert(r);
        }
    }
}

int main() {
    char c;
    cin >> w >> c >> h >> c;
    string b, l;
    int k;
    for (k = 0; k < h; ++k) {
        getline(cin, l);
        b += l;
    }

    t = b.find(42);
    b[t] = 35;

    R r;
    r.b = b;
    q.insert(r);

    for ( ; z; ) {
        r = *q.begin();
        q.erase(q.begin());
        p.insert(r);

        for (k = 0; z && k < w * h; ++k) {
            c = r.b[k];
            if (c > 64) {
                m(r, k, -1, 76);
                m(r, k, 1, 82);
                m(r, k, -w, 85);
                m(r, k, w, 68);
            }
        }
    }

    return 0;
}

L'idée centrale derrière l'algorithme est que deux ensembles sont conservés:

  • q est l'ensemble des configurations en attente de traitement.
  • p est l'ensemble des configurations qui ont été traitées.

L'algorithme démarre avec la configuration initiale dans q. À chaque étape, une configuration est extraite de q, ajoutée à p, tous les mouvements de joint possibles sont générés et les nouvelles configurations résultantes insérées dans q.

Essai:

bash-3.2$ ./a.out <test1
D,R
bash-3.2$ time ./a.out <test2
p,U
c,U
p,R
c,L
m,L
b,L
a,L
D,U
b,L
D,R
D,D
D,L

real    0m2.267s
user    0m2.262s
sys 0m0.003s
bash-3.2$ ./a.out <test3
v,U
D,L
bash-3.2$
Reto Koradi
la source
En utilisant une file d'attente au lieu de définir pour «q», vous pouvez trouver des solutions plus courtes en moins de temps (ma solution pour le test 2 est en 6 étapes).
edc65
@ edc65 Oui, j'ai d'abord été surpris par le nombre de déménagements. Je l'ai parcouru pour confirmer que c'est une solution valable. Utiliser un FIFO qserait certainement mieux dans ce sens. La raison pour laquelle j'ai utilisé un ensemble était que je voulais éviter d'entrer plusieurs fois la même entrée. Mais j'ai commencé à réfléchir après avoir vu le résultat.
Reto Koradi
En termes de performances, vous devez utiliser une file d'attente ET un ensemble pour éviter les répétitions. Mais mettez dans l'ensemble une version modifiée de la grille, car chaque bébé phoque est interchangeable.
edc65