¿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.


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

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!


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.


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;)


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

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).


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

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.


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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.