FizzBuzz Reverse Solver

32

Synopsis: Étant donné la sortie d'un programme FizzBuzz généralisé, retournez la liste des facteurs et des mots utilisés pour le programme.

Description du défi

Imaginez un programme FizzBuzz généralisé qui prend en entrée une liste de facteurs et de mots à utiliser et le nombre à partir duquel commencer. Par exemple, si l'entrée de ce programme était

3 2,Ninja 5,Bear 7,Monkey

Le programme imprimerait les nombres de 3à 100, en remplaçant les nombres divisibles par 2avec Ninja, les nombres divisibles par 5avec Bearet les nombres divisibles par 7avec Monkey. Pour les nombres qui sont divisibles puis plus d'un de ces termes, le programme concaténera les mots, en imprimant des choses comme NinjaBearou BearMonkeyou NinjaMonkeyou NinjaBearMonkey. Voici la sortie de cette entrée:

3
Ninja
Bear
Ninja
Monkey
Ninja
9
NinjaBear
11
Ninja
13
NinjaMonkey
Bear
Ninja
17
Ninja
19
NinjaBear
Monkey
Ninja
23
Ninja
Bear
Ninja
27
NinjaMonkey
29
NinjaBear
31
Ninja
33
Ninja
BearMonkey
Ninja
37
Ninja
39
NinjaBear
41
NinjaMonkey
43
Ninja
Bear
Ninja
47
Ninja
Monkey
NinjaBear
51
Ninja
53
Ninja
Bear
NinjaMonkey
57
Ninja
59
NinjaBear
61
Ninja
Monkey
Ninja
Bear
Ninja
67
Ninja
69
NinjaBearMonkey
71
Ninja
73
Ninja
Bear
Ninja
Monkey
Ninja
79
NinjaBear
81
Ninja
83
NinjaMonkey
Bear
Ninja
87
Ninja
89
NinjaBear
Monkey
Ninja
93
Ninja
Bear
Ninja
97
NinjaMonkey
99
NinjaBear

Notez que chaque fois que le programme doit combiner des mots, il passe toujours du nombre le plus bas au nombre le plus élevé . Il n'imprimera donc pas quelque chose comme MonkeyBear(puisque Monkey est un nombre plus élevé que Bear).

Votre programme doit accepter la sortie du programme FizzBuzz généralisé en entrée et produire l' entrée donnée au programme FizzBuzz généralisé. En d'autres termes, écrivez un "programme inversé" pour le programme FizzBuzz généralisé. Par exemple, étant donné le bloc de code ci-dessus en entrée, votre programme devrait sortir 3 2,Ninja 5,Bear, 7,Monkey.

Il y a quelques règles que les mots suivront toujours:

  • Il sera toujours possible de dire exactement quels sont les facteurs et les mots de l'entrée.
  • Chaque mot commencera par une majuscule et ne contiendra aucune autre majuscule ou chiffre.
  • Chaque facteur est unique.

Exemples d'entrées et de sorties

Contribution:

Calvins
7
Hobbies
9
10
11
Calvins
13
14
15
Hobbies
17
Calvins
19
20
21
22
23
CalvinsHobbies
25
26
27
28
29
Calvins
31
Hobbies
33
34
35
Calvins
37
38
39
Hobbies
41
Calvins
43
44
45
46
47
CalvinsHobbies
49
50
51
52
53
Calvins
55
Hobbies
57
58
59
Calvins
61
62
63
Hobbies
65
Calvins
67
68
69
70
71
CalvinsHobbies
73
74
75
76
77
Calvins
79
Hobbies
81
82
83
Calvins
85
86
87
Hobbies
89
Calvins
91
92
93
94
95
CalvinsHobbies
97
98
99
100

Sortie:

6 6,Calvins 8,Hobbies

Contribution:

FryEggman
7
Am
Fry
The
11
FryAmEggman
13
14
FryThe
Am
17
FryEggman
19
AmThe
Fry
22
23
FryAmEggman
The
26
Fry
Am
29
FryTheEggman
31
Am
Fry
34
The
FryAmEggman
37
38
Fry
AmThe
41
FryEggman
43
Am
FryThe
46
47
FryAmEggman
49
The
Fry
Am
53
FryEggman
The
Am
Fry
58
59
FryAmTheEggman
61
62
Fry
Am
The
FryEggman
67
Am
Fry
The
71
FryAmEggman
73
74
FryThe
Am
77
FryEggman
79
AmThe
Fry
82
83
FryAmEggman
The
86
Fry
Am
89
FryTheEggman
91
Am
Fry
94
The
FryAmEggman
97
98
Fry
AmThe

Sortie:

6 3,Fry 4,Am 5,The 6,Eggman

Contribution:

DeliciousTartApplePie
DeliciousCreamPancakeStrawberry
DeliciousProfiterole
DeliciousCream
DeliciousPancake
DeliciousCreamStrawberryTart

Sortie:

95 1,Delicious 2,Cream 3,Pancake 4,Strawberry 5,Tart 19,Apple 95,Pie 97,Profiterole

Vous pouvez obtenir le code que j'ai utilisé pour générer les entrées ici .

Absinthe
la source
La liste monte-t-elle toujours exactement à 100?
Dennis
@Dennis Oui, la limite supérieure est toujours de 100.
absinthe
15
C'est juste un honneur d'être dans l'un de vos exemples.
NinjaBearMonkey
Ceci est une bien meilleure version de votre défi que ce qui était à l'origine dans le bac à sable :)
Beta Decay
1
@NinjaBearMonkey Je suppose que choisir des noms contenant de nombreux mots nous a fait de meilleurs exemples. Merci de m'avoir inclus aussi @Pyrrha! :)
FryAmTheEggman

Réponses:

10

Pyth, 73 octets

jd+J-101lK.zjL\,Sm,_-F>2+_Jf}d@KTUKd{smtcdf-@dTGUdf>T\:K

C'était certainement difficile. Je pense que j'ai couvert tous les cas marginaux, y compris tout dans l'exemple de @ MartinBüttner et l'exemple sans facteurs de répétition.

NinjaBearMonkey , Deliciousness

Au niveau élevé, le programme trouve d'abord tous les mots en coupant les chaînes alphabétiques en majuscules.

Ensuite, les lignes sont mappées pour indiquer si chaque chaîne apparaît ou non dans la ligne, et chaque facteur possible est testé pour voir s'il produit le même ordre. Si c'est le cas, le facteur est ajouté à une liste globale, qui vérifie si le facteur était déjà présent. S'il n'était pas déjà présent, le facteur est utilisé. Les chaînes sont triées par première apparition dans l'entrée, ce qui a pour effet de lever l'ordre des chaînes qui n'apparaissent chacune qu'une fois dans la même ligne.

Après cela, c'est juste le formatage et l'impression.

isaacg
la source
5

Scala, 350 caractères

(s:String)⇒{def g(a:Int,b:Int):Int=if(b==0)a.abs else g(b,a%b);val(j,q)=(s.lines:\100→Map.empty[String,Int]){case(l,(n,m))⇒if(l(0).isDigit)(n-1,m)else(n-1,m++(Seq(Seq(l(0)))/:l.tail){case(x,c)⇒if(c.isUpper)Seq(c)+:x else (x(0):+c)+:x.tail}.map{t⇒val w=t.mkString;w→g(m.getOrElse(w,n),n)})};s"${j+1}"+q.map{case(k,v)=>s" $v,$k"}.toSeq.sorted.mkString}

pas gagnant ... mais belle question.

résultats testés:

scala> (s:String)⇒{def g(a:Int,b:Int):Int=if(b==0)a.abs else g(b,a%b);val(j,q)=(s.lines:\100→Map.empty[String,Int]){case(l,(n,m))⇒if(l(0).isDigit)(n-1,m)else(n-1,m++(Seq(Seq(l(0)))/:l.tail){case(x,c)⇒if(c.isUpper)Seq(c)+:x else (x(0):+c)+:x.tail}.map{t⇒val w=t.mkString;w→g(m.getOrElse(w,n),n)})};s"${j+1}"+q.map{case(k,v)=>s" $v,$k"}.toSeq.sorted.mkString}
res0: String => String = <function1>

scala> res0("""DeliciousTartApplePie
     | DeliciousCreamPancakeStrawberry
     | DeliciousProfiterole
     | DeliciousCream
     | DeliciousPancake
     | DeliciousCreamStrawberryTart""")
res1: String = 95 1,Delicious 2,Cream 3,Pancake 4,Strawberry 5,Tart 95,Apple 95,Pie 97,Profiterole

scala> res0("""FryEggman
     | 7
     | Am
     | Fry
     | The
     | 11
     | FryAmEggman
     | 13
     | 14
     | FryThe
     | Am
     | 17
     | FryEggman
     | 19
     | AmThe
     | Fry
     | 22
     | 23
     | FryAmEggman
     | The
     | 26
     | Fry
     | Am
     | 29
     | FryTheEggman
     | 31
     | Am
     | Fry
     | 34
     | The
     | FryAmEggman
     | 37
     | 38
     | Fry
     | AmThe
     | 41
     | FryEggman
     | 43
     | Am
     | FryThe
     | 46
     | 47
     | FryAmEggman
     | 49
     | The
     | Fry
     | Am
     | 53
     | FryEggman
     | The
     | Am
     | Fry
     | 58
     | 59
     | FryAmTheEggman
     | 61
     | 62
     | Fry
     | Am
     | The
     | FryEggman
     | 67
     | Am
     | Fry
     | The
     | 71
     | FryAmEggman
     | 73
     | 74
     | FryThe
     | Am
     | 77
     | FryEggman
     | 79
     | AmThe
     | Fry
     | 82
     | 83
     | FryAmEggman
     | The
     | 86
     | Fry
     | Am
     | 89
     | FryTheEggman
     | 91
     | Am
     | Fry
     | 94
     | The
     | FryAmEggman
     | 97
     | 98
     | Fry
     | AmThe""")
res2: String = 6 3,Fry 4,Am 5,The 6,Eggman
Gil Hoch
la source
4

Python 2, 366 340 331 octets

Ce programme reçoit une entrée via stdin.

Nouvelle approche:

Calculez le facteur des mots d'une seule occurrence par la distance à partir de la fin de la ligne. Par exemple ( à partir du dernier échantillon): DeliciousTartApplePiePie est calculate comme: [95,19,5,1][0]et Apple est: [95,19,5,1][1].

import sys
import re
d=[(i,re.findall('[A-Z][a-z]*',l)[::-1])for i,l in enumerate(sys.stdin)]
e=101-len(d)
print e," ".join(`x`+','+`y`[1:-1]for x,y in sorted({next((j-i for j,t in d if j>i and w in t),[x for x in range(i+e,0,-1)if(i+e)%x==0][d[i][1].index(w)]):w for w,i in{w:i for i,l in d[::-1]for w in l}.items()}.iteritems()))

Ancienne approche:

import sys
import re
l=[(i,re.findall('[A-Z][a-z]*',l))for i,l in enumerate(sys.stdin)]
e=101-len(l)
d={}
for i,s in l:
 for w in s[::-1]:
  if w not in d.values():
   d[next((j-i for j,t in l[i+1:]if w in t),next(m for m in range(i+e,0,-1)if(i+e)%m==0and m not in d))]=w 
print e," ".join(`x`+','+`y`[1:-1]for x,y in sorted(d.iteritems()))

Usage:

python FizzBuzzReverseSolver.py < Sample1.txt

Explication (de l'ancienne approche):

  • En général, le programme crée une liste de numéros de ligne et une liste de mots (par exemple [(0, []), (1, ['Ninja']), (2, ['Bear']), ...].
  • Pour chaque mot de chaque ligne (à partir de la fin de la ligne):
    • Recherchez l'occurrence suivante du mot et insérez la différence et le mot dans un dictionnaire prédéfini.
    • S'il ne le trouve pas, insérez le plus grand facteur du numéro de ligne (y compris lui-même) qui n'existe pas déjà dans le dictionnaire et le mot dans le dictionnaire.
TheCrypt
la source