Ile Gwinei to trzy grosze brutto?

32

Aż do zdziesiątkowania w 1971 r. Brytyjskie pieniądze opierały się na podziale funta na 240 centów. Szyling wynosił 12 centów, więc 20 szylingów to funt. Najmniejszy nominał to grzebanie w jednej czwartej centa. Istnieje wiele innych nominałów i pseudonimów monet, co może być dość mylące, jeśli nie jesteś przyzwyczajony do systemu.

Wyzwanie

Napisz program lub funkcję, która może konwertować (prawie) dowolne nominały starych angielskich pieniędzy na dowolne inne. Aby ułatwić użytkownikowi, musisz obsługiwać liczbę mnogą i pseudonimy.

Są to nominały i ich synonimiczne warunki, które musisz wspierać. Dla wygody ich wartość w farthings prowadzi każdą linię.

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

(Nie jestem Brytyjczykiem, ta lista nie jest autorytatywna, ale wystarczy na wyzwanie).

Za pomocą argumentu stdin lub funkcji należy przyjąć ciąg znaków

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

i zwróć lub wydrukuj

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

w których [converted value]to [value to convert]jednostek nominału 1 przekształca się nominał 2.

[value to convert]I [converted value]są pozytywne pływaki. Na wyjściu oba powinny być zaokrąglone lub obcięte do 4 miejsc po przecinku. W razie potrzeby można założyć, że [value to convert]zawsze ma kropkę dziesiętną i zero po wprowadzeniu (np. 1.0Zamiast 1).

Nominały 1 i 2 mogą być dowolnymi dwoma terminami z powyższej listy. Nie martw się, czy są w liczbie mnogiej, czy nie, traktuj wszystkie nominały i synonimy tak samo. Możesz założyć, że format wejściowy i nominały są zawsze prawidłowe.

Przykłady

1 pounds in shilling1 pounds is 20 shilling
( 1.0000 pounds is 20.0000 shillingbyłoby dobrze)

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

Punktacja

Najkrótszy kod w bajtach wygrywa.

Hobby Calvina
źródło
1
„grosze” są używane wyłącznie w odniesieniu do wielu monet, a nie do kwoty pieniężnej.
David Richerby
4
Nit-pick: po dziesiętnej liczbie mnogiej quidjest quid. Najprawdopodobniej byłoby tak samo ze starymi pieniędzmi. Przykład: Five quid a pint! Cor blimey guvnor. Wyjątek: quids-in
Digital Trauma
7
Prawdopodobnie zepsułbym wiele osób, aby wymagały od nich wpisania „ha'penny”.
kaine
3
Nigdy nie słyszałem, żeby ktoś nazywał się kimś innym niż ha'penny, @kaine. Jak w en.wikipedia.org/wiki/Ha%27penny_Bridge . Oczywiście jestem zbyt młody, by zbyt często słyszeć to w mowie, ale apostrof wydaje się być standardem w pisaniu.
TRiG,

Odpowiedzi:

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

Bardziej czytelne (nowe wiersze i wcięcia muszą zostać usunięte, aby uruchomić):

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

Aktualizacja: Okazuje się, że jest o 1 znak krótszy (nie wymaga spacji), aby pokroić ciąg na listę 2 ciągów znaków przed uruchomieniem operacji indeksu ciągu. /x"string"<b2 2-> xc"string"2<b2. Nic więcej nie trzeba zmieniać.

Jak to działa:

  • Wykorzystuje @ podejścia XNOR dnia patrząc w górę wartości waluty przy użyciu dwóch pierwszych liter, a także sprawę wykrywania początkowego halflub twousunięcie go i ponownie wywołanie funkcji.

  • Aby wyszukać wartość pierwszych dwóch znaków, znajduje lokalizację pierwszych dwóch liter waluty w ciągu, a następnie dzieli przez 2 i przyjmuje wartość pod tym indeksem na liście. To jest znacznie krótsze niż dyktat w pyth.

  • Wykorzystuje fakt, że x(znajdź w ciągu ciągu) zwraca -1 po nieudanym uniknięciu wpisania po(funtów) qu(quid) lub so(suwerenów) w ciągu i po prostu domyślnie zwraca ostatni element listy, 960.

  • Przez zmianę kolejności walut w systemie wyszukiwania i staranne zainicjowanie za pomocą K4i J24, wszystkie spacje, które byłyby potrzebne do oddzielenia liczb na liście, zostały usunięte.

  • Używa operatora podwójnego przypisania Pytha A, przy podziale danych wejściowych na, inaby uzyskać początek i koniec danych wejściowych w osobnych zmiennych.

  • Robi w zasadzie to samo wyszukiwanie na końcu, chociaż pyth nie ma .split(_,1), więc jest nieco bardziej kłopotliwy.

Przykłady:

$ 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
źródło
3
Poddaję się;;)
Martin Ender
Nie znałem <i >pracowałem jako operatory odcinków łańcuchów / list; to o wiele, wiele lepiej niż zabranie głowy lub końca kotleta :)
FryAmTheEggman
@FryAmTheEggman Wygląda na to, że brakowało również w dokumentacji - dodałem ją.
isaacg
Prawdopodobnie powinienem uważniej przeczytać macros.py :)
FryAmTheEggman
14

Rubinowy, 345 306 302 288 287 278 273 253 252 242 232 221 202 190 bajtów

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

Pobiera dane wejściowe ze STDIN i drukuje do STDOUT.

Używam krótkich wyrażeń regularnych, aby dopasować tylko pożądane nominały dla każdej wartości. Istnieją dwie tablice, jedna z wyrażeniami regularnymi i jedna z wartościami, przy odpowiednich indeksach. Tablica wyrażeń regularnych jest literałem rozdzielanym spacjami, a tablica wartości jest spakowana w ciąg znaków UTF-8.

Wybieram indeks do wartości, szukając wyrażenia regularnego pasującego do każdego nominału. Domyślam się również przypadku tuppence / half-groat (wartość 8), ponieważ wymagało to najdłuższego wyrażenia regularnego. Podobnie, niektóre wzorce zakładają, że inne wartości zostały już dopasowane do wcześniejszych wzorców, więc każde wyrażenie regularne odróżnia tylko pożądaną wartość tylko od pozostałych. Korzystając z tego, prawdopodobnie mógłbym ogolić kolejną parę bajtów, zmieniając kolejność nominałów.

Dzięki Ventero za pomoc w pokonaniu Pytha, dzięki czemu jest on krótszy!

Martin Ender
źródło
1
Dopasowywanie wyrażeń regularnych ( s[k]) zastępuje $1itp. Możesz zapisać kilka znaków, przenosząc blok mapy do lambda i wywołując go bezpośrednio w ostatnim wierszu (co pozwala również na upuszczenie przypisań dla $1i $2). .indexJest także krótszy niż .find_index.
Ventero
@Ventero Ah, to ma sens. Dziękuję Ci!
Martin Ender
1
Regexp.new k/#{k}/i $><<gets.sub(/foo/){a=$3;...}gets[/foo/];a=$3;puts...w sumie 221. I możesz oczywiście użyć starej sztuczki upakowania tablicy int w łańcuch (używając .pack("U*")), a następnie indeksowania do tego łańcucha. Powinieneś sprowadzić cię do 195 znaków / 200 bajtów.
Ventero
Jeszcze lepiej:a=gets[/foo/,3]
Ventero
@Ventero Dziękuję bardzo. Skończyłem z 196/202, ponieważ dodałem przesunięcie do kodów char, aby uniknąć niedrukowalnego ASCII. Wciąż krótszy niż Pyth. ;)
Martin Ender
8

Python 3: 264 239 znaków

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)

Funkcja fpobiera szylingową wartość łańcucha walutowego cpoprzez odcisk palca pierwszych dwóch liter za pomocą słownika , znajdując je w ciągu. Przedrostki „połowa” i „dwa” są wykrywane i uwzględniane poprzez wycięcie przedrostka i spacji oraz zastosowanie mnożnika. Ponieważ „halfpenny” nie ma spacji po „half”, skutkuje to „enny”, ale jest to obsługiwane za pomocą fikcyjnego wpisu „en”.

Dzięki @isaacg i @grc za wiele ulepszeń w wyszukiwaniu słownika.

xnor
źródło
Wiedziałem, że da się to zrobić :) Jestem też bardzo zawstydzony, że nie wiedziałem, że można zdefiniować taki słownik ...: S
FryAmTheEggman
2
@FryAmTheEggman Nie wiedziałem, że możesz definiować słowniki za pomocą słów kluczowych, dopóki nie zobaczyłem go w odpowiedzi na tej stronie. Rzeczy, których uczysz się w golfa ...
xnor
Zrobiłem wersję Pyth'a i mam 207 znaków. Czy wolałbym zamieścić go tutaj, aby dodać lub opublikować odpowiedź wiki społeczności?
FryAmTheEggman
1
+1 za tę 2/4**(c<'t')część.
njzk2
1
Możesz zapisać 13 znaków, używając .get(c[:2],960)do wyszukiwania wartości ze słownika i pomijając po=960,so=960,qu=960,wpisy ze słownika.
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

Wymaga, aby numer wejściowy był zmiennoprzecinkowy w pythonie, tj 144.1

Myślę, że można to skrócić w Pythonie 3 ...

... Potwierdzone dzięki @xnor. Potwierdził także, że posiadanie lepszego algorytmu ma duże znaczenie;)

FryAmTheEggman
źródło
Chciałbym zastąpić q=raw_input().split(' in ')przezq,b=raw_input().split(' in ')
njzk2
@ njzk2 Całkiem słusznie ... Użyłem tego również do następnej linii, teraz :)
FryAmTheEggman
Myślę, że istnieje konflikt pomiędzy h+' gr':8i h+' g':504w zależności od tego, kto jest oceniany najpierw przez pół kasz
njzk2
@ njzk2 to prawda ... dodane udo gwinei ...
FryAmTheEggman
2

Haskell - 315 bajtów

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
Rhymoid
źródło
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])

Poszedłem z podejściem funkcji skrótu ... Myślę, że nie doceniłem (względnie), jak skomplikowane byłoby przetwarzanie danych wejściowych (w stosunku do wyrażenia regularnego, które nie dbałoby o liczbę).

Robaczek świętojański
źródło
1

Na podstawie odpowiedzi @ FryAmTheEggMan, z innym sposobem testowania 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
njzk2
źródło
Myślę, że musisz dodać końcowe spacje do printi sformatowanego ciągu. Możesz także przepisać lambda, s=lambda x:x and C.get(x,s(x[:-1]))or 0aby zapisać postać (wraz ze spacjami). To całkiem fajny pomysł, btw :)
FryAmTheEggman
dzięki, przez chwilę bawiłem się tą notacją potrójną, którą zawsze uważam za gadatliwą, ale o tym nie myślałem and/or.
njzk2
Tak, nauczyłem się tutaj :) Myślę też, że musisz u.split(' ')mówić w u.split(' ',1)przypadku walut, które mają spacje, na przykład „pół suwerena”.
FryAmTheEggman
więc to jest powód , 1!
njzk2
2
Trójskładnik x and y or 0można ogólnie skrócić do x and y, ponieważ oba oceniają, gdy jest Falsey, 0lub równoważnie . Falsex
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)}

Otrzymuje wartość każdej waluty, porównując ją z różnymi wyrażeniami regularnymi, zaczynając od najszerszego /t/; wartość zostanie zastąpiona, jeśli zostanie znalezione inne dopasowanie. Może istnieć sposób na zmniejszenie kilku bajtów poprzez zmianę kolejności ciągu wyrażeń regularnych. Możesz go przetestować za pomocą powyższego fragmentu (jest sformatowany tylko w celu korzystania z okien dialogowych i usuwania funkcji strzałek ES6, dzięki czemu każdy może łatwo przetestować kod). Dzięki Alconja za sugestie.

NinjaBearMonkey
źródło
1
Możesz przyciąć 2 znaki za pomocą 't0sh|bo0^p....'.split(0), 4 więcej stosując .mapzamiast .forEachi 3 więcej dzwoniąc c(0)i c(1)i robis[d].match
Alconja