{Фигурные числа};

33

На эзотерическом языке программирования Curly программы состоят исключительно из фигурных скобок {}и точек с запятой ;. Несмотря на этот скромный набор инструментов, в Curly есть литералы, которые могут представлять любое неотрицательное целое число. Тем не менее, этот формат немного сложен для чтения непосвященными, поэтому давайте напишем некоторый код, чтобы сделать преобразование для нас.

Формат чисел

Фигурные числа структурированы по следующим правилам:

  1. Добавление точки с запятой добавляет один к числу.
  2. Число, заключенное в фигурные скобки, умножается на четыре.
  3. Группы фигурных скобок могут быть вложенными, но не сцепленными. Брекеты должны соответствовать друг другу.
  4. Точки с запятой вне набора фигурных скобок должны появляться позже, а не раньше.
  5. Чтобы избежать двусмысленности при разборе, число всегда должно начинаться с фигурной скобки.

Некоторые примеры:

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

(Обратите внимание, что правило 5 означает, что числа от 0 до 3 должны начинаться с пустой пары фигурных скобок.)

И несколько неверных примеров:

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

Вот грамматика BNF для фигурных чисел:

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

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

Соревнование

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

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

Вывод может быть распечатан на STDOUT или возвращен из функции. Функция может возвращать целое число, когда это уместно, или она может возвращать строки во всех ситуациях.

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

счет

Самый короткий код в байтах побеждает. Если ваша программа может выполнять оба следующих действия:

  1. правильно обрабатывать неправильные фигурные числа, и
  2. когда дано фигурное число, игнорируйте любые дополнительные символы, которые не являются {};

затем вычтите 10% от вашей оценки. (Целочисленный ввод никогда не будет иметь посторонних символов, даже для бонуса.)

Контрольные примеры

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

Для бонуса:

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

Примечание: Curly еще не реализован. Но если этот вопрос хорошо, я могу развивать его дальше.

DLosc
источник
как он должен обрабатывать регистр, если у вас не совпадает число скобок? или я должен предположить, что это никогда не случится?
user902383 14.09.15
@ user902383 Можно предположить, что несовпадающие фигурные скобки никогда не появятся.
DLosc
2
Я собирался сделать решение Retina, но после того, как он обработал строку Curly (всего 20 байт), я понял, что она также должна обрабатывать положительные целые числа -> Curly, поэтому я сдался.
mbomb007
@DLosc Да, это не победит, поэтому я не собираюсь тратить время.
mbomb007
@ mbomb007 Я имел в виду именно этот вопрос, когда решение Pyth уже на 22% короче, чем самое короткое решение CJam, и имеет право на бонус. Во всяком случае, это был риторический вопрос, пытавшийся сказать: «Нет, но это все равно может быть забавным и вызвать некоторые положительные отзывы». Если вы не согласны с «забавной» частью, это нормально.
DLosc

Ответы:

15

Pyth, 35 32 байта - 10% = 28,8

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

Попробуйте онлайн: демонстрация или тестовый набор

редактировать: как оказалось, я случайно могу также обрабатывать неправильные вьющиеся числа. Не было запланировано вообще. ;-)

Объяснение:

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

.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
источник
2
Самое быстрое оружие на западе :( У меня было это точное решение, кроме того, что я забыл, что оно .[Z2необходимо.
orlp
12

CJam, 51 47 44 41 байт

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

Попробуйте онлайн: пример прогона | тестирование

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

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#
Деннис
источник
7

Python 2, 167 байт - 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("}")])

В этой реализации cесть функция, которая удовлетворяет требованиям. Возвращает строку, если в качестве входных данных указано неотрицательное целое число, или целое число, если в качестве входных данных указано фигурное число

Грег Хьюгилл
источник
6

Python 266 байтов - 10% = 1268,1 326,7 239,4 байта

Мальчик я не код гольфист еще = /, но 10% помогли мне оттуда много , когда мой счет был еще более 1000!

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

(Комментарии только для пояснения)

Смотрите этот код в действии

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)                         # 

Спасибо Эрику Константопулосу за значительное сокращение байтов! Вы могли бы сказать ... он действительно взял ... байт ... из моего кода ... * себя пять *

Тейлор Лопес
источник
4
Добро пожаловать в PPCG! Ваш код содержит много необязательных printоператоров и комментариев, имена переменных слишком длинные, и некоторые пробелы могут быть устранены. Я также рекомендую прочитать Советы по игре в гольф в Пироне .
Деннис
Отличный ресурс, спасибо! Я внесу соответствующие изменения в этот код и посмотрю, как далеко он меня зашёл. Похоже, что если я хочу быть кем-то на этом сайте, мне нужно либо изучать CJam или Pyth, либо писать на своем собственном языке lol.
Тейлор Лопес
3
@iAmMortos Не обязательно . Делайте, если вам это нравится, или придерживайтесь Python, если нет. :)
DLosc 15.09.15
2
Как правило, игра в гольф выполняется в три этапа: 1) сделать вашу программу, как вы это делаете обычно, как можно минимально (т. Е. Нет отладочных операторов, нет необходимости обрабатывать неверный ввод, минимальный вывод) 2) удалить как можно больше : пробел , переименовывать переменные ( valueв и vт. д.), 3) делать умные вещи в гольф : это точка, где вам нужно взглянуть на ссылку Денниса. Мне любопытно посмотреть, сколько вы можете сократить это!
Санчиз
1
Никогда я не получал такой теплый прием в сообществе. лол, я думаю, мне здесь нравится.
Тейлор Лопес
4

CJam, 87 байт, 80,1 балла (89 байт - бонус 10%)

Обновите версию, которая дает право на бонус при увеличении на 2 байта:

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

Попробуйте онлайн

Впервые я использовал рекурсию в CJam! Все это может выглядеть довольно долго, но два совершенно разных преобразования суммируются.

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

Рето Коради
источник
Не будет ли ваш счет 80,1?
PurkkaKoodari
4
@ Pietu1998 Спасибо. Мало того, что мои решения слишком длинные, по-видимому, я также
терплю
3

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

Это не делает проверки и только ищет ;и }символы. Предполагается, что все {символы предшествуют любым ;персонажам. Самое сложное, что я обнаружил, - не вставлять {}в середину фигурного числа.

Разрывы строк и отступы для ясности:

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;
}
Hand-E-Food
источник
Вы можете сохранить один байт, используя var вместо char в циклах foreach.
Разнагул
@DLosc, извините, меня смутил бонус # 1. Я думал, что это относится к выводу, а не к вводу
Hand-E-Food
2

Java 326 байтов - 10% = 294 байта

Это полная программа, написанная на 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));}}}

Я уверен, что это может быть намного короче, но у меня не может быть много времени, чтобы оптимизировать это

user902383
источник
@DLosc Черт, да, и думал, что я могу иметь хороший результат с Java :(
user902383
также: общая оптимизация на java состоит в том, чтобы избежать public предшествующего класса
masterX244
заменить public static void main(String[]c){сstatic{
das_j
2

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

(Я добавил один для использования, -rпрежде чем требовать бонус 10%; я надеюсь, что это правильно)

/;/{
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

Полная версия показывает, что большинство из перечисленного выше является преобразованием между десятичным и унарным:

#!/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
Тоби Спейт
источник
К сожалению, этот вопрос явно говорит о том, что требуется десятичная дробь, поэтому я обеспокоен преобразованием.
Тоби Спейт
Вы правы, что немного удивляет меня, так как исключение унарного не было моим намерением. Ну что ж, думаю, уже слишком поздно менять вопрос. Я подтверждаю мой +1, сэр.
DLosc
2

Perl, 183 177

Это может быть не самый короткий ответ Perl, но я думаю, что это достаточно интересно, чтобы публиковать (ввод $_, вывод в качестве возвращаемого значения):

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

Мы видим, что Curly является просто четвертичной (base-4) нотацией. Нам немного мешает отсутствие в Perl встроенной поддержки четвертичного кода, но, к счастью, каждый кватернит состоит из двух битов в двоичном коде, и мы можем читать и записывать двоичный код. Итак, у нас есть следующее:

  1. Curly to decimal: преобразовать каждую фигурную цифру в 2 двоичных, объединить и преобразовать в десятичную
  2. Десятичное число в курчавое: выведите число в двоичном виде (форсируя четное число цифр), затем преобразуйте каждую битовую пару в фигурное.

Расширенная версия

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 $_ <= {};;;
    }
}
Тоби Спейт
источник
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

Тест бегущего фрагмента ниже

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
источник
Не могли бы вы опубликовать свой фактический код? Кроме того, ваш счет 94,5.
Эрик Outgolfer
@ErikKonstantopoulos мой фактический код был размещен в верхней части тестового фрагмента. Теперь это тоже на вершине ответа. Что касается счета (который должен быть в байтах), я всегда чувствую себя смешно, измеряя половину (или меньше) байта, и предпочитаю округлять вверх
edc65
edc65: Да, но округление плохо для тебя! 94,5 <95, таким образом, меньший балл, что означает, что он, вероятно, побеждает больше представлений. Кроме того, «верхняя часть фрагмента» не место для показа вашего кода.
Эрик Outgolfer
1

Рубин 126,9 129,6 (144 - 10%)

Использует рекурсию для преобразования десятичной формы в фигурную. Снятие флажка для игнорирования символов за пределами /[;{}]/увеличивает счет 0.4на данный момент.

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"})}
Значение чернил
источник
Это сейчас исправлено. Спасибо за сообщение об ошибке; оценка была обновлена.
Чернила стоимости
1

Perl 5, 154 ( 185 170 байт - 10% + 1 штраф)

$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 & Eval разрешить кудри.
Генерация керли делается по-другому.

Тест

Тестовый файл содержит также бонусные случаи

$ 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
источник
Добавлен штраф -1 для -p. $ B = $ r <2? "{}": ""; был добавлен за исключением 0 и 1. {} ;;; это вход в тесте.
LukStorms
Потребовалось некоторое время, чтобы проверить это. Это сейчас исправлено. :)
LukStorms
Я думаю, что +1 штраф приходит после бонуса -10%.
Эрик Outgolfer
Интересное наблюдение. Не уверен, что так и должно быть, но это имеет смысл, так что я все равно изменил. Не то чтобы это меняет итоговый счет.
LukStorms
1

Сетчатка , 69 64 байта

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

Попробуйте Test Suite


объяснение

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

Разложить внутренние скобки только на ;s. Цикл, пока нет больше брекетов.

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

Преобразовать между десятичной и унарной ;

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

Найдите самый длинный пробег ;, кратный 4, и вложите в фигурные скобки, пока не закончится цикл 4+.

^;|^$
{}$&

Если полученное вьющееся число начинается с ;или является пустой строкой, добавьте {}перед.

TwiNight
источник
1

Python 2 , 157 байт -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

Попробуйте онлайн!

Более удачный ответ Python 2, который обрабатывает бонусные случаи. Не хотел, чтобы это были комментарии, так что вот оно.

Он работает изнутри на фигурных числах, добавляя 4 ^ (число конечных фигурных скобок, оставшихся в строке) к сумме для каждой найденной точки с запятой. Если строка является числом, то она рекурсивно создает фигурное число так же, как предоставленная грамматика.

Арнольд Палмер
источник
Это неловко. У меня даже были тестовые случаи для чисел меньше 2. Исправлено для +5 байт.
Арнольд Палмер
@DLosc Клянусь, я обычно не такой плохой. Исправлено, и гольф немного, чтобы сделать его немного более конкурентоспособным.
Арнольд Палмер