¿Cuántas guineas en un bruto de tres peniques?

32

Hasta la decimalización en 1971 , el dinero británico se basaba en dividir la libra en 240 centavos. Un chelín fue de 12 centavos, por lo que 20 chelines hicieron una libra. La denominación más pequeña era el pedo en un cuarto de un centavo. Había muchas otras denominaciones y apodos para las monedas, lo que puede ser bastante confuso si no estás acostumbrado al sistema.

Reto

Escriba un programa o función que pueda convertir (casi) cualquier denominación de dinero antiguo en inglés a cualquier otra. Para que sea más fácil para el usuario, debe admitir plurales y apodos.

Estas son las denominaciones y sus términos sinónimos que debe admitir. Por conveniencia, su valor en farthings lidera cada línea.

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

(No soy británico, esta lista no es de ninguna manera autorizada, pero será suficiente para el desafío).

A través de stdin o argumento de función, debe tomar una cadena de la forma

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

y devolver o imprimir

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

donde [converted value]se [value to convert]convierten las unidades de denominación 1 en la denominación 2.

Los [value to convert]y [converted value]son flotadores positivos. En la salida, ambos deben redondearse o truncarse a 4 decimales. Si lo desea, puede suponer que [value to convert]siempre tiene un punto decimal y cero cuando ingresa (por ejemplo, en 1.0lugar de 1).

Las denominaciones 1 y 2 pueden ser dos términos de la lista anterior. No se preocupe si son plurales o no, trate todas las denominaciones y sinónimos de la misma manera. Puede suponer que el formato de entrada y las denominaciones son siempre válidas.

Ejemplos

1 pounds in shilling1 pounds is 20 shilling
( 1.0000 pounds is 20.0000 shillingestaría 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

Tanteo

El código más corto en bytes gana.

Pasatiempos de Calvin
fuente
1
"centavos" solo se usa para referirse a una cantidad de monedas, no a una cantidad de dinero.
David Richerby el
44
Nit-pick: Post decimalización, el plural de quidis quid. Lo más probable es que esto hubiera sido lo mismo con el dinero antiguo. Ejemplo: Five quid a pint! Cor blimey guvnor. Excepción: quids-in
Trauma digital
77
Probablemente molestaría a mucha gente para exigirles que incluyan "ha'penny".
kaine
3
Nunca escuché que un medio penique llamara otra cosa que un medio penique, @kaine. Como en en.wikipedia.org/wiki/Ha%27penny_Bridge . Por supuesto, soy demasiado joven para haberlo escuchado con demasiada frecuencia en el habla, pero el apóstrofe parece estándar en la escritura.
TRiG

Respuestas:

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

Más legible (las líneas nuevas y las sangrías deben eliminarse para ejecutarse):

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

Actualización: Resulta que es 1 carácter más corto (no se necesita espacio) para cortar la cadena en una lista de cadenas de 2 caracteres antes de ejecutar la operación de índice de cadena. /x"string"<b2 2-> xc"string"2<b2. Nada más necesita ser cambiado.

Cómo funciona:

  • Utiliza el enfoque de @ xnor de buscar el valor de la moneda usando sus dos primeras letras, así como el truco de detectar la inicial halfo two, eliminarla y volver a llamar a la función.

  • Para buscar el valor de los dos primeros caracteres, encuentra la ubicación de las dos primeras letras de la moneda en una cadena, luego se divide por 2 y toma el valor en ese índice en la lista. Esto es mucho más corto que un dict en pyth.

  • Utiliza el hecho de que x(buscar dentro de la cadena) devuelve -1 en caso de no evitar poner po(libras) qu(quid) o so(soberanos) en la cadena, y simplemente devuelve el último elemento de la lista, 960, por defecto.

  • Al reorganizar el orden de las monedas en el sistema de búsqueda e inicializar cuidadosamente, con K4y J24, se eliminaron todos los espacios que habrían sido necesarios para separar los números en la lista.

  • Utiliza el operador de asignación dual de pyth A, en la entrada dividida inpara obtener el principio y el final de la entrada en variables separadas.

  • Esencialmente realiza la misma búsqueda al final, aunque pyth no tiene .split(_,1), por lo que es algo más engorroso.

Ejemplos:

$ 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
isaacg
fuente
3
Me rindo ...;)
Martin Ender
No lo sabía <y >trabajé como operadores de corte de cadena / lista; eso es mucho, mucho mejor que tomar la cabeza o el final de un corte :)
FryAmTheEggman
@FryAmTheEggman Parece que eso también faltaba en la documentación, lo he agregado.
isaacg
Probablemente debería leer macros.py con más cuidado :)
FryAmTheEggman
14

Rubí, 345 306 302 288 287 278 273 253 252 242 232 221 202 190 bytes

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]}

Toma información de STDIN e imprime en STDOUT.

Estoy usando expresiones regulares cortas para hacer coincidir solo las denominaciones deseadas para cada valor. Hay dos matrices, una con expresiones regulares y otra con valores, en los índices correspondientes. La matriz regex es una matriz literal delimitada por espacios, y la matriz de valores está empaquetada en una cadena de caracteres UTF-8.

Estoy seleccionando el índice en los valores buscando una expresión regular que coincida con cada denominación. También estoy por defecto en el caso tuppence / half-groat (valor 8), porque eso requería la expresión regular más larga. Del mismo modo, algunos de los patrones suponen que otros valores ya han sido emparejados por patrones anteriores, por lo que cada expresión regular solo distingue el valor deseado solo de los restantes. Usando esto, probablemente podría recortar otro par de bytes reorganizando el orden de las denominaciones.

¡Gracias a Ventero por ayudarme a vencer a Pyth haciéndolo más corto!

Martin Ender
fuente
1
Es la coincidencia de expresiones regulares ( s[k]) la que sobrescribe, $1etc. Puede guardar algunos caracteres moviendo el bloque del mapa a una lambda y llamando eso directamente en la última línea (que también le permite colocar las asignaciones para $1y $2). También .indexes más corto que .find_index.
Ventero el
@ Ventero Ah, eso tiene sentido. ¡Gracias!
Martin Ender
1
Regexp.new k/#{k}/y $><<gets.sub(/foo/){a=$3;...}gets[/foo/];a=$3;puts...para un total de 221. Y, por supuesto, puede usar el viejo truco de empaquetar la matriz int en una cadena (usando .pack("U*")) y luego indexarla en esa cadena. Debería bajarlo a 195 caracteres / 200 bytes.
Ventero
Aún mejor:a=gets[/foo/,3]
Ventero
@Ventero Muchas gracias. Terminé con 196/202, porque agregué un desplazamiento a los códigos de caracteres para evitar ASCII no imprimible. Aún más corto que Pyth. ;)
Martin Ender
8

Python 3: 264 239 caracteres

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 función fobtiene el valor de chelín de la cadena de moneda cal tomar las huellas digitales de las dos primeras letras usando el diccionario al encontrarlas en una cadena. Los prefijos "mitad" y "dos" se detectan y explican cortando el prefijo y el espacio y aplicando un multiplicador. Como "halfpenny" carece de un espacio después de "half", esto resulta en "enny", pero eso se maneja con una entrada ficticia "en".

Gracias a @isaacg y @grc por muchas mejoras en la búsqueda del diccionario.

xnor
fuente
Sabía que se podía hacer :) También estoy extremadamente avergonzado de no saber que podrías definir un diccionario así ...: S
FryAmTheEggman
2
@FryAmTheEggman No pude definir diccionarios a través de palabras clave hasta que vi que se usaba en una respuesta en este sitio. Las cosas que aprendes jugando al golf ...
xnor
Hice una versión Pyth de esto y obtuve 207 caracteres. ¿Prefieres que lo publique aquí para que lo agregues o publiques una respuesta wiki comunitaria?
FryAmTheEggman
1
+1 para esa 2/4**(c<'t')parte.
njzk2
1
Puede guardar 13 caracteres utilizando .get(c[:2],960)para buscar el valor del diccionario y omitiendo las po=960,so=960,qu=960,entradas del diccionario.
isaacg
5

Pitón 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

Requiere que el número de entrada sea flotante en Python, es decir 144.1

Creo que esto podría acortarse en Python 3 ...

... Confirmado gracias a @xnor. También confirmó que tener un mejor algoritmo importa mucho;)

FryAmTheEggman
fuente
Lo reemplazaría q=raw_input().split(' in ')porq,b=raw_input().split(' in ')
njzk2
@ njzk2 Muy bien ... También he usado esto para la siguiente línea, ahora :)
FryAmTheEggman
Creo que hay un conflicto entre h+' gr':8y h+' g':504dependiendo de quién es evaluado primero por medio groats
njzk2
@ njzk2 eso es cierto ... agregado ual de Guinea ...
FryAmTheEggman
2

Haskell - 315 bytes

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
Rimoide
fuente
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])

Fui con un enfoque de función hash ... Creo que subestimé (relativamente) cuán complejo sería el procesamiento de entrada (sobre el enfoque de expresiones regulares, eso no le importaría el número).

Luciérnaga
fuente
1

Basado en la respuesta de @ FryAmTheEggMan, con una forma diferente de prueba str.startwith:

Pitón 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
njzk2
fuente
Creo que debe agregar un espacio final a la printcadena formateada. También puede reescribir la lambda s=lambda x:x and C.get(x,s(x[:-1]))or 0para guardar un personaje (junto con los espacios). Esta es una buena idea, por cierto :)
FryAmTheEggman
gracias, jugué un rato con esta notación ternaria, que siempre encuentro detallada, pero no pensé en la and/orcosa.
njzk2
Sí, lo aprendí aquí :) También creo que hay que dar u.split(' ')voz u.split(' ',1)a las monedas que tienen espacios, como "medio soberano".
FryAmTheEggman
así que esa es la razón de la , 1!
njzk2
2
El ternario x and y or 0se puede acortar en general a x and y, ya que ambos evalúan 0o son equivalentes Falsecuando xes Falsey.
xnor
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)}

Esto obtiene el valor de cada moneda al compararlo con varias expresiones regulares, comenzando por la más amplia /t/; el valor se sobrescribe si se encuentra otra coincidencia. Puede haber una manera de reducir un par de bytes reordenando la cadena de expresiones regulares. Puede probarlo con el fragmento anterior (está formateado solo para usar cuadros de diálogo y eliminar las funciones de flecha ES6 para que todos puedan probar el código fácilmente). Gracias a Alconja por las sugerencias.

NinjaOsoMono
fuente
1
Se puede recortar 2 caracteres utilizando 't0sh|bo0^p....'.split(0), 4 más usando .mapen lugar de .forEachy 3 más información llamando c(0)y c(1)y haciendos[d].match
Alconja