Подсчет кипу: база 10 в новом мире


41

Кипу - это древнее устройство, используемое инками в доколумбовскую эпоху для записи чисел в базовой десятипозиционной системе узлов на шнуре, которая работает следующим образом:

Каждая группа узлов является цифрой, и существует три основных типа узлов: простые накладные узлы; «длинные узлы», состоящие из верхнего узла с одним или несколькими дополнительными витками; и восьмерка узлов.

  • Степени десяти показаны позицией вдоль струны, и эта позиция выровнена между последовательными нитями.
  • Цифры в позициях для 10 и более степеней представлены группами простых узлов (например, 40 - это четыре простых узла подряд в позиции «десятки»).
  • Цифры в позиции "единицы" представлены длинными узлами (например, 4 - узел с четырьмя поворотами). Из-за того, как узлы связаны, цифра 1 не может быть показана таким образом и представлена ​​в этом положении узлом в виде восьмерки.
  • Ноль представлен отсутствием узла в соответствующей позиции.

Детали

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

Сучки

Каждый узел будет представлен одним символом ASCII.

  • . представляет собой простой узел
  • : представляет один оборот длинного узла
  • 8 представляет собой узел восьмерки
  • | представляет отсутствие узла, а также разделитель между цифрами.

Построение Кипуса

Quipu построены в соответствии с этими правилами.

  1. Нити идут сверху вниз в порядке убывания положения (как, например, цифра единиц будет на нижнем конце жилы). Цифры вдоль нити разделяются символом ( |).
  2. Степень 10, которую представляет цифра, определяется ее положением вдоль цепи таким же образом, как сила 10 цифры будет рассчитываться с использованием ее индекса в числе с нашей системой счисления. То есть, 24где a 2в десятках и a 4в единицах измерения, будут представлены двумя узлами, разделителем ( |), а затем четырьмя узлами.
  3. Цифры в том же положении выровнены по направлению к нижней части жилы. Если у одной цифры в позиции будет меньше узлов, чем у других цифр других чисел в той же позиции, отсутствие этих узлов представляется как ( |).
  4. Последовательные простые узлы ( .) представляют значение в их положении.
  5. Каждая цифра представлена ​​как минимум 1 символом. Когда значение цифры равно 0 для всех чисел в кипе, оно представлено отсутствием узла ( |).
  6. Место подразделений обрабатывается специально. Единица в единицах измерения представлена ​​узлом восьмерки ( 8). Значение двух или более в месте единиц измерения представлено последовательными длинными узлами ( :).
  7. Когда цифра единиц равна 0 для всех чисел в кипе, отсутствие узла не печатается, но конечный разделитель для цифры десятков сохраняется.
  8. После цифры единицы нет разделителя.

правила

  • Ввод будет состоять из непустого списка неотрицательных целых чисел, которые могут быть получены любым из методов ввода по умолчанию . Вы можете предположить, что все эти числа меньше или равны 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

Выход:

|

Более длинные тесты

Дальнейшее чтение


Ответы:


3

Pyth, 64 байта

=QjRTQjCmj\|+:R"[8:]"\.PdedCmm+*\|-h.MZdk*?tk\:\8kdC.[L0h.MZlMQQ

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

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

=QjRTQ   Converts each number in input to decimal (as a list)
         123 becomes [1,2,3]

----

jCmj\|+:R"[8:]"\.PdedCmm+*\|-h.MZdk*?tk\:\8kdC.[L0h.MZlMQQ

                                              .[L0       Q  0-leftpad each #
                                                  h.MZlMQ   (max length) times

                                             C              transpose

                      mm                    d    for each digit:
                        +                        [convert to] sum of
                         *\|                     "|" repeated
                            -                    the difference of
                             h.MZd               maximum digit in same row
                                  k              and itself.. that many times
                                   *?tk\:\8      and (digit > 1 then ":" or "8") repeated
                                           k     itself many times


the list:
[11,23,52]
->[[1,1],[2,3],[5,2]]
->[[1,2,5],[1,3,2]]
->[["||||8","|||::",":::::"],["||8",":::","|::"]]

                     C      transpose

->[["||||8","||8"],["|||::",":::"],[":::::","|::"]]

  m                          for each number
      +                      [convert to] sum of
                 Pd          every element but the last
       :R"[8:]"\.            with "8" and ":" replaced by "."
                   ed        and the last element
   j\|                       joined with "|"

  C                          transpose
 j                           join (with newlines)

Это отличный ответ за исключением одной проблемы. Последний узел - не всегда узел восьмерки 8. Фактически, это только 8узел, когда последняя цифра равна 1 (см. Правило 6). Вы конвертируете все последние узлы, и это не соответствует спецификации. Кроме того, ваша пробная версия онлайн! ссылка имеет код, отличный от того, который выложен здесь, по всей видимости
Sherlock9

22

Не читается , 3183 3001 байт

Это было веселое испытание - работать и выключать между рождественскими праздниками. Спасибо за публикацию! Игра в гольф была интересной, потому что спецификация полна исключений и особых случаев, которые требовали много условий. Кроме того, хотя в этот раз мне не нужно было выполнять преобразование в десятичное число и обратно, мне нужна была своего рода функция «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 станет ясна позже.

введите описание изображения здесь

На этом этапе позвольте мне уточнить терминологию, которую я буду использовать на протяжении всего этого.

  • По номером я подразумеваю одно из входных чисел, разделенных запятыми. В нашем примере это 202, 100 и 1.
  • По цифрой я подразумеваю одну цифру в конкретном из чисел. Первое число имеет 3 цифры.
  • По месту я подразумеваю «одно место», «десятки», «сотни» и т. Д. Поэтому, если я скажу «цифры в текущем месте», а текущее место - это «те места», эти цифры равны 2, 0 и 1 в этом месте. приказ.

Теперь вернемся к нашему обычному программированию. Вся остальная часть программы представляет собой большой цикл, который перемещает 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. Здесь мы выполняем две особые вещи.

  • Во-первых, мы также вычитаем размер r- блока (плюс 1) из * q , но используя указатель r2 , который оставляет его слева. * q становится отрицательным таким образом. В нашем случае r- блок имеет пять единиц, поэтому * q становится равным -3.
  • Во- вторых, мы устанавливаем переменную из в ненулевое значение , чтобы указать , что мы сейчас вступаем выходной каскад. (Технически тот факт, что * q отрицателен, уже указывает на выходной каскад, но это слишком сложно проверить, следовательно, дополнительная переменная.)

Теперь вы понимаете, что мы продолжаем изучать числа, находим текущее место (обозначенное не-1 значением * q ) внутри каждого числа и делаем что-то в зависимости от значения * q . Мы видим, что * q сначала увеличивается до 2 (= вычислить максимальное значение цифры), затем до 3 (вычитать максимальное значение цифры из каждой цифры в этом месте), а затем мы вычитаем его, чтобы сделать его отрицательным. Оттуда он будет продолжать расти, пока не достигнет 1, восстановив, таким образом, значение, которое означает «ничего не делать». В этот момент мы переходим к следующему месту.

Теперь, когда * q отрицательно, мы выводим. * q имеет точно правильное значение, поэтому мы выведем правильное количество строк символов, прежде чем оно достигнет 1; если самая большая цифра - 2, нам нужно вывести 3 строки. Давайте посмотрим, что происходит при каждом значении * q :

  • * q = −2:
    • Для первого числа * p равно -2, что указывает на то, что нам нужно вывести '.'(точка) или ':'(двоеточие). Мы решаем, что, посмотрев на q : если это -1, мы в одном месте, поэтому выведите a ':'(который мы вычисляем как '8'+2), в противном случае a '.'.
    • Для второго числа * p равно −3. Все, что не равно -2, означает, что мы выводим '|'(трубу), а затем увеличиваем значение. Таким образом, он достигнет -2 в нужном месте, а затем мы выводим '.'s / ':'s для остальной части этой цифры.
    • В каждом случае мы также устанавливаем переменную pd в 0, прежде чем мы обработаем число, и устанавливаем pd (= «print») в ненулевое значение, чтобы указать, что мы напечатали символ.
    • Для третьего числа обработка не происходит, потому что третье число не имеет места в сотне. В этом случае pd все равно будет 0 после обработки числа, указывая, что нам все еще нужно вывести a '|'(но только если out не равен нулю, потому что в противном случае мы все еще находимся на стадии 2 или 3).
    • После обработки всех чисел, если out не равен нулю, выведите новую строку. Обратите внимание, что нам нужна переменная out, чтобы мы не выводили символ новой строки на этапе 2 или 3.
  • * q = −1: То же, что и раньше, за исключением того, что * p равно -2 для обоих первых двух чисел, поэтому оба выдают a'.'(а третье выдает a,'|'как и раньше).
  • * q = 0: когда * q равно 0, это означает «ничего не делать, если мы на месте, иначе вывести строку'|'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:

  • Когда * q = -1, все значения * p равны -3, что означает, что мы выводим '|'s и увеличиваем их.
  • Когда * q = 0, мы выводим, '|'потому что это то, что мы всегда делаем, когда * q = 0, независимо от * p .

Таким образом, мы получаем два ряда труб.

Наконец, мы перемещаем * q на свое место. Это становится интересным, потому что нам нужно вывести ':'s, если фактическая цифра не равна 1, а '8'если - 1. Посмотрим, как работает программа. Сначала мы увеличиваем * q, чтобы начать этап 2:

введите описание изображения здесь

После этапа 2 («рассчитать максимальное значение цифры») у нас остается следующее:

введите описание изображения здесь

После этапа 3 («вычесть максимальное значение цифры из всех цифр в текущем месте») лента выглядит следующим образом:

введите описание изображения здесь

Теперь давайте рассмотрим каждую итерацию * q по очереди:

  • * q = −2:
    • Первое число: уже в -2, поэтому выведите a ':'(а не a, '.'потому что q = -1).
    • Второе число: в -4, поэтому выведите a '|'и увеличьте.
    • Третье число: на -3, поэтому выведите a '|'. Однако на этот раз вместо инкремента срабатывает особый случай. Только если мы выводим последнее место ( q = −1), и мы находимся во втором последнем ряду для этого ( * q = −2), а цифра фактически равна 1 ( * p = −3) , то вместо того , чтобы его приращение -2, мы устанавливаем его в -1. Другими словами, мы используем -1 как специальное значение, чтобы указать, что на следующей итерации нам нужно будет выводить '8'вместо ':'.
  • * q = −1:
    • Первое число: уже на -2, поэтому выведите a ':'.
    • Второе число: на -3, поэтому выведите a '|'. Специальное условие не срабатывает, потому что * q больше не равен -2. Поэтому прирост.
    • Третье число: в -1, поэтому выход '8'.
  • * q = 0: Обычно мы выводим здесь строку заполнения'|'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. Чтобы дать вам пример, а не

    while *(++p) { 1 }         // just increment p until *p is 0; the 1 is a noop
    if (pd) { x } else { y }   // where pd is a variable
    

    Я могу сохранить '""""(сделать первое, затем второе) и '"""(константа 1), написав это так, как

    if (while *(++p) { pd }) { x } else { y }
    

    Конечно, это работает, только если я знаю, что цикл while будет выполняться как минимум одну итерацию, но если это так, его возвращаемое значение будет pd, поэтому я могу использовать его как условие для if.


«Неразборчивый», безусловно, удачное имя ...
Алекс А.

9
-1 не хватает объяснения
Парень со шляпой

7

Javascript (ES6) 750 744 690 604 498 346 245 234 байта

Я новичок в PPCG и подумал, что могу попробовать, думая, что это довольно просто. Мальчик был я не прав! Я работал над этим некоторое время, и у меня есть много занятий гольфом ...
Предложения приветствуются! - хотя разобраться в этом не будет легкой задачей.

Выходные канаты, когда вход представляет собой массив чисел (например:) [204, 1].

a=>(o=m=s="",l=a.map(n=>(s+="|",l=(n+"").length)>m?m=l:l),h=[],a=a.map((n,i)=>[..."0".repeat(m-l[i])+n].map((d,j)=>d<h[j]?d:h[j]=d)),h.map((n,i)=>{i?o+=s+`
`:0;for(j=n;j--;o+=`
`)a.map(d=>o+="|.:8"[d[i]-j<1?0:i<m-1?1:d[i]-1?2:3])}),o)

объяснение

a=>(

  o=m=s="",                      // m = max number of digits in a number, s = separator string         
  l=a.map(n=>(                   // l = lengths of each number
      s+="|",                    // set the separator string
      l=(n+"").length                 // convert each number to a string
    )>m?m=l:l                    // get max length
  ),
  h=[],
  a=a.map((n,i)=>
    [..."0".repeat(m-l[i])+n]    // add leading 0s to make all same length
    .map((d,j)=>d<h[j]?d:h[j]=d) // set each digit of h to max
  ),

  h.map((n,i)=>{
    i?o+=s+`
`:0;
    for(j=n;j--;o+=`
`)
      a.map(d=>
        o+=
          "|.:8"[
            d[i]-j<1?0
            :i<m-1?1
            :d[i]-1?2:
            3
          ]
      )
  }),
  o
)

пример

Ввод: Массив чисел: Ввод [4,8,15,16,23,42]
:

|||||.
|||||.
||||..
||....
||||||
|:||||
|:||||
|:|:||
|:::||
::::||
:::::|
::::::
::::::

+1 впечатляющий гольф. Будете ли вы включать пример с вводом и выводом?
DavidC

@DavidC Спасибо! И пример включен. Вызовите его из консоли, и он вернет строку. :)
Aᴄʜᴇʀᴏɴғᴀɪʟ

7

Python 3, 624 598 595 574 561 535 532 527 525 426 345 328 324 294 288 286 283 280 267 265 255 251 245 238 235 234 230 228 байтов

z=input().split();v=max(map(len,z));d=''.join(i.zfill(v)for i in z);x=['']*len(z)
for k,c in enumerate(d):j=k%v;m=int(max(d[j::v]));c=int(c);x[k//v]+="|"*(m-c+0**m+(j>0))+":8."[(c<2)|-(j<v-1)]*c
for r in zip(*x):print(*r,sep='')

Ну, так как на этот вопрос требовался ответ, я предоставил здесь один, где ввод должен быть строкой с разделенными пробелами числами, например "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:

s = input()
z = s.split()
v = max(map(len, z))                # the amount of digits of the largest number
d = ''.join(i.zfill(v) for i in z)  # pad zeroes until every number is the same length
                                     # then join the numbers into one string
x = ['']*len(z)                     # a list of strings for the output, one for each number

for k,c in enumerate(d):          # for every digit in every number
    i,j = divmod(k, v)            # i is the index of the number we're on
                                   # j is the index of the digit of the number we're on
    m = int(max(d[j::v]))         # the largest of all the digits in the j-th place
    c = int(c)                    # the digit in j-th place of the i-th number
    x[i] += "|"*(m-c+0**m+(j>0))  # pad | to size m-c, until the knots are correctly spaced
                                  # add a | if m<1, all j-th place digits are 0
                                  # add a | if j>0, if it's not at the start, as delimiters
    x[i] += ":8."[(c<2)|-(j<v-1)] * c
    # this is essentially the following code
    # if j<v-1:
    #     x[i] += "."*c      # . knots if not in the units place
    # else:
    #     if c == 1:
    #         x[i] += "8"*c  # 8 knots for ones in the units place
    #     else:
    #         x[i] += ":"*c  # : knots for something else is in the units place

for r in zip(*x):       # transpose so all the rows (the quipu strings) now hang down
    print(*r, sep='')    # join the strings together at each knot
                         # and print each on a separate line

Здесь есть что-то конкретное для Python 3 ? Если нет, преобразование его в Python 2 может сэкономить немало байтов
Cyoce

@Cyoce Ничего особенного в Python 3. Я только начал в Python 3, потому что это версия, которую я имею. Я протестирую версию Python 2 на ideone или что-то в этом роде.
Sherlock9

@Maltysen Это не работает с исходными данными 0, такими как 0 12 4.
Sherlock9

Вы можете сохранить несколько байтов, чередуя символы табуляции и пробелы для отступа в Python 2. Я считаю, что 1 символ табуляции == 8 пробелов в соответствии с синтаксическим анализатором отступов Python
Cyoce

for r in zip(*x):print(''.join(r))->print(''.join(r)for r in zip(*x))
Дрянная Монахиня

4

C 238 235 байт

Полагаясь на препроцессор C, сделать код максимально коротким. Как побочный эффект, также делает его практически нечитаемым.

#define l strlen(a[i])
#define d l<k||a[i][l-k]-48
#define m(e) for(i=1;a[i];e<=r?i++:r++);
#define p(e) {m(!putchar(e?'|':k>1?46:d<2?56:58))puts("");}
k,r;main(int i,char**a){m(l)for(k=r,r=1;k;r=k>1){m(d)for(;r;r--)p(d<r)if(--k)p(1)}}

В Ubuntu 14.04 вы можете просто скомпилировать код gcc quipu.c(игнорируйте предупреждения). Пример запуска исполняемого файла:

$ ./a.out 1 2 3 2 1
||:||
|:::|
8:::8

Проверено на все контрольные примеры OP.

Ungolfed исходный код:

// Standard library; leaving out the includes still gives executable code despite the warnings.
#include <stdio.h>
#include <string.h>

// 4 preprocessor macros.
// Note: some of these actually make use of the fact that parentheses have been left out

// l: length of argument i
#define l     strlen(a[i])

// d: shorthand for a digit
#define d     l<k || a[i][l-k]-'0'

// m: loop across all arguments; calculates r as the maximum of expression e
#define m(e)  for (i=1; a[i]; e<=r ? i++ : r++);

// p: prints one line of output
// note: intentionally does not use the r++ code branch of m;
//       putchar always returns a non-zero number here, so !putchar is zero,
//       which is always <=r (because r is never negative)
// note: the semicolon after m(...) is redundant;
//       the definition of m already contains a semicolon
// note: puts("") outputs a newline
#define p(e)  { m(!putchar(e ? '|' : k > 1 ? '.' : d < 2 ? '8' : ':')); puts(""); }

// k: knot position; 1 for units, 2 for tens, 3 for hundreds...
int k;

// r: input and output value for m
// note: the first time we call m, we need r to be zero;
//       by defining it outside main, it is automatically initialized as such
int r;

// function main
// note: parameter i (normally named argc by convention) is not needed
//       (the last element of argv is known; it is followed by a NULL pointer)
//       but we cannot leave it out (otherwise we cannot access argv)
//       so it serves as a local variable (to loop through arguments; see m)
// note: parameter a (normally named argv by convention)
//       is the array of arguments (starting from index 1)
int main(int i, char **a)
{
    // Determine the longest argument; store its length in r.
    // This is the number of knot positions to consider.
    m(l)

    // Iterate k through the knot positions from top to bottom.
    // Note: k > 0 has been abbreviated to k.
    // Note: for each iteration, we also initialize r with either 0 or 1.
    //       0 = suppress printing when all knots are zero
    //       1 = always print, even when all knots are zero
    for (k = r, r = 1; k > 0; r = k > 1)
    {
        // Determine the highest digit at this knot position.
        // Note: due to the absence of parentheses, d mixes up with <=r into:
        // (l < k) || (a[i][l-k]-'0' <= r)
        m(d)

        // Count the digits down.
        for (; r; r--)
        {
            // Print a single line of output.
            // When d (the digit in the current strand) is less than the counter,
            // then print a '|', otherwise print a knot.
            p(d < r)
        }

        // Decrement k (go to next knot position).
        // If this was not the last iteration...
        if (--k > 0)
        {
            // Print separator line.
            p(1)
        }
    }

    // Return exit code zero; redundant.
    return 0;
}

Поздравляем! В качестве кратчайшего ответа за период вознаграждения вы получили мою награду в размере +50 повторений. Хороший ответ! :)
Алекс А.

4

Mathematica 436 453 357 352 347 байт

t=Transpose;y=ConstantArray;a=Table;
g@j_:=(s=t[PadLeft[#,Max[Length/@i]]&/@(i=IntegerDigits@#)]&;p_~u~o_:=(m=Max@p;c=If[o==-2,":","."];w=If[o==-2,"8","."];p//.{0->a["|",Max@{1,m}],1->Join[a["|",{m-1}],{w}],n_/;MemberQ[2~Range~9,n]:>Join[y["|",m-n ],c~y~n]});t[Join@@@t@Join[u[#,0]&/@Most@#,u[#,-2]&/@{#[[-1]]}]]&[Riffle[(s@j),{a[0,Length@j]}]]//Grid)

Над

  • Разбивает каждое целое число на список цифр, используя IntegerDigits; дополняет каждое число нулями влево (чтобы обеспечить одинаковое расстояние); каждое входное число, теперь разложенное на цифры, соответствует строке массива; каждый столбец представляет значение места. Массив транспонирован.
  • Заменяет цифры списком узлов с отступом. Несколько другая процедура сопоставления с образцом используется для подразделений.

пример

g[Range[0, 50]]

пятьдесят


Transpose@Join? Это должно быть в, верно?
CalculatorFeline

Да. Спасибо, что поймали это.
DavidC

Космос прямо перед этим.
CalculatorFeline

1

R - 446 444

Я вижу, что пока нет решения R, так что вот оно. Функция принимает вектор с целыми числами.

function(x){r=nchar(max(x));c=length(x);m=matrix(0,r,c);for(i in 1:c){t=as.numeric(strsplit(as.character(x[i]),"")[[1]]);m[(r+1-length(t)):r,i]=t};Q=c();for(i in 1:r){d=m[i,];z=ifelse(max(d)>0,max(d),1);q=matrix("|",z,c);for(j in 1:c){v=m[i,j];if(i==r){if(v==1)q[z,j]=8;if(v>1)q[(z-v+1):z,j]=rep(":",v)};if(i<r){if(v>0)q[(z-v+1):z,j]=rep(".",v)}};if(i!=1&sum(d)>0)q=rbind(rep("|",c),q);Q=rbind(Q,q)};for(i in 1:nrow(Q))cat(Q[i,],sep="",fill=T)}

Ungolfed

# Some test data
test <- c(201, 0, 100, 222, 53)

# Define function
quipu <- function (x) {

    # Create matrix with a row for each digit and a column for each number
    r=nchar(max(x));c=length(x);m <- matrix(0,r,c)
    for(i in 1:c) {
        t=as.numeric(strsplit(as.character(x[i]),"")[[1]])
        m[(r+1-length(t)):r,i]=t
    }

    # Loop through each row (digit) starting at the top of the quipu
    Q=c() # Empty matrix to store quipu 
    for(i in 1:r){

        d=m[i,]
        z=ifelse(max(d)>0,max(d),1)
        q=matrix("|",z,c)

        # Loop through each column (number in the vector) starting at the leftmost quipu
        for(j in 1:c){

            # The digit
            v=m[i,j]

            # If it is the last segment of the quipu
            if(i==r){
                if(v==1){q[z,j]=8} # If unit digit =1
                if(v>1){q[(z-v+1):z,j]=rep(":",v)} # If unit digit >1               
            }

            # If it is not the last segment of the quipu
            if(i<r){
                if(v>0){q[(z-v+1):z,j]=rep(".",v)} # If non-unit digit >0   
            }
        }

        # Add segment to Q
        if(i!=1 & sum(d)>0){q=rbind(rep("|",c),q)}
        Q=rbind(Q,q)    
    }

    # Print quipu
    for(i in 1:nrow(Q)) {cat(Q[i,], sep="", fill=T)}
}

# Test
quipu(test)

Вам нужно if(v>0)в вашей if(i<r)статье? R принимает диапазон как z+1:zкогда v==0? q[z+1:z,j]Я думаю, если это не повлияет на это вообще. Кроме того, у R есть elseключевое слово и какое-то else ifключевое слово? Если это так, вы сможете сыграть в некоторые из этих условий.
Шерлок9

if(v>0)необходим, потому что если v=0, индекс будет вне границ (то есть, попытается получить строку nrow + 1). R действительно else, и я на самом деле попробовал ваше предложение и использовал, elseгде это возможно, но оказалось, что это было одинаковое количество байтов.
Медленный Лорис
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.