Decifrar sapos neuróticos

28

Decifrar sapos neuróticos

Agora que o Puzzling.SE finalmente quebrou minha cifra obcecada por anfíbios , vamos escrever um programa ou função para descriptografá-la!

(Se você quiser ver o quebra-cabeça antes de estragá-lo, clique no link acima agora.)


Como a cifra funciona

Em Neurotic Frogs O ught Para Rel um x em M ud Banhos ( "Neurotic Frogs" para o short), cada letra é criptografada como uma ou duas palavras:

  • O comprimento de uma palavra em itálico representa uma letra.
    • neurotic => 8 letras => H
    • frogs => 5 letras => E
    • perpendicular => 13 letras = M
  • Uma palavra que contenha itálico modifica a palavra a seguir, adicionando 10 se a palavra em itálico tiver tamanho ímpar ou 20 se a palavra em itálico tiver tamanho par. Qualquer uma ou todas as palavras podem estar em itálico. Uma palavra em itálico é sempre seguida por uma palavra não em itálico.
    • *o*ught to => ímpar, 2 => 12 => L
    • lo*u*nging calms => par, 5 => 25 => Y

Toda palavra de texto simples corresponde a uma frase de texto cifrado, e toda frase de texto simples corresponde a um parágrafo de texto cifrado.

Formato de entrada

Seu programa ou função deve inserir uma mensagem no Neurotic Frogs, formatado em Markdown. A entrada consistirá apenas em ASCII imprimível e novas linhas.

  • As palavras são séries de caracteres que correspondem ao regex [A-Za-z0-9'].
    • Números e letras contam para o comprimento de uma palavra. QB64representa D.
    • NOTA: Os apóstrofos não contam para o comprimento de uma palavra. Isn'trepresenta D, não E.
  • As letras em itálico são colocadas em um par de asteriscos ( *letters*).
    • Uma ou mais letras consecutivas podem estar em itálico, com uma palavra inteira ( masseus*es*, *all*); várias letras não consecutivas em uma palavra também podem estar em itálico ( g*e*n*e*rates).
    • O itálico nunca abrange várias palavras, nunca inclui pontuação e nunca inclui apóstrofos.
    • Asteriscos não emparelhados e vários asteriscos adjacentes nunca ocorrerão.
  • A pontuação é qualquer um dos seguintes caracteres: .,?!:;-()".
    • As palavras em uma frase são separadas por um ou mais caracteres de pontuação e / ou um único espaço. Exemplos: *all* welcomed, toad*s*, newts, Ever*y*one--frogs, cap... bliss,they're (I
    • As frases terminam com um ou mais caracteres de pontuação e são separadas por um espaço duplo: Th*e* Montgomery A*m*phibian Salon! Come luxuriate today!
    • Os parágrafos são separados por uma única nova linha. (A última frase de um parágrafo ainda possui um ou mais caracteres de pontuação no final.)

Outros caracteres não aparecerão na entrada e não precisam ser manipulados.

Seu código pode, a seu critério, esperar que a entrada tenha uma única nova linha à direita.

Formato de saída

O resultado da descriptografia da entrada será uma ou mais frases. Letras em texto sem formatação podem ser qualquer combinação de maiúsculas e minúsculas. As palavras em uma frase devem ser separadas por espaços únicos. As frases devem terminar com um ponto ( .) e ser separadas por um único espaço. Você pode gerar um espaço à direita após a última frase. Sua saída estará toda em uma linha, mas você poderá gerar uma nova linha à direita.

Detalhes diversos

Seu código pode usar qualquer um dos métodos padrão de entrada e saída. Ele deve receber entrada como uma sequência de linhas múltiplas, não como uma lista ou outra estrutura de dados e deve gerar uma sequência de caracteres.

O código mais curto em bytes vence!

Casos de teste

-->
Neurotic Frogs *O*ught To Rel*a*x In *M*ud Baths!
<--
HELLO.

-->
Business standards all*o*w only *adult* amphibians.
<--
HINT.

-->
Rejoice, *a*ll frogs an*d* toads also!  Montgomery Sal*o*n opens up!  Ha*pp*y throng fill*s* street ecstatically!
<--
GOOD JOB PPL.

-->
I like 3.1415926535897.
IM*O*, it's a *b*la*st*, yeah!
<--
ADAM. MAN.

-->
*I*, happily, *th*anks 2 u *e*ditin*g* specific wor*ding*--clarifying a *bit*--betterment :D!
<--
QUARTATA.

-->
Perpendicular l*ou*nging calms.  *A* frog, a m*u*d cap... bliss!  Wallowing g*e*n*e*rates happiness.  Amphibian sp*a* isn't expensive--seventy d*o*llars--cheap!  That'*s* not *a* large e*x*pens*e* from an*y* discerning fr*o*g's money, unlik*e* Super 8.
Ever*y*one--frogs, toad*s*, newts, *a*nd salamanders!  G*e*t a wonderful shiat*s*u, or recei*v*e an other kind.  Masseus*es* are her*e* today!  Invite a fianc*e*e, supervisor, roommate, niece: *all* welcomed!
Y*o*u simply ne*v*er believed these p*o*ssibilitie*s*; they're (I *swear*) absolute truth!  Th*e* Montgomery A*m*phibian Salon!  Come luxuriate today!
<--
MY NAME IS INIGO MONTOYA. YOU KILLED MY FATHER. PREPARE TO DIE.
DLosc
fonte
4
+1 para a entrada da noiva da princesa. Ah, e pela sua habilidade também.
Magic Octopus Urn
É garantido que uma palavra que contenha itálico seja seguida por uma que não contenha itálico?
R. Kap
@ R.Kap Correto. Eu editei a pergunta para esclarecer isso.
DLosc

Respostas:

5

Perl, 72 bytes

#!perl -n
$x=/\*/?2-y/'//c%2:!print/ /?$':chr$x.0+y/'//c+64for/[\w*']+|  /g,' . '

Contando o shebang como um, a entrada é obtida de stdin.

Uso da amostra

$ more in.dat
Neurotic Frogs *O*ught To Rel*a*x In *M*ud Baths!
Perpendicular l*ou*nging calms.  *A* frog, a m*u*d cap... bliss!  Wallowing g*e*n*e*rates happiness.  Amphibian sp*a* isn't expensive--seventy d*o*llars--cheap!  That'*s* not *a* large e*x*pens*e* from an*y* discerning fr*o*g's money, unlik*e* Super 8.
Ever*y*one--frogs, toad*s*, newts, *a*nd salamanders!  G*e*t a wonderful shiat*s*u, or recei*v*e an other kind.  Masseus*es* are her*e* today!  Invite a fianc*e*e, supervisor, roommate, niece: *all* welcomed!
Y*o*u simply ne*v*er believed these p*o*ssibilitie*s*; they're (I *swear*) absolute truth!  Th*e* Montgomery A*m*phibian Salon!  Come luxuriate today!

$ perl neurotic-frogs.pl < in.dat
HELLO. MY NAME IS INIGO MONTOYA. YOU KILLED MY FATHER. PREPARE TO DIE.
primo
fonte
1
Estou concedendo a recompensa a essa resposta, já que é a mais curta no final do período de recompensa, além da minha (na verdade, a única que chegou perto).
DLosc
4

JavaScript (ES6), 172 169 157 150 bytes

Guardado 10 bytes graças a @Neil

x=>x.match(/[\w'*]+|\s+/g).map(y=>y[0]==" "?y[1]:y==`
`?". ":/\*/.test(y,l+=y.match(/\w/g).length)?(l=l%2*10+19,""):l.toString(36,l=9),l=9).join``+"."

Provavelmente pode ser melhorado ainda mais. Saídas em minúsculas.

ETHproductions
fonte
Salve 2 bytes movendo o i=0para o toString.
Neil
Por interesse, tentei consertar esses bugs e cheguei a isso:x=>x.replace(/([\w*']+)[^\w\n*' ]* ?( ?)/g,(_,y,z)=>/\*/.test(y,l=y.replace(/'/g ,"").length)?(i=l%2||2,""):l+i*10+9).toString(36,i=0)+z,i=0).replace(/\n|$/g,". ")
Neil
Parece funcionar da forma atual.
Primo
@ Neil Obrigado. Isso economiza 12 bytes, mas não funciona no último caso de teste. Correção que adiciona 9 para um encurtamento líquido de 3 bytes.
ETHproductions
@ Neil Livrar-se .replacee usar apenas .matchsalvou outros 12 bytes.
ETHproductions
3

Python 2, 238 221 218 214 207 205 bytes

from re import*
def f(x):
 d='';m=0
 for w in split(r"[^\w\d*'~\n]+",sub('  ','~',x))[:-1]:l=len(sub("[*'~\n]",'',w));q='*'in w;d+='. '[w[0]>'}':]*(w[0]in'~\n')+chr(64+l+m)[q:];m=(2-l%2)*10*q
 print d+'.'

Usa muita regex para fazer o processamento. Transformamos o espaço duplo ~e o usamos para processá-lo.~e \nsão tratados especialmente.

O maior ganho de caractere vem do pré-processamento da entrada no for linha; isso definitivamente pode ser ainda mais jogado.

Ideone it!(todos os casos de teste)

Economizou 7 bytes graças ao DLosc!

Cobre
fonte
3

Pip , 65 64 bytes

A pontuação é 62 bytes de código + 2 para os -rssinalizadores.

Flg{O{{(zy*t+#a-1)X!Y'*Na&2-#a%2}MJa@`[\w*]+`}MlRM''^sX2O". "}

Experimente online!

Explicação

A -rbandeira lê todas as linhas de stdin e armazena uma lista delas g. O -ssinalizador define o formato de saída das listas como separado por espaço.

A maneira mais fácil de ler esse código é de fora para:

Flg{...}                   For each line l in g, do:

O{...}MlRM''^sX2O". "      Translate a paragraph into a sentence of plaintext:
       lRM''               Remove apostrophe characters
            ^sX2           Split on "  " into sentences
 {...}M                    Map the below function to each sentence
O                          Output the result list, space-separated, without newline
                O". "      Output that string, without newline

{...}MJa@`[\w*]+`          Translate a sentence into a word of plaintext:
       a@`[\w*]+`          Find all matches of regex (runs of alphanumeric and *)
{...}MJ                    Map the below function to each word and join into string

(zy*t+#a-1)X!Y'*Na&2-#a%2  Translate a word into a letter of plaintext:
      #a-1                 Length of word minus 1
  y*t+                     Add 10 or 20 if y is set (see below)
(z        )                Use that number to index into lowercase alphabet
              '*Na&        Count * characters in word, logical AND with...
                   2-#a%2  2 if word is even length, 1 if odd
             Y             Yank that value into y, to modify the following word
           X!              String multiply the character by not(y)
                           If y is truthy, the word had italics, and we get ""
                           If y is falsy, the word had no italics, and we get a letter
DLosc
fonte
Parece imbatível.
primo
1

Python 2.7, 390 342 341 339 335 bytes:

from re import*
def F(i):
 W=X="";S,s=split,sub;D='[^\w\s*]';Q=lambda c,t:len(s(D,X,c.group()).split()[t])
 for m in S('\W\n',s(D+"*\w*\*\w+\*.*?(?=\s) \w+",lambda v:"a"*([20,10][Q(v,0)%2]+Q(v,1)),s("'",X,s("--"," ",i)))):
  for g in S('\W  ',m):
   for q in S('\W',g):
    W+=chr(64+len(q))
   W+=" "
  W=W[:-1]+". "
 print s("@",X,W)

Recebe entrada no formato:

F('''Multi or Single-lined String''')

Pode ser jogado muito mais, o que farei sempre que tiver a chance.

Repl.it com todos os casos de teste!

Explicação:

Usa o imenso poder dos built-ins de expressão regular do Python para decifrar a entrada. Este é o processo fundamental pelo qual a função passa para cada entrada:

  1. Primeiro, todos --são substituídos por um único espaço e todos os apóstrofos são removidos. Em seguida, todas as palavras que contêm componentes em itálico e a palavra que a segue são correspondidas em uma sequência e substituídas pelo 10 + len(second word)número de as consecutivos, se o comprimento da primeira palavra for odd, e 20 + len(second word)consecutivos, acaso contrário. Isso faz uso da seguinte expressão regular:

    [^\w\s*]*\w*\*\w+\*.*?(?=\s) \w+

    Por exemplo, se tivermos a sentença Perpendicular l*ou*nging calms., l*ou*nging calmsela será substituída por aaaaaaaaaaaaaaaaaaaaaaaaaou 25 as, pois l*ou*ngingpossui um número par de caracteres e calmspossui 5 20+5=25..

  2. Agora, a entrada recém-modificada é dividida em cada sinal de pontuação, seguida por uma nova linha ( \n) para obter os parágrafos; depois, cada parágrafo é dividido em cada pontuação, seguido por 2 espaços para obter as sentenças e, finalmente, cada frase é dividida em palavras. qualquer pontuação, incluindo um espaço. Então, para cada palavra (incluindo as execuções de as consecutivas ), adicionamos a uma sequência Wa letra correspondente ao ponto de código unicode 64(o ponto de código unicode do caractere anterior A, que é @) mais len(word). Em seguida, adicionamos um único espaço a Wuma vez que todas as palavras de uma frase foram esgotadas e, quando todas as frases em um parágrafo foram esgotadas, adicionamos um .seguido por um único espaço.

  3. Finalmente, depois de toda a entrada ter sido processada, Wé emitida stdoutcomo a mensagem decifrada.

R. Kap
fonte
Nitpick menor: spec diz que as sentenças de saída são separadas por espaço único, não duplo (essa alteração também salva um byte). Sugestão inicial de golfe: como você está importando tudo re, use em subvez de str.replace. Sugestão de golfe mais geral: provavelmente é mais eficiente tratar tudo que não é uma palavra ou *pontuação. Economiza em grandes classes de personagens.
DLosc
@DLosc Oh, meu mal. Eu pensei que a especificação era separar frases na saída por 2 espaços. Eu vou consertar isso. Além disso, obrigado pelas sugestões de golfe! Vou ver o que posso fazer com isso.
R. Kap
1

PHP, 196 bytes

<?preg_match_all("#[\w*']+|  |$#m",$_GET[s],$m);foreach($m[0]as$s){if(!$s||$s=="  ")echo!$s?". ":" ";else{$l=$p+64+strlen(str_replace("'","",$s));if(!$p=strstr($s,"*")?20-$l%2*10:0)echo chr($l);}}

Se eu pudesse assumir que existe apenas um apóstrofo no meio de uma palavra 194 bytes

<?preg_match_all("#[\w*]+(<?=')[\w*]+|[\w*]+|  |$#m",$_GET[s],$m);foreach($m[0]as$s){if(!$s||$s=="  ")echo!$s?". ":" ";else{$l=$p+64+strlen($s);if(!$p=strstr($s,"*")?20-$l%2*10:0)echo chr($l);}}
Jörg Hülsermann
fonte
@DLosc Foi codificado %0A como uma função rawurlencode("\n"). Eu prefiro, neste caso, um formulário com um textarea para a entrada e assim o meu site html torna automaticamente para codificar a string
Jörg Hülsermann
@DLosc Suspeito que error_reporting no php.ini esteja ativado. tente 'error_reporting (0);' depois do <?. Um erro pertence a $_GET[s]ele, mas o correto é $_GET["s"]e é melhor declarar e inicializar a variável $p=0;antes do loop. Agora, minha pergunta para você é: Posso assumir que em uma Palavra existe apenas um apóstrofo no meio da Palavra?
Jörg Hülsermann
@DLosc para vários apóstrofes Devo usar minha primeira resposta. O segundo - 2 bytes funciona apenas com um Apostroph no meio, se a palavra.
Jörg Hülsermann
Eu descobri qual era o meu problema - meu servidor não tem tags de abertura curtas ativadas. Mudando para <?phpfuncionou.
DLosc
@ Dalcos Eu nunca uso <?na realidade. Eu uso a tag curta apenas no meu post aqui. Agora eu sei que ele pode ser exibido novamente em uma página em branco.
Jörg Hülsermann
1

PHP, 231 226 228 bytes

para começar

<?preg_match_all("#([\w\*']+)([^\w\*']*)#",$argv[1],$m,2);foreach($m as list(,$a,$b)){$e=strlen(strtr($a,["'"=>""]))+$d;if(!$d=strstr($a,'*')?$e%2*10:0)echo chr($e+64),strpos(".$b","
")?". ":(strpos(".$b","  ")?" ":"");}echo".";

Salvar no arquivo, rund php <scriptpath> <text>. Escape de novas linhas no texto para fazê-lo funcionar com casca.

Titus
fonte
1
Você pode dar algumas instruções sobre como executar isso? Parece que ele lê entradas de $argv[1], mas não sei como essa abordagem funcionará quando as entradas contiverem novas linhas. Tentei "Neurotic Frogs *O*ught To Re*a*x In *M*ud Baths!"como argumento da linha de comando e obtive IFHCHCFF.a saída (assim como um Undefined variable: daviso).
DLosc
@DLosc: Esse aviso (não um aviso) não deve estar lá com as configurações padrão. A maneira mais fácil é anexar <?, salvá-lo em um arquivo e chamá-lo com php <filename> <string>. Talvez eu precise adicionar 2 à contagem de bytes.
Titus
@Titus Se você começar <?, também pode terminar com ?>., para um ganho líquido de 1. FWIW, recebo IFHCMFF.o primeiro caso de teste (usando o PHP 5.5.21 de 64 bits, VC14). Usar $argncom -Ftambém pode ser uma opção.
primo
What I mean is, I don't see how php <filename> <string> is possible when <string> can contain newlines.
DLosc
@DLosc: corrigido o erro. Para as novas linhas: escape delas.
Titus