Визуализировать евклидов алгоритм


17

Евклидов алгоритм является широко известным алгоритмом вычисления наибольшего общего делителя (GCD) двух натуральных чисел.

Алгоритм

Для целей этой задачи алгоритм описывается следующим образом:

  1. Отображение двух входных данных в виде смежных строк определенного символа,
    например вход 3,4может быть представлен соседними строками 000и0000

  2. Превратите первые length(short_line)символы в более длинной строке в другого персонажа, скажем, -
    теперь он выглядит 000и---0

  3. Удалите первые length(short_line)символы в длинной строке.
    Теперь 000,0

  4. Повторите шаг 2 и 3 до двух имеют одинаковую длину, используя более короткие и более длинные строки после каждой итерации, например
    000, 0
    -00, 0
    00, 0
    -0, 0
    0,0

  5. Вы можете выбрать, останавливаться ли здесь или продолжить итерацию и превратить одну из строк в пустую.

Каждый из этих шагов должен быть разделен интервалом от 0,3 с до 1,5 с.

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

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

Примеры

Это пример с входными 24,35данными, которые являются взаимно простыми, поэтому их GCD равен 1.

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

Это пример с вводом 16,42, который имеет GCD 2.

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

правила


Разъяснения

  • Строки, которые представляют числа, должны оставаться в их исходном порядке, то есть первая и вторая строки первого отображаемого «кадра» должны быть соответственно первой и второй строками во всех последующих кадрах.
  • После завершения алгоритма никакая дополнительная видимая сущность не должна появляться. Однако это также означает, что все строки можно очищать, если вы убедитесь, что последний «кадр» отображается в течение, по крайней мере, того же промежутка времени, что и все остальные кадры, перед тем, как отключиться.

@WheatWizard отличное предложение, на нем
busukxuan

Должны ли линии оставаться в одном и том же относительном порядке? Или они могут быть переупорядочены между итерациями? (Проверка, потому что последний, вероятно, будет намного более кратким в большинстве языков, и, следовательно, мне нужно знать, следует ли мне использовать эту оптимизацию или игнорировать ее из-за нарушения sepc.)

@ ais523 Да, они делают:-)
busukxuan

@ ais523 Да, можно очистить его, но убедитесь, что последний кадр имеет то же время отображения, что и остальные кадры
busukxuan

1
@busukxuan Лично я думаю, что позволил бы использовать пробелы в конце, но, возможно, не пробел, как один из «значимых» символов
Луис Мендо

Ответы:


3

Желе , 29 байт

VY“ñc‘ỌœS.⁸
1ẋǵ+M¦ṚÇt€2ǵ⁻/¿

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

Это определяет функцию 2Ŀ(не полную программу; ссылка TIO содержит нижний колонтитул, который преобразует функцию в программу), которая принимает список из двух элементов в качестве входных данных и отображает выходные данные на экране (один из наших допустимых методов ввода / вывода и тот, который вроде необходим для этого вызова, потому что он говорит о появлении на экране). Это предполагает, что программа запускается в терминале, который соответствует стандарту ANSI (я использовал, gnome-terminalно большинство будет работать), и что терминал изначально пуст (что кажется наиболее разумным значением по умолчанию); обратите внимание, что попробуйте онлайн! никак не соответствует этим предположениям, и , таким образом , выходной сигнал искажается там (я запускал программу локально , чтобы убедиться , что она одушевляет , как и ожидалось). Я использую 1там, где используется вопрос 0, и2на месте -.

объяснение

Вспомогательная функция 1Ŀ (при наличии списка из двух списков цифр выводит их в первой и второй строках экрана, затем ждет 0,5 секунды; возвращает свой ввод)

VY“ñc‘ỌœS.⁸
V                   Convert each list of digits to an integer
 Y                  Separate these integers by newlines
  “ñc‘              {Output that; then restart with} the list [27, 99]
      Ọ             Convert codepoints to characters (i.e. "\x1bc"
       œS.          Wait (œS) 0.5 (.) seconds
          ⁸         {Output that; then return} the initial argument

Строка «\ x1bc» при отправке на ANSI-совместимый терминал интерпретируется как управляющий код для сброса терминала; это очистит экран и переместит курсор в верхний левый угол (таким образом, терминал будет готов к следующему выводу).

Вспомогательная функция названа 1Ŀ(Jelly автоматически генерирует имена этой формы для функций, и на самом деле нет другого способа присвоить им имена), но ее можно ссылаться просто как Çиз основной программы (поскольку в языке есть сокращение для функций с числами рядом ).

Основная функция 2Ŀ (реализует задачу, заданную в вопросе)

1ẋǵ+M¦ṚÇt€2ǵ⁻/¿
1ẋ                  Convert input to unary
  Ç                 Call helper function (producing one animation frame)
   µ         µ  ¿   While
              ⁻/      the elements differ:
     M¦               Change the largest element
    +  Ṛ                by adding corresponding elements of the other element
        Ç             Call helper function (producing one animation frame)
         t€2          Delete all 2s from each side of each element
            Ç         Call helper function (producing one animation frame)

6

JavaScript (ES6), 128 124 байта

t=0
f=
(a,b,o,c,d)=>setInterval(e=>{e=[b,d,a,c];o.data=`-0
-0`.replace(/./g,c=>c.repeat(e.pop()));c|d?c=d=0:a>b?a-=c=b:b-=d=a},1e3)
<form><input id=a><input id=b><button onclick=clearTimeout(t),t=f(+a.value,+b.value,o.firstChild)>Go!</button><pre id=o>



2

Javascript (ES6), 215 194 ... 135 129 127 байт

a=>b=>F=(c=0)=>alert('-'[d='repeat'](e=c&a>b&&b)+'0'[d](a-=e)+`
`+'-'[d](f=c&a<b&&a)+'0'[d](b-=f))|a-b|c&&setTimeout(F,1e3,1-c)

использование

Это принимает вклад в вариации на карри. Чтобы использовать это, сначала присвойте функцию переменной (например G), затем вызовите ее так:

G(5)(6)()

объяснение

Несколько рекурсивная функция, которая вызывает себя через 1 секунду, пока алгоритм еще не завершен. Он отслеживает третью переменную, cкоторая определяет, нужно ли aи bнужно ли изменять (если cесть 1, пришло время для изменений).

Сначала функция что-то записывает в консоль. Если cесть 0, он записывает две строки нулей с новой строкой между ними. Так как cинициализируется 0, мы можем воспользоваться этим, и установить глобальные переменные fи gкоторые держат некоторые строки Нам нужно часто (как 0и repeat).

В противном случае он создает строку с нулями и минусами. Все такие строки состоят из двух частей: сначала некоторые (называют эту сумму A) минусы, затем некоторые (называют эту сумму B) нули, затем символ новой строки, затем некоторые (называют эту сумму D) минусы и, наконец, некоторые (называют эту сумму E) нули.

Если первый вход меньше, чем второй, нам нужно удалить нули со второго входа, поэтому он Aравен нулю, Bравен первому входу, Dравен первому входу и Eравен второму входу минус первый вход. Если первый вход не меньше второго входа, применяется обратное ( Aвторой вход, Bпервый вход минус второй вход и т. Д.).

С этими новыми значениями для входа и переключаемой переменной cзапланирован повторный вызов функции в 1e3миллисекундах, что равно одной секунде.

Примечания

  • Используется alertдля вывода
  • Использует 0и -, как в примерах
  • Задержка между шагами составляет 1000 мс (1 секунда)
  • После первого шага функция (из-за особенностей JavaScript) возвращает некоторое число, которое следует игнорировать
  • Версия на TIO выводит все сразу, вставка кода в консоль браузера правильно учтет задержки

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

Попробуй это здесь!


2

Python 2 , 208 204 194 байта

-4 с благодарностью @math_junkie за подлый трюк с time.sleep

-10 с благодарностью @busukxuan за разъяснение правила «очистки экрана».

def z(a,b,y='-',w=1):
 import time;c,d,n,s='0'*a,'0'*b,'\n',time.sleep
 if w:print c+n+d;s(1)
 if b>a:d=y*a+d[a:]
 else:c=y*b+c[b:]
 print c+n+d;s(1)
 if c!=d:z(len(c),len(d),('','-')[y!='-'],0)

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

Уверен, что это может быть больше в гольфе. Больно мне , чтобы дублировать printи forпетлю , чтобы создать паузу , но я не могу найти способ вокруг него в данный момент.

Примечания

  • Пауза теперь использует подсказку от @math_junkie
  • Не полностью работает на TIO, так как он сохраняет выходные данные и выгружает их по завершении программы. Работает нормально в консоли, хотя.

1
Вы должны быть в состоянии сохранить несколько байт , используя import time, s=time.sleepи s(1)вместо того, чтобы петли для задержки
математике наркомана

Спасибо @math_junkie - я пробовал большинство комбинаций, time.sleepно пропустил. Попробую.
ElPedro

@math_junkie - 215 для меня. Может быть, мне не хватает чего-то глупого. Можете ли вы опубликовать пример в Try it Online ?
ElPedro


1

Perl, 161 149 байт

... без отступов и переносов:

($a,$b)=map 0 x$_,@ARGV;
sub p{say"\n$a\n$b";sleep 1}p;
while($a ne$b){
  ($A,$B)=$b lt$a?(\$a,\$b):(\$b,\$a);
  map$$A=~s/0/-/,1..length$$B;
  p;
  $$A=~s/-//g;
  p
}

Поместите его в файл gcd.pl и запустите так:

perl -M5.010 gcd.pl 16 42

1
-M5.010Флаг Perl свободен, так что вы можете сэкономить несколько байт, используя sayболее print…\n. Кроме того, я уверен, что лучше дать вашей анонимной подпрограмме имя, а не сохранять его в переменной.

Спасибо ais523 за советы, чтобы сбрить 12 байтов
Kjetil S.

1

GNU Sed (с eрасширением xec), 88

Оценка включает в себя +3 для -zrfвариантов sed.

p
:
x
esleep 1
g
ta
:a
s/o+//p
t
s/^((O+)(O+)\n\2\b|(O+)\n\4\B)/\L\2\U\3\4\n\2\L\4\U/p
t

Входные данные даны в виде двух одинарных целых чисел, разделенных новой строкой, с использованием верхнего регистра в Oкачестве цифр

Например, пример 16, 42 может быть запущен как:

printf "%0*d\n%0*d\n" 16 0 42 0 | tr 0 O | sed -znrf euclidvis.sed

Согласно последним комментариям, я не очищаю экран между итерациями.


0

V , 47 44 байта

Àé0á
Àé0Hqwmmjlhmmkl@wqòHî@w
gs`mlhv0r-gsÓ-ò

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

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

Àé0                     " Print (Arg1) zeroes
   á                    " Newline
Àé0                     " Print (Arg2) zeroes
   H                    " Go home
    qwmmjlhmmkl@wq      " Store a recursive macro in w that finds the shorter line
                  ò     " recursively
                   Hî@w " find the longest line
gs                      " wait a second
  `mlhv0r-              " replace the zeroes of the long line with -
          gs            " wait a second
            Ó-          " delete all -
              ò         " end recursion

Тебе действительно нужен конец ò?
Kritixi Lithos

Он висит без него, не знаю почему. Будем ждать, пока у меня не будет компьютера с V для отладки
nmjcman101
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.