Combien de guinées en un brut de trois ans?


32

Jusqu'à la décimalisation en 1971 , la monnaie britannique était basée sur la division de la livre en 240 sous. Un shilling était de 12 sous, donc 20 shillings ont fait une livre. La plus petite dénomination était la portion d'un quart de sou. Il y avait beaucoup d'autres dénominations et surnoms pour les pièces, ce qui peut devenir assez déroutant si vous n'êtes pas habitué au système.

Défi

Écrivez un programme ou une fonction qui peut convertir (presque) toute dénomination de vieil argent anglais en une autre. Pour faciliter la tâche de l'utilisateur, vous devez prendre en charge les pluriels et les surnoms.

Ce sont les dénominations et leurs termes synonymes que vous devez prendre en charge. Pour plus de commodité, leur valeur en farthings mène chaque ligne.

1: farthing, farthings
2: halfpence, halfpenny, halfpennies
4: penny, pennies, pence, copper, coppers
8: twopenny, twopennies, twopence, tuppence, half groat, half groats
12: threepence, threepenny, threepennies, threepenny bit, threepenny bits, thruppence, thrupenny, thrupennies, thrupenny bit, thrupenny bits
16: groat, groats
24: sixpence, sixpenny, sixpennies, sixpenny bit, sixpenny bits, tanner, tanners
48: shilling, shillings, bob
96: florin, florins, two bob bit, two bob bits
120: half crown, half crowns
240: crown, crowns
480: half sovereign, half sovereigns
504: half guinea, half guineas
960: pound, pounds, pounds sterling, sovereign, sovereigns, quid, quids
1008: guinea, guineas

(Je ne suis pas britannique, cette liste ne fait nullement autorité mais elle suffira pour le défi.)

Via stdin ou argument de fonction, vous devez prendre une chaîne de la forme

[value to convert] [denomination 1] in [denomination 2]

et retourner ou imprimer

[value to convert] [denomination 1] is [converted value] [denomination 2]

[converted value]sont les [value to convert]unités de la dénomination 1 converties en dénomination 2.

Les [value to convert]et [converted value]sont des flotteurs positifs. Dans la sortie, les deux doivent être arrondis ou tronqués à 4 décimales. Si vous le souhaitez, vous pouvez supposer qu'il a [value to convert]toujours un point décimal et zéro lors de la saisie (par exemple 1.0au lieu de 1).

Les dénominations 1 et 2 peuvent être deux termes quelconques de la liste ci-dessus. Ne vous inquiétez pas s'ils sont pluriels ou non, traitez toutes les dénominations et synonymes de la même manière. Vous pouvez supposer que le format d'entrée et les dénominations sont toujours valides.

Exemples

1 pounds in shilling1 pounds is 20 shilling
(ce 1.0000 pounds is 20.0000 shillingserait bien)

0.6 tuppence in tanner0.6 tuppence is 0.2 tanner

24 two bob bits in pounds sterling24 two bob bits is 2.4 pounds sterling

144 threepennies in guineas144 threepennies is 1.7143 guineas

Notation

Le code le plus court en octets gagne.


1
"pennies" n'est utilisé que pour désigner un certain nombre de pièces, pas une somme d'argent.
David Richerby

4
Nit-pick: Post décimalisation, le pluriel de quidest quid. Cela aurait probablement été le même avec l'ancien argent. Exemple: Five quid a pint! Cor blimey guvnor. Exception: quids-in
Digital Trauma

7
Je gâcherais probablement beaucoup de gens pour leur demander d'inclure "ha'penny".
kaine

3
Je n'ai jamais entendu un ha'penny appeler autre chose qu'un ha'penny, @kaine. Comme dans en.wikipedia.org/wiki/Ha%27penny_Bridge . Bien sûr, je suis trop jeune moi-même pour l'avoir entendu trop souvent dans le discours, mais l'apostrophe semble standard par écrit.
TRiG

Réponses:


9

Pyth , 146 145

K4J24L?*y>b-5>b\t?2>b\t.5}<b2"hatw"@[1K8K12K16J48J1008*JT96*2J960)xc"fapetucothengrsishtagucrflbo"2<b2AGHcz" in"++G%" is %0.4f"*vhcGdcyjdtcGdytHH

Plus lisible (les sauts de ligne et les retraits doivent être supprimés pour fonctionner):

K4J24
L?*y>b-5>b\t?2>b\t.5
  }<b2"hatw"
  @[1K8K12K16J48J1008*JT96*2J960)
   xc"fapetucothengrsishtagucrflbo"2<b2
AGHcz" in"
++G
  %" is %0.4f"
   *vhcGdcyjdtcGdytH
 H

Mise à jour: Il s'avère que c'est un caractère plus court (pas d'espace nécessaire) pour découper la chaîne en une liste de 2 chaînes de caractères avant d'exécuter l'opération d'indexation de chaîne. /x"string"<b2 2-> xc"string"2<b2. Rien d'autre ne doit être changé.

Comment ça marche:

  • Cela utilise l'approche de @ xnor consistant à rechercher la valeur de la devise en utilisant ses deux premières lettres, ainsi que l'astuce de détection de l'initiale halfou two, de la supprimer et d'appeler à nouveau la fonction.

  • Pour rechercher la valeur des deux premiers caractères, il trouve l'emplacement des deux premières lettres de la devise dans une chaîne, puis divise par 2 et prend la valeur à cet index dans la liste. C'est beaucoup plus court qu'un dict en pyth.

  • Utilise le fait que x(find within string) renvoie -1 en cas d'échec pour éviter de mettre po(livres) qu(quid) ou so(souverains) dans la chaîne, et renvoie simplement le dernier élément de la liste, 960, par défaut.

  • En réorganisant l'ordre des devises dans le système de recherche et en l'initialisant soigneusement, avec K4et J24, tous les espaces qui auraient été nécessaires pour séparer les nombres dans la liste ont été supprimés.

  • Utilise l'opérateur d'affectation double de pyth,, Asur la division d'entrée inpour obtenir le début et la fin de l'entrée dans des variables distinctes.

  • Fait essentiellement la même recherche à la fin, bien que pyth n'en ait pas .split(_,1), il est donc un peu plus lourd.

Exemples:

$ pyth programs/currency.pyth <<< '5 florins in half guineas'
5 florins is 0.9524 half guineas

$ pyth programs/currency.pyth <<< '0.4 quid in sixpenny bits'
0.4 quid is 16.0000 sixpenny bits

3
J'abandonne ...;)
Martin Ender

Je ne savais pas <et >travaillais en tant qu'opérateurs de tranche de chaîne / liste; c'est beaucoup, beaucoup mieux que de prendre la tête ou la fin d'une côtelette :)
FryAmTheEggman

@FryAmTheEggman On dirait que cela manquait également dans la documentation - je l'ai ajouté.
isaacg

Je devrais probablement lire macros.py plus attentivement :)
FryAmTheEggman

14

Rubis, 345 306 302 288 287 278 273 253 252 242 232 221 202 190 octets

f=->s{" !#+/7OďǿȗϟЏ'"[%w{fa fp ^pe|co r..p ^gr x|ta sh|^b fl|b f.c ^c f.s .gu d|v ^g .}.index{|k|s[/#{k}/]}].ord-31}
$><<gets.sub(/ (.+ i)n /){" #{r=$1}s %0.4f ".%$`.to_f/f[$']*f[r]}

Prend l'entrée de STDIN et imprime vers STDOUT.

J'utilise des expressions régulières courtes pour ne faire correspondre que les dénominations souhaitées pour chaque valeur. Il existe deux tableaux, un avec des expressions rationnelles et un avec des valeurs, aux indices correspondants. Le tableau d'expressions régulières est un littéral de tableau délimité par des espaces et le tableau de valeurs est compressé dans une chaîne de caractères UTF-8.

Je sélectionne l'index dans les valeurs en recherchant une expression régulière qui correspond à chaque dénomination. Je prends également par défaut le cas de tuppence / half-groat (valeur 8), car cela nécessitait la plus longue expression régulière. De même, certains des modèles supposent que d'autres valeurs ont déjà été mises en correspondance avec des modèles antérieurs, de sorte que chaque expression régulière ne distingue que la valeur souhaitée uniquement des autres. En utilisant cela, je pourrais probablement raser un autre couple d'octets en réorganisant l'ordre des dénominations.

Merci à Ventero de m'avoir aidé à battre Pyth pour le raccourcir!


1
C'est la correspondance regex ( s[k]) qui écrase $1etc. Vous pouvez enregistrer quelques caractères en déplaçant le bloc de carte dans un lambda et en l'appelant directement dans la dernière ligne (ce qui vous permet également de supprimer les affectations pour $1et $2). Est également .indexplus court que .find_index.
Ventero

@Ventero Ah, c'est logique. Merci!
Martin Ender

1
Regexp.new k/#{k}/et $><<gets.sub(/foo/){a=$3;...}gets[/foo/];a=$3;puts...pour un total de 221. Et vous pouvez bien sûr utiliser l'ancienne astuce consistant à compresser le tableau int dans une chaîne (à l'aide .pack("U*")) puis à l'indexer dans cette chaîne. Cela devrait vous faire descendre à 195 caractères / 200 octets.
Ventero

Encore mieux:a=gets[/foo/,3]
Ventero

@Ventero Merci beaucoup. Je me suis retrouvé avec 196/202, car j'ai ajouté un décalage aux codes de caractères pour éviter ASCII non imprimable. Toujours plus court que Pyth. ;)
Martin Ender

8

Python 3: 264 239 caractères

f=lambda c:c[:2]in"hatw"and f(c[5-(c>'t'):])*2/4**(c<'t')or[1,4,4,4,8,12,16,24,24,48,48,96,240,1008,960]['fapecoentuthgrsitashboflcrgu'.find(c[:2])//2]
a,b=input().split(" in ")
x,c=a.split(" ",1)
print(a,"is %0.4f"%(eval(x)*f(c)/f(b)),b)

La fonction fobtient la valeur en shilling de la chaîne monétaire cen empreinte digitale les deux premières lettres à l'aide du dictionnaire en les trouvant dans une chaîne. Les préfixes "moitié" et "deux" sont détectés et pris en compte en coupant le préfixe et l'espace et en appliquant un multiplicateur. Comme "halfpenny" manque d'espace après "half", cela se traduit par "enny", mais cela est géré avec une entrée fictive "en".

Merci à @isaacg et @grc pour de nombreuses améliorations dans la recherche du dictionnaire.


Je savais que cela pouvait être fait :) Je suis aussi extrêmement gêné de ne pas savoir que vous pourriez définir un dictionnaire comme ça ...: S
FryAmTheEggman

2
@FryAmTheEggman Je ne savais pas que vous pouviez définir des dictionnaires via des mots clés non plus jusqu'à ce que je le voie utilisé dans une réponse sur ce site. Les choses que vous apprenez à jouer au golf ...
xnor

J'en ai fait une version Pyth et j'ai obtenu 207 caractères. Préférez-vous que je le poste ici pour que vous puissiez l'ajouter ou publier une réponse wiki communautaire?
FryAmTheEggman

1
+1 pour cette 2/4**(c<'t')partie.
njzk2

1
Vous pouvez enregistrer 13 caractères en utilisant .get(c[:2],960)pour rechercher la valeur dans le dictionnaire et en omettant les po=960,so=960,qu=960,entrées du dictionnaire.
isaacg

5

Python 2 - 345 358

s=str.startswith
h='half'
u,v=raw_input().split(' in ')
a,b=u.split(' ',1)
C=dict(fa=1,pe=4,twop=8,tu=8,thr=12,gr=16,si=24,ta=24,sh=48,b=48,fl=96,c=240,po=960,so=960,q=960,gu=1008)
C.update({h+'p':2,h+' gr':8,'two ':96,h+' c':120,h+' s':480,h+' gu':504})
for c in iter(C):
 if s(b,c):k=C[c]
 if s(v,c):f=C[c]
print u+' is %0.4f '%(eval(a)*k/f)+v

Nécessite que le numéro d'entrée soit un flottant en python, c'est-à-dire 144.1

Je pense que cela pourrait être raccourci en python 3 ...

... Confirmé grâce à @xnor. A également confirmé qu'avoir un meilleur algorithme est très important;)


Je remplacerais q=raw_input().split(' in ')parq,b=raw_input().split(' in ')
njzk2

@ njzk2 C'est vrai ... J'ai aussi utilisé cela pour la ligne suivante, maintenant :)
FryAmTheEggman

Je pense qu'il y a un conflit entre h+' gr':8et h+' g':504selon qui est évalué en premier pour les demi-gruaux
njzk2

@ njzk2 c'est vrai ... ajouté uà celui de la Guinée ...
FryAmTheEggman

2

Haskell - 315 octets

w x=f(u x)*v(u x)
f=maybe 1 id.l"ha tw tu th si"[0.5,2,2,3,6]
v x@(_:xs)|Just w<-l"bo cr gr gu so co fa fl pe po qu sh ta"[12,60,4,252,240,1,0.25,24,1,240,240,12,6]x=w|True=v xs
l k v x=take 2 x`lookup`zip(words k)v
u=unwords
i s|(n:x,_:t)<-span(/="in")$words s=u$n:x++["is",show$read n*w x/w t]++t
main=interact i

2

JavaScript (ES5), 344

I=prompt()
n=I.match(/[\d.]+ /)[0]
A=I.slice(n.length).split(" in ")
function m(x){return{fi:1,he:2,p:4,pe:4,cr:4,tn:8,hg:8,tp:12,te:12,g:16,gs:16,sn:24,tr:24,si:48,b:48,fn:96,to:96,hc:120,c:240,cs:240,hs:480,hgtrue:504,ps:960,se:960,q:960,ga:1008}[x[0]+(x[5]||"")+(x[10]=="a"||"")]}
alert(n+A[0]+" is "+(n*m(A[0])/m(A[1])).toFixed(4)+" "+A[1])

Je suis allé avec une approche de fonction de hachage ... Je pense que j'ai sous-estimé (relativement) la complexité du traitement d'entrée (par rapport à l'approche regex, peu importe le nombre).


1

Basé sur la réponse de @ FryAmTheEggMan, avec une manière différente de tester str.startwith:

Python 2: 317

h='half'
C=dict(fa=1,pe=4,twop=8,tu=8,thr=12,gr=16,si=24,ta=24,sh=48,b=48,fl=96,c=240,po=960,so=960,q=960,gu=1008)
C.update({h+'p':2,h+' gr':8,'two ':96,h+' c':120,h+' s':480,h+' gu':504})
u,v=raw_input().split(' in ')
a,b=u.split(' ',1)
s=lambda x:x and C.get(x, s(x[:-1]))
print u+' is %0.4f '%(eval(a)*s(b)/s(v))+v

Je pense que vous devez ajouter un espace de fin à la printchaîne formatée et. Vous pouvez également réécrire le lambda s=lambda x:x and C.get(x,s(x[:-1]))or 0pour enregistrer un caractère (avec les espaces). C'est une
bonne

merci, j'ai joué pendant un moment avec cette notation ternaire, que je trouve toujours verbeuse, mais qui n'a pas pensé à la and/orchose.
njzk2

Oui, je l'ai appris ici :) Je pense aussi que vous devez faire entendre votre u.split(' ')voix u.split(' ',1)pour les devises qui ont des espaces, comme "demi-souverain".
FryAmTheEggman

c'est donc la raison du , 1!
njzk2

2
Le ternaire x and y or 0peut être raccourci en général x and y, car les deux évaluent 0ou équivalent Falseà xFalsey.
2014

1

JavaScript ES6, 264 273

f=t=>{s=t.split(x=' in')
c=d=>{'t0sh|bo0^p|co0f0fp0fl|b b0gu0d|v0wn0gr0f g|t..?p0f s0f gu0f c0x|an'.split(0).map((e,i)=>{v=s[d].match(e)?[12,48,4,1,2,96,1008,960,240,16,8,480,504,120,24][i]:v})
return v}
return s.join(' is '+~~(1e4*t.split(' ')[0]*c(0)/c(1))/1e4)}

Cela obtient la valeur de chaque devise en la comparant à différentes expressions régulières, en commençant par la plus large /t/; la valeur est remplacée si une autre correspondance est rencontrée. Il pourrait y avoir un moyen de raser quelques octets en réorganisant la chaîne d'expression régulière. Vous pouvez le tester à l'aide de l'extrait ci-dessus (il est formaté uniquement pour utiliser des boîtes de dialogue et supprimer les fonctions de flèche ES6 afin que tout le monde puisse tester le code facilement). Merci à Alconja pour les suggestions.


1
Vous pouvez couper 2 caractères en utilisant 't0sh|bo0^p....'.split(0), 4 plus en utilisant au .maplieu de .forEachet 3 plus en appelant c(0)et c(1)et faires[d].match
Alconja
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.