JS, 1719/1694
Теорія
На жаль, набір правил, який ви надаєте, не може бути розумним рішенням з математичної точки зору. Насправді, використовуючи менший підмножина правил, ви можете знайти рішення для кожного числа в заданому інтервалі
окрім
для якого немає рішення.
Скорочений набір правил
Розглянемо наступну підгрупу правил:
- Використовуйте лише операторів
plus
, minus
і times
.
- Вам не потрібно реалізовувати численні зустрічі
plus
або minus
у своїх виразах.
- Вам не потрібно ні реалізувати, ні
division
ні operator associativity
(оскільки їх набір рішень вже охоплений першим правилом).
Причина, чому це працює, полягає в тому, що, як ви обговорювали раніше з @Qwix, ви дозволяєте нудні відповіді , тобто вирази, які закінчуються в регулярному виразі
( times one)+$
. Дозволяючи це, кожне число у заданому інтервалі матиме рішення.
Коли ви відповіли в одному зі своїх коментарів,
@Qwix Так; нудні відповіді прийнятні, хоча це не працює для 104, 105, 106, 107, 108, 109, 110 або 111. -
ви були абсолютно праві: це не спрацьовує, коли ви намагаєтеся побудувати своє вираження, починаючи з самих чисел, тобто one hundred four times one times one …
будь-яких інших цих чисел.
Якщо ж ваш вираз починається з виразу, оцінка якого дорівнює одному із заданих чисел, вам не пощастило. Наприклад, зауважте, що 17 + 87
це дійсно 104
, тому ми могли б написати 104
так:
104: seventeen plus eighty seven times one times one times one times one times one times one times one times one times one times one
Щоб побачити, що ця підмножина працює, збережіть цей файл як num.js
і переконайтесь, що у вашій системі встановлено SpiderMonkey, двигун JavaScript для командних рядків.
Алгоритм
- Давайте визначимо властивість
K
для натуральних чисел як стан числа, що має N
літери та має значення N
.
- Далі визначимо властивість
F
для виразу як стан його перетворення слів, який 8k
-тричі коротший, ніж його оцінка з k ∈ ℕ. F
означає "fillable" і описує, чи можемо ми заповнити перетворення слова виразом виразами довжини 8 (тобто " times one"
) таким чином, щоб отриманий вираз міг отримати властивість N
.
Потім ми поступаємо так:
- Перетворити вхідне число в слова.
- Перевірте, чи є вхідний номер
K
.
- Якщо це так, поверніть слова (
4
на жаль, єдине число з цією властивістю).
- Якщо цього не відбувається, продовжуйте.
- Для всіх виразів з двома операндами (додавання, віднімання та множення в цьому порядку), які призводять до вхідного числа, перевірте, чи має їх оцінка властивість
K
.
- Якщо так, поверніть слова.
- Якщо це не так, перевірте, чи має вираз двох операндів властивість
N
.
- Якщо це так, заповніть вираз
" times one"
і перевірте, чи має значення отриманий вираз властивістьK
.
- Якщо так, поверніть слова
- Якщо цього не відбувається, продовжуйте
- Якщо цього не відбувається, продовжуйте
- Іди випий каву
Практика
num.js (для SpiderMonkey / командних рядків)
function X(e,t){return e+": "+t}function P(e){var n,t;for(n=1;.5*e+(e%2===0?1:0)>n;++n){if(t=C.s(n)+" plus "+C.s(e-n),t.replace(/\s/g,"").length===e)return t;if(F(e,t)&&e>t.length)return G(e,t)}return!1}function M(e){var t,n;for(t=L;t>1;--t){if(0>t-e)return!1;if(n=C.s(t)+" minus "+C.s(t-e),n.replace(/\s/g,"").length===e)return n;if(F(e,n)&&e>n.length)return G(e,n)}return!1}function F(e,t){return(e-t.replace(/\s/g,"").length)%8===0}function G(r,t){var e,i=(r-t.replace(/\s/g,"").length)/8,n="";for(e=0;i>e;++e)n+=" times one";return t+n}function T(e){var t,n,r;if(F(e,C.s(e)))return G(e,C.s(e));for(t=1,n=1;t<Math.floor(Math.sqrt(e));++t){for(;e>tn;)++n;if(tn===e&&(r=C.s(t)+" times "+C.s(n),r.replace(/\s/g,"").length===e))return r}return!1}function Y(e){var n,r,t;return e===C.s(e).length?X(e,C.s(e)):(n=P(e))?X(e,n):(r=M(e))?X(e,r):(t=T(e),t?X(e,t):X(e,"impossible"))}var L=1e4,C=new function(){return this.o=["","one","two","three","four","five","six","seven","eight","nine"],this.t=["","","twenty","thirty","forty","fifty","sixty","seventy","eighty","ninety"],this.T=["ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen"],this.s=function(e){return e?this.m(e):"zero"},this.m=function(e){return e>=1e6?this.m(Math.floor(e/1e6))+" million"+(e%1e6!==0?" "+this.Z(e%1e6):""):this.Z(e)},this.Z=function(e){return e>=1e3?this.h(Math.floor(e/1e3))+" thousand"+(e%1e3!==0?" "+this.h(e%1e3):""):this.h(e)},this.h=function(e){return e>99?this.o[Math.floor(e/100)]+" hundred"+(e%100!==0?" "+this.U(e%100):""):this.U(e)},this.U=function(e){return 10>e?this.o[e]:e>=10&&20>e?this.T[e-10]:this.t[Math.floor(e/10)]+(e%10!==0?" "+this.o[e%10]:"")},this};print(Y(0|arguments[0]))
num.js (для браузерів)
Даний код зверху не може працювати для браузерів через останню команду, яка захоплює аргументи командного рядка, щоб зробити гарну команду з даного сценарію.
Для того, щоб запустити код JavaScript безпосередньо з вашого браузера, виберіть цей фрагмент вищевказаного коду:
function X(e,t){return e+": "+t}function P(e){var n,t;for(n=1;.5*e+(e%2===0?1:0)>n;++n){if(t=C.s(n)+" plus "+C.s(e-n),t.replace(/\s/g,"").length===e)return t;if(F(e,t)&&e>t.length)return G(e,t)}return!1}function M(e){var t,n;for(t=L;t>1;--t){if(0>t-e)return!1;if(n=C.s(t)+" minus "+C.s(t-e),n.replace(/\s/g,"").length===e)return n;if(F(e,n)&&e>n.length)return G(e,n)}return!1}function F(e,t){return(e-t.replace(/\s/g,"").length)%8===0}function G(r,t){var e,i=(r-t.replace(/\s/g,"").length)/8,n="";for(e=0;i>e;++e)n+=" times one";return t+n}function T(e){var t,n,r;if(F(e,C.s(e)))return G(e,C.s(e));for(t=1,n=1;t<Math.floor(Math.sqrt(e));++t){for(;e>tn;)++n;if(tn===e&&(r=C.s(t)+" times "+C.s(n),r.replace(/\s/g,"").length===e))return r}return!1}function Y(e){var n,r,t;return e===C.s(e).length?X(e,C.s(e)):(n=P(e))?X(e,n):(r=M(e))?X(e,r):(t=T(e),t?X(e,t):X(e,"impossible"))}var L=1e4,C=new function(){return this.o=["","one","two","three","four","five","six","seven","eight","nine"],this.t=["","","twenty","thirty","forty","fifty","sixty","seventy","eighty","ninety"],this.T=["ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen"],this.s=function(e){return e?this.m(e):"zero"},this.m=function(e){return e>=1e6?this.m(Math.floor(e/1e6))+" million"+(e%1e6!==0?" "+this.Z(e%1e6):""):this.Z(e)},this.Z=function(e){return e>=1e3?this.h(Math.floor(e/1e3))+" thousand"+(e%1e3!==0?" "+this.h(e%1e3):""):this.h(e)},this.h=function(e){return e>99?this.o[Math.floor(e/100)]+" hundred"+(e%100!==0?" "+this.U(e%100):""):this.U(e)},this.U=function(e){return 10>e?this.o[e]:e>=10&&20>e?this.T[e-10]:this.t[Math.floor(e/10)]+(e%10!==0?" "+this.o[e%10]:"")},this}
Тепер вставте його в консоль JavaScript свого веб-переглядача, щоб ви могли створити ті самі результати у своєму браузері, наприклад:
Y(1234);
Приклади (командний рядок)
chiru@chiru ~ $ js num.js 28
28: fourteen plus fourteen times one
chiru@chiru ~ $ js num.js 7
7: impossible
chiru@chiru ~ $ js num.js 42
42: nine thousand sixty minus nine thousand eighteen
А для того , щоб побачити трюк , з яким ви можете зробити кожен номер роботи, просто подивитися на нудному відповідь на js num.js 1337
:
1337: ten plus one thousand three hundred twenty seven times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one times one
Надані коди генерують дійсні рішення для заданого інтервалу (і, мабуть, навіть вище, вам доведеться лише підняти значення змінної L
).
Статистика
Мене цікавило, наскільки нудними були вирази (або: скільки підрядкаtimes one
було використано для кожного виразу в рамках цього алгоритму), оскільки ця частина відповідала за пошук рішення для кожного числа протягом заданого інтервалу. Побачте самі:
x : n-й вираз (хв. 0, макс. 10000)
y : кількість випадків підрядки "раз один" в виразі (хв. 0, макс. 1245)
Висновки:
- Вирази, як правило, стають все більш нудними в лінійному порядку.
- Понад 99% рішень нудні.
So for 1234 we can do (massive expression) times zero plus one thousand two hundred thirty four.
Ви можете виключити нуль. До вас.