可视化欧几里得算法


17

欧几里得算法是用于计算两个正整数的最大公约数(GCD)的广为人知的算法。

算法

为解决这一挑战,算法描述如下:

  1. 将两个输入显示为某个字符的相邻行,
    例如的输入3,4可以由相邻行0000000

  2. length(short_line)较长行中的第一个字符转换为另一个字符,-
    现在说看起来像000---0

  3. 删除length(short_line)较长行中的第一个字符。
    现在0000

  4. 重复步骤2和3,直到两个具有相等的长度,使用较短和较长的线在每次迭代之后,例如
    0000
    -000
    000
    -00
    00

  5. 您可以选择是在此处停止还是继续迭代,然后将其中一行转换为空行。

这些步骤中的每个步骤之间应间隔0.3秒至1.5秒。

挑战

编写一个程序,给定两个自然数作为输入,它会创建一个输出,该输出看起来与上述算法的输出完全相同。您可以使用其他非空白打印的ASCII字符比0-,但要一致,仅使用两个字符。如果输出(包括时序)与上述算法产生的输出完全相同,您也可以使用其他算法。

例子

这是input的示例24,35,它们是互质数,因此它们的GCD为1。

在此处输入图片说明

这是带有16,42GCD 2的input的示例。

在此处输入图片说明

规则


澄清说明

  • 代表数字的线需要保持其原始顺序,即,在所有后续帧中,第一个显示的“框架”的第一和第二行分别必须是第一和第二行。
  • 算法结束后,不应再出现其他可见实体。但是,这也意味着如果确保最后一个“帧”显示的时间至少与消隐之前所有其他帧的显示时间相同,则可以将行消隐。

@WheatWizard很棒的建议
busukxuan

线是否必须保持相同的相对顺序?还是可以在迭代之间对它们进行重新排序?(进行检查,因为后者在大多数语言中可能更加简洁,因此我需要知道我是否应该使用该优化或由于违反sepc而忽略该优化。)

@ ais523是的,他们这样做:-)
busukxuan

@ ais523是的,可以将其为空白,但请确保为最后一帧提供与其他帧相同的显示时间
busukxuan

1
@busukxuan我个人认为我会允许尾随空格,但也许不是空间的“有意义”的人物之一
路易斯Mendo

Answers:


3

果冻,29个字节

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

在线尝试!

这定义了一个函数2Ŀ(不是完整的程序; TIO链接包含用于将一个函数转换为程序的页脚),该函数将两个元素的列表作为输入,并在屏幕上显示输出(我们的合法I / O方法之一) ,这是这项挑战所必需的,因为它谈到的是屏幕的外观)。这假定程序在符合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 '17

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,其判断是否ab应当改变(如果c1,它的时间变化)。

首先,该函数向控制台写入内容。如果c为is 0,则将写入两个零字符串,并在其中插入换行符。既然c已初始化为0,我们就可以利用这一点,并设置全局变量fg保存一些我们经常需要的字符串(例如0repeat)。

否则,它将构建一个带有零和减号的字符串。所有这些字符串由两部分组成:首先是一些(称为此金额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 times=time.sleeps(1)不是用于延迟一个循环
数学迷

谢谢@math_junkie-我尝试使用大多数组合,time.sleep但是错过了那个组合。会努力的。
ElPedro '17

@math_junkie-对我来说是215。也许我缺少一些愚蠢的东西。您可以在“ 在线试用”上发布示例吗?
ElPedro '17


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.010perl 的标志是免费的,因此您可以使用sayover 节省一些字节print…\n。另外,我很确定给匿名子例程起一个名字,而不是将其存储在变量中是很麻烦的。

This到ais523,以获取删除12个字节的提示
Kjetil

1

GNU Sed(带有exec扩展名),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

V47 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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.