Кипу - это древнее устройство, используемое инками в доколумбовскую эпоху для записи чисел в базовой десятипозиционной системе узлов на шнуре, которая работает следующим образом:
Каждая группа узлов является цифрой, и существует три основных типа узлов: простые накладные узлы; «длинные узлы», состоящие из верхнего узла с одним или несколькими дополнительными витками; и восьмерка узлов.
- Степени десяти показаны позицией вдоль струны, и эта позиция выровнена между последовательными нитями.
- Цифры в позициях для 10 и более степеней представлены группами простых узлов (например, 40 - это четыре простых узла подряд в позиции «десятки»).
- Цифры в позиции "единицы" представлены длинными узлами (например, 4 - узел с четырьмя поворотами). Из-за того, как узлы связаны, цифра 1 не может быть показана таким образом и представлена в этом положении узлом в виде восьмерки.
- Ноль представлен отсутствием узла в соответствующей позиции.
Детали
Для этой задачи каждая ветвь кипу представляет собой одно число (хотя, как говорится в статье в Википедии, вы можете представить много чисел на одной цепочке, в этой задаче мы не будем).
Сучки
Каждый узел будет представлен одним символом ASCII.
.
представляет собой простой узел:
представляет один оборот длинного узла8
представляет собой узел восьмерки|
представляет отсутствие узла, а также разделитель между цифрами.
Построение Кипуса
Quipu построены в соответствии с этими правилами.
- Нити идут сверху вниз в порядке убывания положения (как, например, цифра единиц будет на нижнем конце жилы). Цифры вдоль нити разделяются символом (
|
). - Степень 10, которую представляет цифра, определяется ее положением вдоль цепи таким же образом, как сила 10 цифры будет рассчитываться с использованием ее индекса в числе с нашей системой счисления. То есть,
24
где a2
в десятках и a4
в единицах измерения, будут представлены двумя узлами, разделителем (|
), а затем четырьмя узлами. - Цифры в том же положении выровнены по направлению к нижней части жилы. Если у одной цифры в позиции будет меньше узлов, чем у других цифр других чисел в той же позиции, отсутствие этих узлов представляется как (
|
). - Последовательные простые узлы (
.
) представляют значение в их положении. - Каждая цифра представлена как минимум 1 символом. Когда значение цифры равно 0 для всех чисел в кипе, оно представлено отсутствием узла (
|
). - Место подразделений обрабатывается специально. Единица в единицах измерения представлена узлом восьмерки (
8
). Значение двух или более в месте единиц измерения представлено последовательными длинными узлами (:
). - Когда цифра единиц равна 0 для всех чисел в кипе, отсутствие узла не печатается, но конечный разделитель для цифры десятков сохраняется.
- После цифры единицы нет разделителя.
правила
- Ввод будет состоять из непустого списка неотрицательных целых чисел, которые могут быть получены любым из методов ввода по умолчанию . Вы можете предположить, что все эти числа меньше или равны
2147483647
или2^31-1
. Несмотря на то, что контрольные примеры разделены пробелами, ваш формат ввода может разделять входные данные любым удобным для вашего языка способом, будь то разделенный запятыми, разделитель новой строки, массив и т. Д. - Выход состоит из одного Quipu, построенного в соответствии с правилами, описанными выше. Вывод может быть дан через любой из способов вывода по умолчанию .
- Ваш код должен быть программой или функцией, хотя он не обязательно должен быть именованной функцией.
- Узлы занимают некоторое время, чтобы сэкономить время, ваш код должен быть максимально коротким.
Как всегда, если проблема неясна, пожалуйста, дайте мне знать. Удачи и хорошего гольфа!
Примеры
Входные данные:
5 3 1 0
Выход:
:|||
:|||
::||
::||
::8|
Входные данные:
50 30 10 0
Выход:
.|||
.|||
..||
..||
...|
||||
Входные данные:
330
Выход:
.
.
.
|
.
.
.
|
Входные данные:
204 1
Выход:
.|
.|
||
||
||
:|
:|
:|
:8
Входные данные:
201 0 100 222
Выход:
.||.
.|..
||||
|||.
|||.
||||
|||:
8||:
Входные данные:
1073741823 2147483647
Выход:
|.
..
||
|.
||
.|
.|
.|
..
..
..
..
||
|.
|.
|.
|.
..
..
..
||
.|
.|
.|
..
..
..
..
||
|.
|.
|.
|.
..
..
..
..
||
|.
|.
..
||
.|
.|
..
..
..
..
..
..
||
|.
|.
..
..
||
|:
|:
|:
|:
::
::
::
Входные данные:
0
Выход:
|
Ответы:
Pyth, 64 байта
Попробуйте онлайн!
Как это работает
источник
8
. Фактически, это только8
узел, когда последняя цифра равна 1 (см. Правило 6). Вы конвертируете все последние узлы, и это не соответствует спецификации. Кроме того, ваша пробная версия онлайн! ссылка имеет код, отличный от того, который выложен здесь, по всей видимостиНе читается ,
31833001 байтЭто было веселое испытание - работать и выключать между рождественскими праздниками. Спасибо за публикацию! Игра в гольф была интересной, потому что спецификация полна исключений и особых случаев, которые требовали много условий. Кроме того, хотя в этот раз мне не нужно было выполнять преобразование в десятичное число и обратно, мне нужна была своего рода функция «max» для определения наибольшего числа цифр в каждом числе и наибольшего значения цифр в каждом месте.
Первая версия этого была 4844 байта, просто чтобы дать вам представление о том, сколько я играл в гольф.
Программа ожидает ввод в виде списка целых чисел через запятую . Без пробелов и переносов. Их использование приведет к неопределенному поведению.
объяснение
Я расскажу вам, как работает программа, и покажу, как она обрабатывает определенные данные
202,100,1
.В начале мы создадим несколько значений, которые нам понадобятся позже - в основном это ASCII-коды символов, которые мы будем выводить.
Как видите,
'8'
и'.'
уже есть в наличии.'|'
однако в действительности это 124, а не 14. Мы используем цикл while, чтобы дважды добавить к нему временное значение в слоте № 1, чтобы получить 124 (что составляет 14 + 55 × 2, потому что цикл while работает для 56−1 = 55 итерации). Это экономит некоторые байты, потому что большие целочисленные литералы, такие как 124, действительно длинные. На следующей диаграмме я показываю расположение каждой переменной, используемой программой.Далее мы хотим ввести все символы и сохранить их на ленте, начиная с ячейки # 12 ( p - это текущий указатель для этого). В то же время, мы хотим знать, какой длины самое длинное число (сколько цифр). Чтобы достичь этого, мы сохраняем промежуточную сумму в унарном порядке, идущем влево, начиная с ячейки # -1 (мы используем q в качестве бегущего указателя). После первого ввода числа (
202
) лента теперь выглядит так:Вы заметите, что числа отключены на 4. Хорошо, когда мы впервые вводим их, они являются их значениями ASCII, поэтому они «выключены» на 48 и запятая составляет 44. Для каждого символа мы копируем 46 из
'.'
в r и затем вычитаем его с помощью цикла while (который вычитает 45), а затем добавляем 1. Мы делаем это так, что запятая (наш разделитель) равна 0, поэтому мы можем использовать условное выражение для его распознавания.Кроме того, вы заметили, что мы оставляем ячейку № 11 в 0. Нам нужно это, чтобы распознать границу первого числа.
Следующим символом будет запятая, поэтому мы храним 0 в # 15, но, конечно, на этот раз мы не продвигаем q . Вместо этого мы устанавливаем q обратно в 0 и начинаем «перезаписывать» те 1, которые мы уже разместили.
После того, как все оставшиеся символы обработаны, мы получаем это:
Как вы можете видеть, 1s, написанные q, теперь указывают (в унарном виде) длину самого длинного числа.
Теперь мы используем цикл while для перемещения q в крайнее левое положение, а затем помещаем туда другой указатель, который я назову r2 . Цель r2 станет ясна позже.
На этом этапе позвольте мне уточнить терминологию, которую я буду использовать на протяжении всего этого.
Теперь вернемся к нашему обычному программированию. Вся остальная часть программы представляет собой большой цикл, который перемещает q вперед, пока не достигнет ячейки # 0. Каждая из ячеек на этом пути представляет собой место, где ячейки расположены справа, и q будет начинаться с самого значительного. В нашем примере это сотни мест.
Мы продолжаем, увеличивая ячейку q на (то есть * q ).
Сейчас мы находимся на «этапе 2» для сотен мест. На этом этапе мы выясним, какая самая большая цифра среди всех цифр в сотнях мест. Для этого мы используем тот же трюк с одинарным счетом, за исключением того, что на этот раз указатель называется r, а указатель r2 отмечает его начальную позицию, в которую нам нужно сбрасывать его каждый раз, когда мы переходим к следующему числу.
Начнем с первого номера. Мы начинаем с установки p в 11 (жестко заданная начальная позиция всех чисел). Затем мы используем цикл while, чтобы найти конец числа и устанавливаем p2, чтобы обозначить позицию. В то же время мы также устанавливаем q2 в 0:
Не отвлекайся на то, что q2 отвлекайтесь указывает на переменную. У нас там нет заполнения пустой ячейки, потому что мы можем обнаружить ячейку № 0 просто потому, что она равна нулю.
Далее, мы проходим текущее число, уменьшая p и q2 вместе, пока * p не станет равным нулю. В каждом месте значение * q2 говорит нам, что нам нужно делать. 1 означает «ничего не делать», поэтому мы продолжаем. В конце концов мы сталкиваемся с 2 в ячейке # −3. Каждый раз, когда * q2 не равно 1, q2 всегда равно q .
Как я уже говорил, этап 2 - «определить самую большую цифру в этом месте». Таким образом, мы устанавливаем r в r2 , используем цикл while для уменьшения * p и перемещаем r влево и заполняем ленту 1с, а затем используем другой цикл while для перемещения r назад вправо и увеличиваем * p еще раз, чтобы восстановить значение. Помните, что каждый цикл while выполняется на одну итерацию меньше, чем значение, на котором мы его используем; из-за этого число записанных единиц будет на 3 больше (а не на 4) больше, чем значение цифры, а окончательное значение, сохраненное в * p, будет на 2 больше. Таким образом, это эффективно уменьшилось * p на 2.
После этого мы устанавливаем p в значение p2, а затем делаем все это снова. Во второй раз установите q2 в 0, найдите конец числа, сдвинув p вправо, а затем пройдитесь по цифрам этого числа, уменьшив p и q2 вместе. Еще раз мы встретим 2 в ячейке # −3 и напишем, что много 1s осталось от * r .
В случае третьего числа мы ничего не делаем, потому что у него нет места в сотне (поэтому q2 никогда не достигает q ), но это нормально, потому что это не влияет на вычисление максимального значения цифры.
Мы также устанавливаем ячейку * (г - 4) , которую я здесь пометил немаркированной стрелкой, равной 1 (даже если она уже равна 1). Я не собираюсь говорить вам, почему, но, может быть, вы уже догадались?
Следующее увеличение * q приводит нас к этапу 3, который «вычитает максимальную цифру из всех цифр в текущем месте». Как и прежде, мы сбрасываем p на 11 и q2 на 0, а затем просматриваем все числа, как мы делали на предыдущем этапе; за исключением этого времени, * q = 3 вместо 2. Каждый раз, когда q2 встречает q и p находится в сотнях мест, мы используем цикл while для уменьшения * p столько раз, сколько 1s в блоке слева от * r2 (5 в нашем примере) с использованием гв качестве бегущего указателя. Мы фактически уменьшаем его еще раз, чтобы самая большая цифра заканчивалась на -2, по причине, которая станет ясна позже:
После того как мы обработали все числа, мы находимся в конце этапа 3. Здесь мы выполняем две особые вещи.
Теперь вы понимаете, что мы продолжаем изучать числа, находим текущее место (обозначенное не-1 значением * q ) внутри каждого числа и делаем что-то в зависимости от значения * q . Мы видим, что * q сначала увеличивается до 2 (= вычислить максимальное значение цифры), затем до 3 (вычитать максимальное значение цифры из каждой цифры в этом месте), а затем мы вычитаем его, чтобы сделать его отрицательным. Оттуда он будет продолжать расти, пока не достигнет 1, восстановив, таким образом, значение, которое означает «ничего не делать». В этот момент мы переходим к следующему месту.
Теперь, когда * q отрицательно, мы выводим. * q имеет точно правильное значение, поэтому мы выведем правильное количество строк символов, прежде чем оно достигнет 1; если самая большая цифра - 2, нам нужно вывести 3 строки. Давайте посмотрим, что происходит при каждом значении * q :
'.'
(точка) или':'
(двоеточие). Мы решаем, что, посмотрев на q : если это -1, мы в одном месте, поэтому выведите a':'
(который мы вычисляем как'8'
+2), в противном случае a'.'
.'|'
(трубу), а затем увеличиваем значение. Таким образом, он достигнет -2 в нужном месте, а затем мы выводим'.'
s /':'
s для остальной части этой цифры.'|'
(но только если out не равен нулю, потому что в противном случае мы все еще находимся на стадии 2 или 3).'.'
(а третье выдает a,'|'
как и раньше).'|'
s независимо от * p ». Таким образом, мы получаем отступ между цифрами.Теперь мы увеличиваем q, чтобы перейти к следующему месту, десятку, и увеличиваем * q там. В начале этапа 2 лента выглядит так:
Затем мы выполняем этап 2, как и раньше. Помните, что это эффективно вычитает 2 из каждой цифры в этом месте, а также оставляет унарное число слева от * r2, указывающее максимальную цифру. Мы оставляем прежний унарный номер в покое и просто продолжаем расширять ленту влево; это будет стоить только лишнего дополнительного кода для «очистки». Когда мы закончим и увеличим * q , в начале этапа 3 лента будет:
На самом деле, это ложь. Помните ранее, где я сказал, что мы установили * (r - 4) в 1, и я не сказал вам, почему? Теперь я расскажу почему. Это для таких случаев, как этот, где наибольшая цифра фактически равна 0, что означает, что все цифры в этом месте равны 0. Установка * (r - 4) , обозначенная стрелкой без метки выше, в 1 увеличивает унарное число на 1, но только в этом особом случае. Таким образом, мы притворяемся, что наибольшая цифра была 1, что означает, что мы выведем еще одну строку.
После этапа 3 (вычесть максимальную цифру из всех цифр в текущем месте), включая дополнительный шаг, который делает * q отрицательным, лента выглядит следующим образом. В прошлый раз самая большая цифра была представлена -2 в блоке * p , но на этот раз они все -3, потому что все они фактически равны нулю, но мы притворяемся, что максимальная цифра была 1.
Теперь давайте посмотрим, что происходит по мере продвижения * q к 1:
'|'
s и увеличиваем их.'|'
потому что это то, что мы всегда делаем, когда * q = 0, независимо от * p .Таким образом, мы получаем два ряда труб.
Наконец, мы перемещаем * q на свое место. Это становится интересным, потому что нам нужно вывести
':'
s, если фактическая цифра не равна 1, а'8'
если - 1. Посмотрим, как работает программа. Сначала мы увеличиваем * q, чтобы начать этап 2:После этапа 2 («рассчитать максимальное значение цифры») у нас остается следующее:
После этапа 3 («вычесть максимальное значение цифры из всех цифр в текущем месте») лента выглядит следующим образом:
Теперь давайте рассмотрим каждую итерацию * q по очереди:
':'
(а не a,'.'
потому что q = -1).'|'
и увеличьте.'|'
. Однако на этот раз вместо инкремента срабатывает особый случай. Только если мы выводим последнее место ( q = −1), и мы находимся во втором последнем ряду для этого ( * q = −2), а цифра фактически равна 1 ( * p = −3) , то вместо того , чтобы его приращение -2, мы устанавливаем его в -1. Другими словами, мы используем -1 как специальное значение, чтобы указать, что на следующей итерации нам нужно будет выводить'8'
вместо':'
.':'
.'|'
. Специальное условие не срабатывает, потому что * q больше не равен -2. Поэтому прирост.'8'
.'|'
s, но в особом случае, когда мы находимся в одном месте ( q = −1), мы пропускаем это.После этого q увеличивается до 0, и большой цикл while заканчивается.
Теперь вы знаете, как работает вход, как
202,100,1
. Однако есть еще один особый случай, который мы до сих пор не раскрыли. Возможно, вы помните, что в то время как мы обрабатывали последнее место, когда * p было -3, мы установили его на -1 для1
(вместо увеличения до -2), чтобы следующая итерация выводила'8'
вместо него. Это работает только потому, что у нас есть итерация, в которой * p равно −3, и мы принимаем решение относительно того, увеличивать его или устанавливать на -1. У нас нет такой итерации, если все цифры в одном месте равны 0 или 1. В таком случае все значения * p для 1 будут начинаться с -2; нет возможности решить установить его на -1а не увеличивать его с −3 . Из-за этого в Стадии 3 есть еще одно условие особого случая («вычитать максимальную цифру из каждой цифры в текущем месте»). Я утверждал, что после вычитания максимального значения цифры из каждой цифры (в этот момент максимальная цифра равна -1), мы просто уменьшаем ее еще раз, но на самом деле есть условие, которое выглядит следующим образом:Если цифра, на которую мы смотрим, равна максимальной цифре в этом месте ( * p = −1), и это место соответствует единице ( q = −1), а максимальная цифра равна 1 ( * (r +) 5) = 0, т. Е. Унарный блок в самом левом углу имеет длину всего 5 ячеек), только тогда мы оставляем * p на -1, чтобы указать, что единственная итерация вывода должна выводить an
'8'
. Во всех остальных случаях мы уменьшаем его еще раз.Выполнено. С Новым Годом!
Изменить 1 (3183 → 3001): немного счастливого нового года в гольф! Мне удалось полностью избавиться от переменных p2 и r2 ! Теперь p мчится взад и вперед, чтобы найти начало и конец чисел, но в коде оно кажется короче. Я также пытался избавиться от q2 , но так не смог сделать код короче.
Я также нашел еще несколько мест, где я мог бы применять типичные нечитаемые трюки в гольфе, такие как повторное использование последнего значения цикла while. Чтобы дать вам пример, а не
Я могу сохранить
'""""
(сделать первое, затем второе) и'"""
(константа 1), написав это так, какКонечно, это работает, только если я знаю, что цикл while будет выполняться как минимум одну итерацию, но если это так, его возвращаемое значение будет pd, поэтому я могу использовать его как условие для if.
источник
Javascript (ES6)
750744690604498346245234 байтаЯ новичок в PPCG и подумал, что могу попробовать, думая, что это довольно просто. Мальчик был я не прав! Я работал над этим некоторое время, и у меня есть много занятий гольфом ...
Предложения приветствуются! - хотя разобраться в этом не будет легкой задачей.
Выходные канаты, когда вход представляет собой массив чисел (например:)
[204, 1]
.объяснение
пример
Ввод: Массив чисел: Ввод
[4,8,15,16,23,42]
:
источник
Python 3,
624598595574561535532527525426345328324294288286283280267265255251245238235234230228 байтовНу, так как на этот вопрос требовался ответ, я предоставил здесь один, где ввод должен быть строкой с разделенными пробелами числами, например
"204 1"
. Мальчик, это долго. Любые предложения по игре в гольф (или лучшие ответы) приветствуются.Редактировать: байты сохраняются путем смешивания табуляции и пробелов.
Редактировать: я сохранил много байтов, изменив способ получения цифр числа (составьте список из строки числа, дополненной нулями, затем в теле кода перенесите, чтобы получить сотни цифр, десять цифр и т. Д. .)
Изменить: И я сохранил еще немного, включив этот последний
:8
цикл в основной цикл Quipu.Теперь, если бы я только мог понять, почемуРазобрался, и решение занимает слишком много байтов. (Также уменьшилось количество байтов, потому что каким-то образом вкладки превратились в четыре пробела. Возможно, это было форматирование блока кода на этом сайте)b=d[j*v+i]==m(d[i::v])
не работает.Редактировать: я реорганизовал, как сделал кипу. Теперь он создает одну нить за раз, а затем переносит для печати.
Изменить: превратил мой ответ обратно в программу на Python 3, чтобы сохранить еще несколько байтов.
Редактировать: я обнаружил ошибку в своем коде, из-за которой он неправильно печатал нули в середине чисел (см. Контрольный пример
204 1
выше). Исправив это, мне удалось сыграть в гольф :)Изменить: я изменил печать, чтобы сохранить 10 байтов. И я отложил все старые подсчеты байтов, просто потому что.
Edit: Golfed назначения
v
использованияmap
для четырех байт. Кредит CarpetPython , как я получил идею от их ответа здесь .Редактировать: превратил середину цикла for в цикл for в один цикл for для шести байтов.
Изменить: сейчас с помощью
enumerate
. Больше не используюl=len(z)
. Превратил троичныйif-else
в список троичный. Смотрите ниже для деталей.Редактировать: Sp3000 предложил редактировать
print
и редактировать троичное условие, сохраняющее каждый байт.Ungolfed:
источник
0
, такими как0 12 4
.for r in zip(*x):print(''.join(r))
->print(''.join(r)for r in zip(*x))
C
238235 байтПолагаясь на препроцессор C, сделать код максимально коротким. Как побочный эффект, также делает его практически нечитаемым.
В Ubuntu 14.04 вы можете просто скомпилировать код
gcc quipu.c
(игнорируйте предупреждения). Пример запуска исполняемого файла:Проверено на все контрольные примеры OP.
Ungolfed исходный код:
источник
Mathematica
436 453 357 352347 байтНад
IntegerDigits
; дополняет каждое число нулями влево (чтобы обеспечить одинаковое расстояние); каждое входное число, теперь разложенное на цифры, соответствует строке массива; каждый столбец представляет значение места. Массив транспонирован.пример
источник
Transpose@Join
? Это должно быть в, верно?R -
446444Я вижу, что пока нет решения R, так что вот оно. Функция принимает вектор с целыми числами.
Ungolfed
источник
if(v>0)
в вашейif(i<r)
статье? R принимает диапазон какz+1:z
когдаv==0
?q[z+1:z,j]
Я думаю, если это не повлияет на это вообще. Кроме того, у R естьelse
ключевое слово и какое-тоelse if
ключевое слово? Если это так, вы сможете сыграть в некоторые из этих условий.if(v>0)
необходим, потому что еслиv=0
, индекс будет вне границ (то есть, попытается получить строку nrow + 1). R действительноelse
, и я на самом деле попробовал ваше предложение и использовал,else
где это возможно, но оказалось, что это было одинаковое количество байтов.