JS, 1719/1694
Teoria
Infelizmente, o conjunto de regras que você fornece pode não ser uma decisão sábia do ponto de vista matemático. De fato, usando um subconjunto menor de regras, você pode encontrar uma solução para cada número no intervalo especificado
exceto por
para o qual não há solução.
Conjunto de regras reduzido
Considere o seguinte subconjunto de regras:
- Use apenas os operadores
plus
, minus
e times
.
- Você não precisa implementar várias ocorrências de
plus
ou minus
em suas expressões.
- Você não precisa implementar nem
division
nem operator associativity
(como o conjunto de soluções já está coberto pela primeira regra).
A razão pela qual isso funciona é que, conforme discutido anteriormente com o @Qwix, você permite respostas chatas , ou seja, expressões que terminam na expressão regular
( times one)+$
. Permitindo isso, cada número no intervalo especificado terá uma solução.
Quando você respondeu em um de seus comentários,
@Qwix Sim; respostas chatas são aceitáveis, embora essa não funcione para 104, 105, 106, 107, 108, 109, 110 ou 111. -
você estava absolutamente certo: isso não funciona quando você está tentando criar sua expressão começando pelos próprios números, one hundred four times one times one …
ou seja, ou qualquer outro desses números.
Se, no entanto, sua expressão começar com uma expressão cuja avaliação seja igual a um dos números fornecidos, você estará sem sorte. Por exemplo, observe que 17 + 87
sim 104
, para que possamos escrever 104
como:
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
Para verificar se esse subconjunto funciona, salve esse arquivo num.js
e verifique se o SpiderMonkey, um mecanismo JavaScript para linhas de comando, está instalado no seu sistema.
O algoritmo
- Vamos definir a propriedade
K
para números inteiros positivos como o estado do número com N
letras e com um valor de N
.
- Vamos definir ainda mais a propriedade
F
de uma expressão como o estado de sua conversão de palavras sendo - 8k
vezes mais curto que sua avaliação com k ∈ ℕ. F
significa "preenchível" e descreve se podemos ou não preencher a conversão de palavras da expressão com expressões de comprimento 8 (ou seja " times one"
), de modo que a expressão resultante possa obter a propriedade N
.
Em seguida, procedemos da seguinte forma:
- Converta o número de entrada em palavras.
- Verifique se o número de entrada tem propriedade
K
.
- Se isso acontecer, retorne as palavras (
4
é o único número com essa propriedade, infelizmente).
- Caso contrário, prossiga.
- Para todas as expressões de dois operandos (adições, subtrações e multiplicações nesta ordem) que resultam no número de entrada, verifique se a avaliação tem propriedade
K
.
- Se isso acontecer, retorne as palavras.
- Caso contrário, verifique se a expressão de dois operandos possui propriedade
N
.
- Se houver, preencha a expressão
" times one"
e verifique se a avaliação da expressão resultante tem propriedade K
.
- Se isso acontecer, retorne as palavras
- Caso contrário, continue
- Caso contrário, continue
- Vá tomar um café
Prática
num.js (para SpiderMonkey / linhas de comando)
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 (para navegadores)
O código fornecido acima não funciona nos navegadores devido ao seu último comando, que captura os argumentos da linha de comando para criar um bom comando a partir do script fornecido.
Para executar o código JavaScript diretamente de dentro do seu navegador, selecione esta parte do código acima:
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}
Agora, cole-o no console JavaScript do seu navegador, para que você possa produzir os mesmos resultados no seu navegador com, por exemplo:
Y(1234);
Exemplos (linha de comando)
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
E para ver o truque com o qual você pode fazer cada número funcionar, basta dar uma olhada na resposta chata para 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
Os códigos fornecidos geram soluções válidas para o intervalo especificado (e provavelmente até acima, você só precisa aumentar o valor da variável L
).
Estatisticas
Eu estava interessado em "quão chatas " eram as expressões (ou: quanto a substring times one
foi usada por expressão nesse algoritmo), pois essa parte era responsável por encontrar uma solução para cada número dentro do intervalo especificado. Veja por si mesmos:
x : n-ésima expressão (mín. 0, máx. 10.000)
y : número de ocorrências de substring "vezes um" dentro da expressão (mín. 0, máx. 1245)
Conclusões:
- As expressões tendem a ficar cada vez mais chatas de maneira linear.
- Mais de 99% das soluções são chatas.
So for 1234 we can do (massive expression) times zero plus one thousand two hundred thirty four.
Você pode excluir zero. Você decide.