Візуалізуйте алгоритм Евкліда


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,3s та 1,5s.

Змагання

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

Приклади

Це приклад із вхідними даними 24,35, які є копрімерами, тому їх GCD дорівнює 1.

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

Це приклад із вхідними даними 16,42, які мають GCD 2.

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

Правила


Роз'яснення

  • Рядки, що представляють числа, повинні залишатися у своєму початковому порядку, тобто перший та другий рядки першого відображеного "кадру" повинні бути першим та другим рядками відповідно у всіх наступних кадрах.
  • Після закінчення алгоритму додаткові видимі об'єкти не повинні з’являтися. Однак це також означає, що поряд з порожніми рядками буде добре пропустити рядки, якщо ви впевнені, що останній "кадр" відображається принаймні стільки ж часу, як і всі інші кадри перед вимиканням.

@WheatWizard чудова пропозиція, на ньому
busukxuan

Чи повинні лінії зберігатись у тому ж відносному порядку? Або вони можуть бути перепорядковані між ітераціями? (Перевірка, тому що остання, ймовірно, буде набагато більш стислою для більшості мов, і тому мені потрібно знати, чи слід використовувати цю оптимізацію чи ігнорувати її через порушення септу.)

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


3

Python 2 , 152 146 байт

import time
s,o='-0'
a,b=input()
while a*b:
 d,e=o*a,o*b
 if a>b:a=a-b;d=s*b+o*a
 elif b>a:b=b-a;e=s*a+o*b
 else:a=0
 print d+'\n'+e;time.sleep(1)

Спробуйте в Інтернеті!


В якості введення бере два цілих цілих числа, розділених комами


Це гарна відповідь.
ElPedro

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. Можливо, я пропускаю щось дурне. Чи можете ви розмістити приклад у програмі " Спробуйте в Інтернеті" ?
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. Крім того, я впевнений, що терміновіше давати ім’я анонімній підпрограмі, а не зберігати його в змінній.

Thx в 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 на ньому
відладкуватимуться
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.