{Números encaracolados};

33

Na linguagem de programação esotérica Curly, os programas consistem apenas de chaves {}e ponto e vírgula ;. Apesar desse humilde conjunto de ferramentas, o Curly possui literais que podem representar qualquer número inteiro não negativo. No entanto, o formato é um pouco difícil para os não iniciados, então vamos escrever um código para fazer a conversão para nós.

Formato dos números

Os números encaracolados são estruturados de acordo com as seguintes regras:

  1. Adicionar um ponto e vírgula adiciona um ao número.
  2. Um número entre chaves é multiplicado por quatro.
  3. Os grupos de chaves podem ser aninhados, mas não concatenados. O aparelho deve corresponder corretamente.
  4. Ponto e vírgula fora de um conjunto de chaves deve vir depois, não antes.
  5. Para evitar ambiguidade na análise, um número deve sempre começar com uma chave.

Alguns exemplos:

{;;}     2*4 = 8
{{;};};  (1*4+1)*4+1 = 21
{};;;    0*4+3 = 3

(Observe que a regra 5 significa que os números de 0 a 3 devem começar com um par vazio de chaves.)

E alguns exemplos inválidos:

{{;}{;;}}  Curly brace groups side-by-side, not nested
{;}}       Unmatched brace
{;{;}}     Semicolon before curly-brace group
;;;        Number does not start with curly brace

Aqui está uma gramática BNF para números encaracolados:

<number> ::= "{" <inner> "}" <semis>
<inner>  ::= <semis>
           | <number>
<semis>  ::= ";" <semis>
           | ""

Números como {;;;;}(mais de três pontos e vírgulas seguidas) ou {{};}(grupos de chaves vazias desnecessários) são chamados de números Curly incorretos . Eles obedecem à gramática acima e podem ser avaliados da maneira usual, mas também são capazes de representações mais curtas (para os exemplos acima {{;}}e {;}respectivamente).

O desafio

Escreva um programa ou função que insira / receba uma string. Se a string for um número inteiro decimal não negativo, produza / retorne a representação Curly apropriada (ou seja, a mais curta possível) para esse número inteiro. Se a sequência for um número Curly, produza / retorne sua representação decimal.

A entrada pode ser recebida via STDIN, argumento de linha de comando ou parâmetro de função. Ele deve ser uma string; ou seja, você não pode escrever uma função que aceite seqüências de caracteres para números encaracolados, mas números inteiros para números decimais.

A saída pode ser impressa em STDOUT ou retornada da função. Uma função pode retornar um número inteiro quando apropriado ou retornar seqüências de caracteres em todas as situações.

Seu programa não tem que lidar com má entrada (números Curly que quebram as regras de formatação, números de ponto flutuante, inteiros negativos, texto aleatório), e é não necessário para lidar com números Curly impróprias (mas veja abaixo). A entrada consistirá apenas em caracteres ASCII imprimíveis.

Pontuação

O código mais curto em bytes vence. Se o seu programa pode fazer ambos do seguinte:

  1. lidar corretamente com números Curly incorretos e
  2. quando receber um número encaracolado, ignore os caracteres extras que não sejam {};

subtraia 10% da sua pontuação. (A entrada inteira nunca terá caracteres estranhos, mesmo para o bônus.)

Casos de teste

Input       Output
{;;}        8
{{;};};     21
{};;;       3
{{{{;}}};}  260
{}          0
4           {;}
17          {{;}};
1           {};
0           {}
96          {{{;};;}}

Para o bônus:

{};;;;;     5
{{;;;;};;}  72
c{u;r;l}y;! 9
42{;} ;;;;  8

Nota: O Curly ainda não está implementado. Mas se essa pergunta for bem, posso desenvolvê-la ainda mais.

DLosc
fonte
como deve lidar com maiúsculas e minúsculas se você não tiver o número correspondente de parênteses? ou devo assumir que isso nunca aconteceu?
user902383
@ user902383 Você pode assumir que chaves não correspondentes nunca acontecerão.
DLosc
2
Eu estava indo fazer uma solução Retina, mas depois de fazer com que ela lida com uma string Curly (apenas 20 bytes), percebi que ela também precisava lidar com números inteiros positivos -> Curly, então desisti.
mbomb007
@DLosc Sim, não iria ganhar, então não vou gastar o tempo.
Mbomb007
@ mbomb007 Eu quis dizer especificamente sobre esta questão, onde a solução Pyth já é 22% menor que a menor solução CJam e se qualifica para o bônus. Enfim, era uma pergunta retórica tentando dizer: "Não, mas ainda assim poderia ser divertido e angariar alguns votos positivos". Se você não concorda com a parte "divertida", tudo bem.
DLosc

Respostas:

15

Pitão, 35 32 bytes - 10% = 28,8

.x.U+jb`HZ*R\;.[Z2jsz4i/R\;cz\}4

Experimente on-line: Demonstration or Test Suite

editar: como se viu, acidentalmente também posso lidar com números encaracolados impróprios. Não foi planejado. ;-)

Explicação:

Existem duas expressões no código. O primeiro converte um número em um número encaracolado e o segundo converte um número encaracolado em um número regular. .xidentificadores, cuja expressão é impressa. Ele tentará imprimir a primeira expressão. Se houver algum dígito na entrada, a primeira expressão falhará (via Exceção). .xcaptura a exceção e imprime a segunda.

.U+jb`HZ*R\;.[Z2jsz4   # number to Curly Number
                 sz    read the input and converts it to an int
                j  4   convert to base 4
            .[Z2       pad zeros on the left, until length is >= 2
        *R\;           convert each digit to ";"s
                       lets call this list of ";"s Y
.U                     reduce this list, start with b=Y[0], 
                       Z iterates over Y[1], Y[2], ..., 
                       update b in each step with:
   jb`H                   put b into curly brackets
  +    Z                  and append Z

i/R\;cz\}4             # Curly Number to regular number
     cz\}              split the input by "}"
 /R\;                  count the ";"s in each string
i        4             convert this list from base 4 to base 10
Jakube
fonte
2
Mais rápido arma no oeste :( Eu tinha essa solução exata só que eu tinha esquecido que o .[Z2necessário.
orlp
12

CJam, 51 47 44 41 bytes

r_'{-_@={i4bYUe[';f*{{}s@*\+}*}{'}/:,4b}?

Experimente online: exemplo de execução | suíte de teste

Como funciona

r        e# Read a token from STDIN.
_'{-     e# Remove all left curly brackets from a copy of the token.
_@       e# Copy the modified token and rotate the original on top of it.
=        e# Check for equality.
{        e# If the strings were equal:
  i4b    e#   Convert to integer, then to base 4.
  YUe[   e#   Left-pad the resulting array with zeroes to a length of 2.
  ';f*   e#   Replace each digit with that many semicolons.
  {      e#   For each string of semicolons but the first:
    {}s  e#     Push the string "{}".
    @    e#     Rotate the first string or the result of the previous 
         e#     iteration on top of the stack.
    *    e#     Join, i.e., surround the string with curly brackets.
    \+   e#     Append the current string of semicolons to the result.
  }*     e#
}{       e# Else:
  '}/    e#   Split the modified input at right curly brackets.
  :,     e#   Replace each run of 0 to 3 semicolons by its length.
  4b     e#   Convert from base 4 to integer.
}?       e#
Dennis
fonte
7

Python 2, 167 bytes - 10% = 150,3

d=lambda x:("{"+d(x//4)+"}"if x>3 else"")+";"*(x%4)
c=lambda n:"{}"*(int(n)<4)+d(int(n))if n.isdigit()else reduce(lambda x,y:x*4+y,[x.count(";")for x in n.split("}")])

Nesta implementação, cé a função que satisfaz os requisitos. Ele retorna uma string se receber um número inteiro não negativo como entrada ou um número inteiro se receber um número não especificado como entrada.

Greg Hewgill
fonte
6

Python 266 bytes - 10% = 1268,1 326,7 239,4 bytes

Boy não sou um golfista código ainda = /, mas que 10% ajudou -me um monte quando a minha pontuação ainda mais de 1000 era!

Eu tenho uma versão totalmente detalhada (e detalhada) desse código aqui. Ele reconhecerá a validade dos números curvos e fornecerá uma interface em loop para inserir números para teste.

(Comentários apenas para esclarecimentos)

Veja este código em ação

def c(t):                           # curly to int function
 v=0                                #  int value of input
 for a in t:                        #  for each character of input
  if a==';':v+=1                    #   if you find a ';', add one to total
  if a=='}':v*=4                    #   if you find a '}', multiply total by 4
 print v                            #  print value
def i(t):                           # int to curly function
 v=int(t);f,b="{}"if v<4 else"",""  #  get integer value. initialize front (f) and back (b) strings
 while 1:                           #  loop until stopped
  r,v=v%4,int(v/4)                  #   get remainder of v/4 and int value of v/4
  if r>0:b=';'*r+b                  #   if remainder exists, prepend that many ';' to back string
  if v>0:f=f+'{';b='}'+b            #   if remaining value > 4, append '{' to front and prepend '}' to back
  if v<4:b=';'*v+b;break            #   if remaining value < 4, prepend that many ';' to back string and break
 print f+b                          #  print result
t=raw_input()                       # get raw input
try:int(t);i(t)                     # use try block to determine which function to call
except:c(t)                         # 

Agradecimentos a Erik Konstantopoulos por uma grande redução de bytes! Você poderia dizer ... ele realmente tirou um ... byte ... do meu código ... * eu mesmo *

Taylor Lopez
fonte
4
Bem-vindo ao PPCG! Seu código contém muitas printinstruções não necessárias e um comentário, seus nomes de variáveis ​​são muito longos e alguns espaços em branco podem ser eliminados. Também recomendo a leitura de dicas para jogar golfe em Pyrhon .
Dennis
Ótimo recurso, obrigado! Vou fazer as alterações apropriadas neste código e ver até onde ele me leva. Parece que se eu quiser ser alguém neste site, eu preciso aprender CJam ou Pyth, ou escrever minha própria língua, lol.
Taylor Lopez
3
@iAmMortos Não necessariamente . Faça se achar agradável ou fique com o Python, se não. :)
DLosc 15/09/2015
2
Normalmente, o golfe é realizado em três etapas: 1) torne seu programa como você faria normalmente, o mínimo possível (ou seja, sem instruções de depuração, sem necessidade de lidar com entradas inválidas, com um resultado mínimo) 2) remova o máximo possível : espaço em branco , renomeie variáveis ​​( valuepara vetc), 3) faça coisas inteligentes no golfe : esse é o ponto em que você precisa ver o link de Dennis. Estou curioso para ver o quanto você pode reduzir isso!
Sanchises 15/09/2015
1
Nunca recebi uma recepção tão calorosa em uma comunidade. lol, acho que gosto daqui.
Taylor Lopez
4

CJam, 87 bytes 80,1 pontos (89 bytes - bônus de 10%)

Atualize a versão que se qualifica para o bônus enquanto aumenta 2 bytes:

l_'{#){VX@{";{}"#)" _@+\ 4* 4/"S/=~}/;}{i_4<{"{}"\';*}{{4md\_{F'{\+'}+}{;L}?\';*+}:F~}?}?

Experimente online

Primeira vez que usei recursão no CJam! A coisa toda pode parecer meio demorada, mas as duas conversões completamente separadas se somam.

Usei um caso completamente separado para converter números menores que 4 em Curly. Provavelmente é possível evitar isso, mas dobrar o tratamento especial de caso na função recursiva não seria totalmente trivial. E adicionar o extra {}como uma etapa de pós-processamento não parecia realmente melhor, embora eu devesse tentar novamente se for um pouco mais curto.

Reto Koradi
fonte
Sua pontuação não seria 80,1?
PurkkaKoodari
4
@ Pietu1998 Obrigado. Não são apenas as minhas soluções muito tempo, aparentemente, eu também falhar em aritmética básica ...
Reto Koradi
3

C #, 173 - 10% = 155,7 171,0, 177,3

Isso faz nenhuma validação e só procura ;e }personagens. Ele assume que todos os {caracteres vêm antes de qualquer ;caractere. A coisa mais difícil que encontrei foi não inserir um {}no meio de um número Curly.

Quebras de linha e recuos para maior clareza:

string C(string a,int b=0){
    int n;
    if(int.TryParse(a,out n))
        a=(n>=b?"{"+C(""+n/4,4)+"}":"")+";;;".Remove(n%4);
    else
        foreach(int c in a)
            a=""+(c==59?++n:c==125?n*=4:n);
    return a;
}
Mão-E-Comida
fonte
Você pode salvar um byte usando var em vez de char nos loops foreach.
raznagul
@DLosc, desculpe, fiquei confuso com o bônus nº 1. Eu pensei que isso se aplicava à saída e não à entrada.
Hand-E-Food
2

Java 326 bytes - 10% = 294 bytes

É um programa completo escrito em java,

public class a{static String c(long a,int v){if(a==0)return v==0?"{}":"";String x="";for(int i=0;i<a%4;i++)x+=";";return "{"+c(a/4,v+1)+"}"+x;}public static void main(String[]c){try{System.out.println(c(Long.parseLong(c[0]),0));}catch(Exception e){System.out.println(c[0].chars().reduce(0,(a,b)->b==';'?a+1:b=='}'?a*4:a));}}}

Tenho certeza que pode ser muito mais curto, mas agora não posso ter muito tempo para otimizá-lo

user902383
fonte
@DLosc maldito, certo, e pensei que pode ter um bom resultado com java :(
user902383
também: otimização comum em java é evitar a public classe antes
masterX244
substitua public static void main(String[]c){porstatic{
das_j
2

GNU sed, 330 326 - 10% = 293,4

(Eu adicionei um para o uso de -rantes de reivindicar o bônus de 10%; espero que esteja correto)

/;/{
s/[^};]//g
:c
s/(;*)\}/\1\1\1\1/
tc
:d
/;/{
s/;;;;;/v/g
s/vv/x/g
/[;v]/!s/\b/0/2
s/;;/b/g
s/bb/4/
s/b;/3/
s/v;/6/
s/vb/7/
s/v3/8/
s/v4/9/
y/;bvx/125;/
td
}
n
}
:u
s/\b9/;8/
s/\b8/;7/
s/\b7/;6/
s/\b6/;5/
s/\b5/;4/
s/\b4/;3/
s/\b3/;2/
s/\b2/;1/
s/\b1/;0/
s/\b0//
/[^;]/s/;/&&&&&&&&&&/g
tu
:v
s/;;;;/v/g
s/v+/{&}/
y/v/;/
tv

A versão completa mostra que a maioria dos itens acima é conversão entre decimal e unário:

#!/bin/sed -rf

/;/{

# Delete non-Curly characters
s/[^};]//g

# Curly to unary
:c
s/(;*)\}/\1\1\1\1/
tc

# unary to decimal
:d
/;/{
s/;;;;;/v/g
s/vv/x/g
/[;v]/!s/\b/0/2
s/;;/b/g
s/bb/4/
s/b;/3/
s/v;/6/
s/vb/7/
s/v3/8/
s/v4/9/
y/;bvx/125;/
td
}

# done
n

}


# Decimal to unary
:u
s/\b9/;8/
s/\b8/;7/
s/\b7/;6/
s/\b6/;5/
s/\b5/;4/
s/\b4/;3/
s/\b3/;2/
s/\b2/;1/
s/\b1/;0/
s/\b0//
/[^;]/s/;/&&&&&&&&&&/g
tu

# Unary to Curly
:v
s/;;;;/v/g
s/v+/{&}/
y/v/;/
tv
Toby Speight
fonte
Infelizmente, esta pergunta diz explicitamente que o decimal é necessário, e é por isso que eu me incomodei em converter.
Toby Speight
Você está certo, o que é um pouco surpreendente para mim, pois excluir unário não era minha intenção. Bem, acho que é tarde demais para mudar a pergunta agora. Eu reafirmo meu +1, senhor.
DLosc
2

Perl, 183 177

Esta pode não ser a resposta Perl mais curta, mas acho interessante o suficiente postar (entrada $_, saída como valor de retorno):

sub f{if(/}/){s/[{}]/00/g;oct'0b'.s/00(;+)/sprintf'%02b',length$1/ger}else{$_=sprintf'%064b',$_;s/../oct"0b$&"/ge;s/^0+(?!$)//;$_='{'x length.$_;s/\d/'}'.';'x$&/ge;s/\Q{{}/{/r}}

Observamos que Curly é simplesmente uma notação quaternária (base-4). Estamos um pouco prejudicados pela falta de suporte nativo de Perl ao quaternário, mas, felizmente, cada quaternit tem dois bits em binário, e podemos ler e escrever em binário. Portanto, temos o seguinte:

  1. Curly em decimal: converta cada dígito Curly em 2 dígitos binários, concatene e converta em decimal
  2. Decimal para Curly: imprima o número em binário (forçando um número par de dígitos) e converta cada par de bits em Curly.

Versão expandida

sub f
{
    if (/}/) {
        s/[{}]/00/g;     # digits are now 00 00; 00;; 00;;;
                         # and opening braces become harmless leading zeros
        s/00(;+)/sprintf'%02b',length $1/ge;
                         # convert semicolons to binary, leaving zeros alone
        oct "0b$_"       # now to decimal
    } else {
        $_=sprintf'%064b',$_;   # decimal to binary
        s/../oct"0b$&"/ge;      # bit-pair to quaternit
        s/^0+(?!$)//;           #/remove leading zeros
        $_='{'x length.$_;      # prefix enough opening braces
        s/\d/'}'.';'x$&/ge;     #/digit to semicolons
        s/{{}/{/r               # first empty brace, unless $_ <= {};;;
    }
}
Toby Speight
fonte
1

JavaScript (ES6), 95 (105-10%)

f=(n,r='{}')=>-1-n?(n>3?'{'+f(n>>2,'')+'}':r)+';'.repeat(n&3):n.replace(/[;}]/g,c=>c>';'?n*=4:++n,n=0)&&n

Teste a execução do snippet abaixo

f=(n,r='{}')=>-1-n?(n>3?'{'+f(n>>2,'')+'}':r)+';'.repeat(n&3)
:n.replace(/[;}]/g,c=>c>';'?n*=4:++n,n=0)&&n

// Test
function out(x) { O.innerHTML=x+'\n'+O.innerHTML; }

function go() { out(I.value + ' --> ' + f(I.value)) }

;[ 
  ['{;;}', 8]
, ['{{;};};', 21 ]
, ['{};;;', 3 ]
, ['{{{{;}}};}', 260 ]
, ['{}', 0 ]
, [ 4, '{;}' ]
, [ 17, '{{;}};' ]
, [ 1,'{};' ]
, [ 0, '{}' ]
, [ 96, '{{{;};;}}' ]
, ['{};;;;;', 5 ]
, ['{{;;;;};;}' , 72 ]
, ['c{u;r;l}y;!', 9 ]
, ['42{;} ;;;;', 8 ]
].forEach(t => {
  r=f(t[0])
  k=t[1]
  out('Test ' +(r==k?'OK':'Fail')+'\nInput:  '+t[0]+'\nResult: '+r+'\nCheck:  '+k+'\n')
})
Custom test <input id=I><button onclick='go()'>-></button>
<pre id=O></pre>

edc65
fonte
Você poderia postar seu código real? Além disso, sua pontuação é de 94,5.
Erik the Outgolfer
@ErikKonstantopoulos meu código real foi postado na parte superior do snippet de teste. Agora também está no topo da resposta. Sobre a pontuação (que deveria estar em bytes), eu sempre me sinto meio engraçado de medição (ou menos) byte e preferem rouniding-se
edc65
edc65: Sim, mas arredondar é ruim para você! 94,5 <95, portanto, menor pontuação, o que significa que provavelmente supera mais finalizações. Além disso, a "parte superior do snippet" não é o local para mostrar seu código.
Erik the Outgolfer
1

Rubi, 126,9 129,6 (144 - 10%)

Usa recursão para converter decimal em forma ondulada. A remoção da verificação por ignorar caracteres fora de /[;{}]/aumenta a pontuação 0.4no momento.

f=->s{s=~/^\d+$/?(n=s.to_i
"{#{n<1?'':f[(n/4).to_s].gsub('{}','')}}#{?;*(n%4)}"):eval(s.tr("^{;}","").gsub(/./){|c|c<?A?"+1":c>?|?")*4":"+(0"})}
Value Ink
fonte
Está consertado agora. Obrigado por relatar o bug; pontuação foi atualizada.
Valor Ink
1

Perl 5, 154 ( 185 170 Bytes - 10% + 1 penalidade)

$e=$/;if($_=~/{/){s/[^{};]//g;s/;/+1/g;s/{/+4*(/g;s/}/+0)/g;$b=eval}else{$r=$_;$b=$r<4?"{}":"";while($r>0){if($r%4>0){$r--;$e=";$e"}else{$b.="{";$e="}$e";$r/=4}}}$_=$b.$e

Regex e eval resolvem os curlies.
A geração dos curlies é feita de maneira diferente.

Teste

O arquivo de teste contém também os casos de bônus

$ cat curlytestcases.txt
{}
{};
{};;
{};;;
{;;}
{{;};};
{{{{;}}};}
0
1
2
3
4
17
96
{};;;;;
42{;} ;;;;
c{u;r;l}y;!
{{;;;;};;}

$ cat curlytestcases.txt |perl -p curlies.pl
0
1
2
3
8
21
260
{}
{};
{};;
{};;;
{;}
{{;}};
{{{;};;}}
5
8
9
72
LukStorms
fonte
Adicionada a penalidade -1 para -p. O $ b = $ r <2? "{}": ""; foi adicionado com exceção de 0 e 1. {} ;;; é a entrada no teste.
LukStorms
Precisava de algum tempo para testá-lo. Está consertado agora. :)
LukStorms
Eu acho que a penalidade +1 vem depois do bônus de -10%.
Erik the Outgolfer
Observação interessante. Não tenho certeza se é agora, mas faz sentido, então eu mudei de qualquer maneira. Não que isso mude a pontuação final.
LukStorms
1

Retina , 69 64 bytes

+`{(;*)}
$1$1$1$1
^\d+|^(;*)
$*;$.1
+`(;+)\1\1\1
{$1}
^;|^$
{}$&

Experimente o Conjunto de Testes


Explicação

+`{(;*)}
$1$1$1$1

Decomponha as chaves mais internas para apenas ;s. Faça um loop até não ter mais aparelhos.

^\d+|^(;*)
$*;$.1

Converter entre decimal e unário ;

+`(;+)\1\1\1
{$1}

Encontre a execução mais longa de ;um múltiplo de 4 e aninhe-a entre chaves, faça um loop até que não exista mais execuções de 4+.

^;|^$
{}$&

Se o número encaracolado resultante começar com ;ou for uma string vazia, adicione {}na frente.

TwiNight
fonte
1

Python 2 , 157 bytes -10% = 141,3

lambda n:'{}'*(int(n)<4)+g(int(n))if n.isdigit()else sum((v==';')*4**n.count('}',i)for i,v in enumerate(n))
g=lambda n:'{%s}'%g(n/4)+';'*(n%4)if n>3else';'*n

Experimente online!

Uma resposta Python 2 mais eficiente que lida com os casos de bônus. Não queria necro posts mortos com isso como um comentário, então aqui está.

Funciona de dentro para dentro em números ondulados, adicionando 4 ^ (o número de colchetes finais deixados na cadeia) à soma de cada ponto e vírgula encontrado. Se a sequência for um número, ela cria recursivamente o número encaracolado da mesma maneira que a gramática fornecida.

Arnold Palmer
fonte
Isso é estranho. Eu até tive casos de teste lá para números menores que 2. Corrigidos para +5 bytes no total.
Arnold Palmer
@DLosc Eu juro que normalmente não sou tão ruim assim. Corrigido e jogado um pouco para torná-lo um pouco mais competitivo.
21917 Arnold Palmer