Supposons qu'un jour vous fouilliez dans votre grande boîte de cordons et d'adaptateurs informatiques inutilisés (USB vers USB mini, VGA vers DVI, etc.). Il y a partout des cordons emmêlés qui font tout un gâchis, et vous vous demandez si vous pourriez simplifier les choses en attachant tous les cordons ensemble dans un long brin, puis en les enroulant simplement.
La question est, est-il possible de connecter tous vos cordons et adaptateurs sur une longue ligne comme celle-ci? Ce n'est évidemment pas toujours possible, par exemple si vous n'aviez que deux cordons avec des fiches complètement différentes, ils ne pourraient pas être connectés ensemble. Mais si vous aviez un troisième cordon qui peut se connecter aux deux, vous pouvez alors lier tous vos cordons ensemble.
Vous ne vous souciez pas du type de fiches aux extrémités du brin tout cordon. Ils n'ont pas besoin de se connecter les uns aux autres pour former une boucle. Vous voulez seulement savoir si la fabrication du toron tout cordon est possible, et si c'est le cas, comment le faire.
Défi
Écrivez un programme ou une fonction qui prend une chaîne multiligne où chaque ligne représente l'un des cordons que vous possédez. Un cordon est composé d'un ou plusieurs tirets ( -
), avec une fiche à chaque extrémité. Une prise est toujours l'un des 8 caractères ()[]{}<>
.
Voici donc quelques cordons valides:
>->
(--[
}-{
<-----]
(---)
Mais ce ne sont pas:
-->
(--
)--
[{
---
Lors de la connexion des cordons, seules les fiches ayant exactement le même type de support peuvent être connectées ensemble.
Voici donc quelques connexions de cordon valides:
...---((---...
...---))---...
...---]]---...
...---{{---...
...---<<---...
Et ceux-ci ne sont pas valides:
...---()---...
...---)(---...
...---{]---...
...---{[---...
...---><---...
...--->)---...
Si tous les cordons de l'entrée peuvent être réarrangés et attachés ensemble dans un long brin, alors sortez ce brin vers la sortie standard sur une ligne (avec un retour à la ligne de fin facultatif). Lorsqu'il existe plusieurs solutions, vous pouvez choisir l'une d'entre elles pour la sortie. S'il n'est pas possible de créer un seul brin, alors ne rien produire (ou sortir une chaîne vide avec un retour à la ligne facultatif).
Par exemple, si l'entrée est
[-->
{---]
>----{
la sortie pourrait être
[-->>----{{---]
où tous les cordons sont attachés ensemble.
Cependant, si l'entrée était
[-->
{---]
les cordons ne peuvent pas être connectés, il n'y aurait donc pas de sortie.
Notez que les cordons peuvent être retournés autant de fois que nécessaire pour effectuer les connexions. par exemple [-->
et <--]
sont effectivement le même cordon car ils peuvent faire le même type de connexions. Certaines sorties peuvent dépendre du retournement des cordons d'entrée.
Par exemple
(-[
}--]
pourrait avoir une sortie
(-[[--{
où le deuxième cordon est retourné, ou
}--]]-)
où le premier cordon est retourné.
(Notez qu'en général, le retournement de la sortie entière est valide car c'est la même chose que le retournement initial de chaque cordon individuellement.)
Les longueurs des cordons dans la sortie doivent bien sûr correspondre aux longueurs des cordons d'entrée correspondants. Mais les cordons peuvent être réorganisés et retournés autant que vous le souhaitez pour faire le brin tout cordon. L'entrée contiendra toujours au moins un cordon.
Le code le plus court en octets gagne.
Cas de test
Cas avec sortie:
[-->
{---]
>----{
gives
[-->>----{{---]
or
[---}}----<<--]
(-[
}--]
gives
(-[[--{
or
}--]]-)
(-)
gives
(-)
[--{
gives
[--{
or
}--]
[-]
]-[
gives
[-]]-[
or
]-[[-]
[----->
)------------[
{--<
}---)
could give
[----->>--}}---))------------[
or
>--}}---))------------[[----->
or
}---))------------[[----->>--}
or
{--<<-----]]------------((---{
etc.
>-->
>->
>--->
could give
>-->>->>--->
or
>--->>-->>->
or
>->>-->>--->
or
<--<<---<<-<
etc.
(-]
]->
>-}
}-)
)-[
[-<
<-{
{-(
could give
(-]]->>-}}-))-[[-<<-{{-(
or
{-((-]]->>-}}-))-[[-<<-{
or
<-{{-((-]]->>-}}-))-[[->
etc.
Cas sans sortie:
[-->
{---]
[-]
[-]
(-]
]->
}-)
>->
>-->
]---]
[-------------------]
]-------------------[
[-----------------]
[-----------------]
{--[
]--}
Réponses:
Illisible , 3924 octets
C'est la première fois que j'implémente une structure semblable à une pile d'appels dans Unreadable.
(La première version de celui-ci était plus de 5300 octets, juste pour donner une idée de combien j'ai joué au golf.)
Explication
Considérez cet exemple d'entrée:
Pendant la majeure partie de l'exécution, la bande se présente comme suit:
Les cellules 0 à 5 sont des emplacements pour diverses variables.
La cellule 6 à partir de maintenant contient toutes les informations sur le jeu de câbles dans votre boîte:
Les cellules restantes après le «zéro terminateur» contiennent la pile. Chaque «stackframe» est une cellule unique qui pointe vers la première cellule d'un câble (la cellule «start plug»). Dans l'exemple ci-dessus, lorsque le programme décide qu'il a trouvé une solution, la pile contiendra 6 (se référant au
>--{
premier câble) et 21 (se référant au{---]
miroir du deuxième câble).Le programme se déroule en trois étapes principales:
La première étape (lire l'entrée et générer la structure des câbles) utilise uniquement les cellules # 1 (que j'appellerai
p
) et # 2 (que j'appelleraich
) et fonctionne dans une boucle while comme suit:En condition: incrémentez
p
de 6, lisez le caractère suivant (start plug) dans la cellule*p
et vérifiez qu'il ne l'est pas-1
(EOF).Lisez les caractères suivants
*(p+2)
et comptez-les*(p+1)
jusqu'à ce que nous rencontrions autre chose que-
(trait d'union). À ce stade,*(p+1)
contiendra le nombre de tirets (longueur du câble) et*(p+2)
le dernier caractère non-trait d'union (le bouchon d'extrémité). (Nous copions également les traits d'union dans la cellule # 5 afin que nous puissions accéder à ce code ASCII plus tard dans l'étape de sortie.)Dans une boucle while, trouvez la prise miroir et stockez-la à
*(p+3)
, puis incrémentezp
de 2 jusqu'à ce que*p
soit zéro. La boucle ressemble à ceci en pseudocode:Cette boucle effectuera toujours deux itérations (la fiche de démarrage et la fiche de fin) et stockera les résultats dans les quatrième et sixième cellules de ce câble. Maintenant, si vous avez fait attention, vous vous rendez compte que la sixième cellule est en effet l'emplacement correct pour la fiche d'extrémité en miroir, mais la fiche de démarrage en miroir se trouve dans la cellule intitulée "booléen indiquant le câble d'origine". C'est OK car nous avons seulement besoin que cette cellule soit une valeur non nulle.
Puisqu'il
p
vient d'être incrémenté d'un total de 4, il pointe maintenant vers la cellule intitulée «le câble booléen indiquant que le câble est en cours d'utilisation». Définissez*(p+3)
la valeur de*(p-1)
. Cela place la prise de démarrage en miroir au bon endroit.Lisez (et jetez) un caractère de plus (qui devrait être une nouvelle ligne, mais le programme ne vérifie pas cela).
p
commence initialement à 0 mais est incrémenté de 6 à l'intérieur de la condition while, ainsi les données du câble commencent à la cellule # 6.p
est incrémenté de 4 à l'intérieur du corps de la boucle, et donc un total de 10 pour chaque câble, ce qui est exactement ce dont nous avons besoin.Au cours de la deuxième étape, les cellules # 0-4 sont occupés par des variables que je vais appeler
a
,p
,q
,m
etnotdone
. (La cellule n ° 5 se souvient toujours du code ASCII du trait d'union.)Pour se préparer à l'étape 2, nous devons
*p
remettre à 0 (la cellule intitulée «terminaison zéro») afin qu'elle puisse agir comme terminateur pour la liste des câbles; nous définissons égalementq
(qui est notre pointeur de pile) lap+1
(c'est- à -dire la cellule après le «zéro terminateur»; c'est là que la pile commence);*q
à 1 (le premier objet de la pile; pourquoi 1 deviendra apparent plus tard); etnotdone
à 1. Tout cela se fait en une seule déclaration:La deuxième étape est également une boucle while. Son état est simplement
notdone
. À chaque itération de cette boucle while, l'une des quatre choses suivantes peut se produire:*q
à un autre câble éligible (que nous marquons rapidement comme «en cours d'utilisation» avec son jumeau), puis recurse (c'est-à-dire créer un nouveau stackframe).*q
car il n'y a plus de câble éligible, nous devons donc revenir en arrière (supprimer un stackframe et marquer le câble précédent et son jumeau comme n'étant plus «utilisé»).*q
car aucun autre câble éligible n'existe et nous ne pouvons pas revenir en arrière car nous avons atteint le bas de la pile. Cela signifie qu'il n'y a pas de solution.Le corps de la boucle vérifie chacune de ces quatre conditions dans cet ordre. Voici les détails:
Réglez
m
etp
sur 1 et dans une boucle while, incrémentezp
de 5 (itérant ainsi à travers les câbles) et vérifiez si*(p+4)
(«en cours d'utilisation») est défini. Si ce n'est pas le cas, définissez-lem
sur 0. À la fin de cette boucle,m
nous indique si tous les câbles sont utilisés. Si tel est le cas, définissez-lenotdone
sur 0 pour terminer la boucle principale. Sinon, passez à l'étape 2 ci-dessous.Réglez
p
sur*q
(le câble en haut de la pile) et dans une boucle de temps similaire à celle ci-dessus, incrémentezp
de 5 pour parcourir les câbles. Commencer par*q
garantit que nous ne considérons que ceux que nous n'avons pas déjà pris en compte auparavant; cependant, n'oubliez pas que la valeur initiale d'un nouveau stackframe est 1, donc le premier câble examiné est celui de la cellule 6, qui est en effet le premier câble.Pour chaque câble, nous devons vérifier
*(p+4)
qu'il n'est pas déjà utilisé, et aussi que soit*(q-1)
zéro (ce qui signifie que nous sommes au bas de la pile, donc il n'y a pas de contrainte sur la prise de démarrage), ou*p
(le début du câble fiche) est égal à*(*(q-1)+2)
(la fiche d'extrémité du câble juste en dessous sur la pile). Nous vérifions l'égalité en définissanta
to*(*(q-1)+2)
etm
to*p+1
puis en décrémentant les deux dans une boucle while. Le+1
ism
est décrémenté à l'intérieur de la condition while, il est donc décrémenté une fois de plusa
. Sia
est nul à la fin de cela, les deux fiches sont égales.Ainsi, si l'un
*(q-1)
était égal à zéro ou la comparaison d'égalité réussie, le câble est éligible. Réglez*q
pourp
remplacer le câble en haut de la pile par le nouveau; réglém
sur le même pour indiquer que nous avons trouvé un câble correspondant; puis décrémenterp
. Cette décrémentation est une petite astuce pour provoquer la fin de la boucle while (itération à travers les câbles); il augmenterap
à nouveau de 5, l'amenant ainsi à la cellule contenant l'indicateur «in use» de ce câble, et nous savons que c'est zéro parce que nous venons de le vérifier. Enfin, après la boucle itérative du câble, nous vérifions si ellem
est non nulle. Si tel est le cas, nous avons trouvé un câble correspondant etp
pointons l'indicateur «en cours d'utilisation» pour ce câble correspondant. Réglez-le sur 1 pour le marquer comme utilisé. Définir également*(*(p-1) ? p+5 : p-5)
à 1 pour marquer son jumeau comme en cours d'utilisation. Enfin, incrémentezq
et définissez le nouveau*q
sur 1 pour créer un nouveau stackframe.Si, après la boucle itérative du câble, nous trouvons
m
zéro, il n'y a plus de câbles correspondants, nous devons donc revenir en arrière. Décrémenterq
pour descendre la pile et vérifier si elle pointe toujours vers un câble (une valeur non nulle). Si c'est le cas, marquez ce câble et son jumeau comme n'étant plus utilisé. (Nous conservons la valeur*q
enp
pour rendre cette expression plus courte dans le code.)Si, après décrémentation
q
, nous constatons qu'il pointe vers une valeur nulle, alors c'est le «terminateur zéro», ce qui signifie que nous avons dépassé la pile. Nous concluons qu'il n'y a pas de solution. Nous avons misnotdone
à 0 pour terminer la boucle principale.Le troisième étage est l'étage de sortie. Deux choses peuvent se produire:
Commodément, s'il n'y avait pas de solution,
p
est zéro parce que nous l'avons mis à la valeur de*q
avant de vérifier cela pour zéro; et s'il y avait une solution,p
pointe le «terminateur zéro» parce qu'il vient d'itérer à travers les câbles, nous pouvons donc maintenant utiliserp
pour itérer à travers la pile. Il suffit donc d'itérer dans la pile, de sortir pour chaque câble la prise de départ (*(*p)
), les tirets (en décrémentant*(*p+1)
dans une boucle while; et en utilisant le code ASCII de trait d'union stocké dans la cellule # 5), et la prise de fin (*(*p+2)
). Peu importe que cela détruise les informations de longueur de câble; nous n'en avons plus besoin.la source
CJam, 67
Essayez-le en ligne
Remarque: le lien utilise le dernier code du référentiel (poussé mais pas encore publié), car il contient un correctif de bogue.
Explication:
Le programme essaie simplement toutes les permutations et toutes les orientations des cordes.
la source
(-] ]-> >-} }-) )-[ [-< <-{ {-(
.JavaScript (ES6), 206
Fonction récursive
Plus lisible
Tester
la source
Javascript, 800 octets
Loin d'une solution optimisée, mais voici un hack rapide ensemble en javascript (pas d'ecma5 sophistiqué ou quoi que ce soit, car je ne le sais pas).
Ungolfed, le voici ... Je suis sûr qu'au moins 2 boucles sont inutiles ici et que la vérification d'une entrée d'élément unique en haut et d'une correspondance d'élément unique en bas est stanky ... mais cela semble fonctionner et traite les entrées de test.
la source
s.charAt(x)
===s[x]
Python 3, 217 octets
( Démo sur Ideone )
la source
(-] ]-> >-} }-) )-[ [-< <-{ {-(
?Lua, 477 octets
Accepte les cordons comme arguments de ligne de commande
la source
Python 3.5,
448432427424286311 octets:( +25 car il y avait un bug où la sortie peut être plus longue qu'elle ne devrait l'être pour certaines entrées )
Fonctionne parfaitement!
sauf pour les entrées de 7 valeurs ou plus. Cela prend beaucoup de temps pour ceux-ci, probablement parce qu'il doit passer par toutes ces permutations de l'entrée plus l'entrée inversée . J'essaierai de résoudre ce problème si et quand je le peux, mais pour l'instant, cela semble suffisant.Tout va bien maintenant! Si seulement je pouvais en quelque sorte utiliser cetry-except
bloc dans la compréhension de la liste, il pourrait être un peu plus court et beaucoup plus joli. Néanmoins, il fonctionne maintenant pour tous les cas de test et, surtout, il n'utilise aucune importation! :)Essayez-le en ligne! (Ideone) (284 octets ici)
(Astuce: Pour l'essayer, sélectionnez simplement "fork", puis entrez vos choix, séparés par des espaces , et sélectionnez "exécuter")
Explication
Fondamentalement, ce qui se passe est ...
B
est créée à partir de l'entrée en la divisant au niveau de l'espace en ses "cordons".M
est une chaîne que j'ai créée qui, lorsqu'elle est évaluée, renvoie une liste basée surB
laquelle contient tous les cordons, mais cette fois en arrière .M
est finalement concaténée avecB
elle-même pour créer une listef
, avec toutes les orientations possibles des "cordons".d
est créée, qui sera initialisée avec la première valeur (valeurf[0]
) def
.d
sont itérées, et le dernier caractère de chaque valeur est comparé au premier caractère de chaque élément dansf
, et lorsqu'une correspondance est trouvée, ce caractère est sauté (ou supprimé) et renvoyé de la listef
. Cela se produit jusqu'à ce que aIndexError
soit augmenté, ou que la longueur de la listed
dépasseB
et que aNameError
soit déclenché après l'appel àE
, les deux étant traités, puisd
le contenu de la liste est joint dans une chaîne et renvoyé tant que la longueur de la listed
est supérieure. supérieur ou égal à la longueur de la listeB
. Sinon, une chaîne vide est retournée (''
), card
n'étant pas de la même longueur queB
signifie que tous les "cordons" de la listeB
ne peut pas être réuni en un long "cordon".la source
<!-- language: lang-python -->
. Qu'est-ce que cela change?