Сколько гиней в трех пенни?

32

До десятичности в 1971 году британские деньги основывались на делении фунта на 240 копеек. Шиллинг был 12 копеек, поэтому 20 шиллингов сделали фунт. Самым маленьким номиналом был фартинг на четверть копейки. Было много других номиналов и прозвищ для монет, которые могут запутать, если вы не привыкли к системе.

Вызов

Напишите программу или функцию, которая может преобразовать (почти) любую деноминацию старых английских денег в любую другую. Чтобы пользователю было проще, вам нужно поддерживать множественное число и псевдонимы.

Это наименования и их синонимы, которые вы должны поддерживать. Для удобства их значение в фартингах приводит каждую строчку.

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

(Я не британец, этот список ни в коем случае не является авторитетным, но его будет достаточно для вызова.)

С помощью стандартного аргумента или функции вы должны получить строку вида

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

и вернуть или распечатать

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

где [converted value]- [value to convert]единицы достоинства 1, преобразованные в наименование 2.

[value to convert]И [converted value]положительные поплавки. В выходных данных оба должны быть округлены или усечены до 4 десятичных знаков. При желании вы можете предположить, что [value to convert]всегда имеет десятичную точку и ноль при вводе (например, 1.0вместо 1).

Деноминации 1 и 2 могут быть любыми двумя терминами из списка выше. Не беспокойтесь о том, множественные они или нет, относитесь ко всем наименованиям и синонимам одинаково. Вы можете предположить, что формат ввода и номиналы всегда действительны.

Примеры

1 pounds in shilling1 pounds is 20 shilling
( 1.0000 pounds is 20.0000 shillingбыло бы хорошо)

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

счет

Самый короткий код в байтах побеждает.

Кальвин Хобби
источник
1
«пенни» используется только для обозначения количества монет, а не количества денег.
Дэвид Ричерби
4
Nit-pick: после десятичной дроби, множественное число quidявляется quid. Скорее всего, это было бы то же самое со старыми деньгами. Пример: Five quid a pint! Cor blimey guvnor. Исключение: квидс-ин
Цифровая травма
7
Я, вероятно, запутал бы многих людей, требуя, чтобы они включили "ha'penny".
kaine
3
Я никогда не слышал, чтобы ха'пенни называл что-либо, кроме ха'пенни, @kaine. Как в en.wikipedia.org/wiki/Ha%27penny_Bridge . Конечно, я сам слишком молод, чтобы слышать это слишком часто в речи, но апостроф кажется стандартным в письменной форме.
TRiG

Ответы:

9

Пиф , 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

Более читабельно (для запуска необходимо удалить переводы строки и отступы):

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

Обновление: Оказывается, это на 1 символ короче (без пробела), чтобы разбить строку в список из 2-х символьных строк перед запуском операции индекса строки. /x"string"<b2 2-> xc"string"2<b2. Больше ничего не нужно менять.

Как это работает:

  • При этом используется подход @ xnor, который заключается в поиске значения валюты с использованием первых двух букв, а также в приеме определения начального halfили twoудаления его и повторного вызова функции.

  • Чтобы найти значение первых двух символов, он находит расположение первых двух букв валюты в строке, затем делит на 2 и принимает значение по этому индексу в списке. Это намного короче, чем диктат в пите.

  • Использует тот факт, что x(найти в строке) возвращает -1 при невозможности избежать помещения po(фунтов) qu(quid) или so(суверенных) в строку и просто возвращает последний элемент списка, 960, по умолчанию.

  • Путем изменения порядка валют в поисковой системе и тщательной инициализации с помощью K4и J24все пробелы, необходимые для разделения чисел в списке, были удалены.

  • Использует оператор двойного присваивания pyth при разбивке Aвходных данных, inчтобы получить начало и конец входных данных в отдельных переменных.

  • По сути, делает тот же поиск в конце, хотя Pyth не имеет .split(_,1), так что это несколько более громоздко.

Примеры:

$ 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
источник
3
Я сдаюсь ...;)
Мартин Эндер
Я не знал <и >работал как оператор среза строки / списка; это намного, намного лучше, чем брать голову или
кончик
@FryAmTheEggman Похоже, этого не было в документации - я добавил его.
Исаак
Я, наверное, должен прочитать Macros.py более внимательно :)
FryAmTheEggman
14

Ruby, 345 306 302 288 287 278 273 253 252 242 232 221 202 190 байтов

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

Принимает ввод из STDIN и печатает в STDOUT.

Я использую короткие регулярные выражения, чтобы соответствовать только желаемым номиналам для каждого значения. Есть два массива, один с регулярными выражениями и один со значениями, с соответствующими индексами. Массив регулярных выражений является литералом массива с разделителями-пробелами, а массив значений упакован в строку символов UTF-8.

Я выбираю индекс по значениям путем поиска регулярного выражения, соответствующего каждому наименованию. Я также по умолчанию использую случай tuppence / half-groat (значение 8), потому что для этого требуется самое длинное регулярное выражение. Аналогично, некоторые из шаблонов предполагают, что другие значения уже сопоставлены с более ранними шаблонами, поэтому каждое регулярное выражение только отличает желаемое значение только от остальных. Используя это, я мог бы, вероятно, сбрить еще пару байтов, изменив порядок номиналов.

Спасибо Вентеро за то, что он помог мне победить Пита, сделав его короче!

Мартин Эндер
источник
1
Это регулярное выражение match ( s[k]), которое перезаписывает $1и т. Д. Вы можете сохранить несколько символов, переместив блок карты в лямбду и вызвав его непосредственно в последней строке (что также позволяет отбрасывать назначения для $1и $2). И .indexкороче чем .find_index.
Вентеро
@ Ventero Ах, это имеет смысл. Спасибо!
Мартин Эндер
1
Regexp.new k/#{k}/и $><<gets.sub(/foo/){a=$3;...}gets[/foo/];a=$3;puts...всего 221. И вы, конечно, можете использовать старый трюк, заключающийся в упаковке массива int в строку (использование .pack("U*")) и последующем индексировании в эту строку. Должны получить до 195 символов / 200 байт.
Вентеро
Еще лучше:a=gets[/foo/,3]
Ventero
@Ventero Большое спасибо. Я закончил с 196/202, потому что я добавил смещение к кодам символов, чтобы избежать непечатного ASCII. Все еще короче, чем Пиф. ;)
Мартин Эндер
8

Python 3: 264 239 символов

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)

Функция fполучает значение шиллинга строки валюты cпутем снятия отпечатков пальцев с первых двух букв, используя словарь , находя их в строке. Префиксы «половина» и «два» обнаруживаются и учитываются путем выбора префикса и пробела и применения множителя. Поскольку «полпенни» не хватает пробела после «половины», это приводит к «enny», но это обрабатывается с вымышленной записью «en».

Спасибо @isaacg и @grc за большое улучшение поиска по словарю.

XNOR
источник
Я знал, что это можно сделать :) Я также очень смущен тем, что я не знал, что вы можете определить словарь подобным образом ...: S
FryAmTheEggman
2
@FryAmTheEggman Я не мог определить словари по ключевым словам, пока я не увидел их в ответе на этом сайте. Вещи, которые ты изучаешь в гольфе ...
xnor
Я сделал версию Pyth этого и получил 207 символов. Вы бы предпочли, чтобы я разместил его здесь, чтобы вы могли добавить его, или опубликовал вики-ответ сообщества?
FryAmTheEggman
1
+1 за эту 2/4**(c<'t')часть.
njzk2
1
Вы можете сохранить 13 символов, используя .get(c[:2],960)поиск значения из словаря и пропуская po=960,so=960,qu=960,записи из словаря.
Исаак
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

Требуется, чтобы входной номер был числом с плавающей точкой в ​​python, т.е. 144.1

Я думаю, что это может быть сокращено в Python 3 ...

... Подтверждено благодаря @xnor. Также подтвердил, что лучший алгоритм имеет большое значение;)

FryAmTheEggman
источник
Я бы заменил q=raw_input().split(' in ')наq,b=raw_input().split(' in ')
njzk2
@ njzk2 Совершенно верно ... Я также использовал это для следующей строки, сейчас :)
FryAmTheEggman
Я думаю, что существует конфликт между h+' gr':8и в h+' g':504зависимости от того, кого оценивают в первую очередь для
полушерсти
@ njzk2 это правда ... добавлено uк гвинейскому ...
FryAmTheEggman
2

Haskell - 315 байт

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
источник
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])

Я пошел с подходом хэш-функции ... Я думаю, что недооценил (относительно), насколько сложной была бы обработка ввода (по сравнению с подходом регулярных выражений, это не заботится о числе).

Светляк
источник
1

На основе ответа @ FryAmTheEggMan, с другим способом тестирования 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
источник
Я думаю, что вам нужно добавить завершающий пробел к printи отформатированной строке. Вы также можете переписать лямбду, s=lambda x:x and C.get(x,s(x[:-1]))or 0чтобы сохранить символ (вместе с пробелами). Это довольно
изящная
спасибо, я какое-то время возился с этой троичной нотацией, которую я всегда нахожу многословной, но не думал об этом and/or.
njzk2
Да, я узнал об этом здесь :) Я также думаю, что вы должны u.split(' ')сказать, u.split(' ',1)для валют, которые имеют пробелы, такие как "наполовину суверенный".
FryAmTheEggman
так вот в чем причина , 1!
njzk2
2
Троичный x and y or 0может быть сокращен в целом x and y, так как оба оценивают 0или эквивалентно, Falseкогда xФолси.
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)}

Это получает значение каждой валюты, сравнивая ее с различными регулярными выражениями, начиная с самого широкого /t/; значение перезаписывается, если встречается другое совпадение. Может быть способ сократить пару байтов, переупорядочив строку регулярного выражения. Вы можете протестировать его с помощью приведенного выше фрагмента (он отформатирован только для использования диалоговых окон и удаления функций стрелок ES6, чтобы каждый мог легко протестировать код). Спасибо Alconja за предложения.

NinjaBearMonkey
источник
1
Вы можете обрезать 2 символов, используя 't0sh|bo0^p....'.split(0), 4 больше, используя .mapвместо .forEachи 3 более по телефону c(0)и c(1)и делатьs[d].match
Alconja