感谢FryAmTheEggman为XOR解决方案提供一些必要的启发。
0000 !@
0001 ?.|@!
0010 #?#!)@
0011 ?!@
0100 +?|@!?
0101 ??!@
0110 ?<@!!<_\~(
0111 ?<<@!
1000 )\!#?@{
1001 (~?/@#!
1010 ??|@!)
1011 \#??!1@
1100 ?(~!@
1101 ?.|@!)
1110 ?$@#)!<
1111 1!@
所有程序都使用0false和1true。
在线尝试!这不是测试套件,您必须复制不同的程序并自行输入。
上面的解决方案在2字节的最佳范围内(除非我们放宽对真假的解释,我想)。我让了近两天对所有节目的蛮力搜索运行的是适合边长2,即最多7个字节(不相当的所有程序-我在每一个有效的程序需要什么,什么做了几个假设没有有效的程序可能有)。搜索找到了16个可能的登机口中的15个的解决方案-通常远远不止一个。您可以在此pastebin中找到所有替代解决方案的列表,在这里我还按等效行为将它们分组。我选择上面显示的方法是因为它们是最简单或最有趣的解决方案,我将在明天为它们添加说明。
至于第16个门:XOR是唯一显然不能在7个字节中实现的门。不幸的是,使用我当前的代码对较大的程序进行暴力搜索是不可行的。因此,XOR必须是手写的。到目前为止,我发现的最短的是上面的10字节程序,它是基于FryAmTheEggman的一次失败(但非常接近)尝试而建立的。可能存在8字节或9字节的解决方案,但除此之外,所有解决方案的确应该是最佳的。
说明
警告:文字墙。在偶然的情况下,任何人都对这些高度压缩的Hexagony程序实际上如何工作感兴趣,我在下面提供了对每个程序的解释。我试图在存在多个最佳程序的情况下为每个门选择最简单的解决方案,以使解释合理地简短。但是,其中一些仍然令人吃惊,所以我认为应该对此进行详细说明。
0000:错误
我认为我们不需要这个图表:
! @
. . .
. .
由于整个内存网格都初始化为零,因此!只需打印零即可@终止程序。
这也是唯一的2字节解决方案。
0001:并且
? .
| @ !
. .
这基本上实现了短路。下面的灰色图显示了程序的开始,在该处读取了第一个输入,?并且指令指针(IP)绕到了左角,在该角|镜将其反射。现在,转角用作条件,因此取决于第一个输入的值,有两个不同的执行路径。红色图显示了的控制流程,A = 0绿色图显示了A = 1:

如您所见,当Ais 0为时,我们只需将其打印并终止(请记住,所有操作.均为无操作)。但是当A是时1,IP再次遍历第一行B,而是读取并打印该行。
总共有16个针对该门的5字节解决方案。其中的十四个基本上与上面的相同,或者使用>代替|或用.有效地为无操作的命令替换,或置于?第二位置:
?.|@! .?|@! ?=|@! =?|@! ?_|@! _?|@! ?0|@!
?.>@! .?>@! ?=>@! =?>@! ?_>@! _?>@! ?0>@!
然后还有另外两个解决方案(彼此等效)。这些也实现了相同的短路逻辑,但是执行路径有点疯狂(留给读者练习):
?<!@|
?<!@<
0010:A而不是B
# ?
# ! )
@ .
这也实现了一种短路形式,但是由于使用#了控制流程,因此更加棘手。#是有条件的IP交换机。六角形实际上带有六个标记0为的IP 5,这些IP 从网格的六个角开始,沿其顺时针方向指向(程序始终以IP开头0)。#遇到a 时,当前值取模6,控制流程继续使用相应的IP。我不确定是什么疯狂程度使我添加了此功能,但是它肯定允许一些令人惊讶的程序(如此程序)。
我们将区分三种情况。如果A = 0,该程序是相当简单的,因为值总是0当#遇到使得没有IP的交换发生:

#不执行任何操作,?读取A(即也不执行任何操作),#仍然不执行任何操作,!打印0,将其)递增(这很重要,否则IP不会跳至第三行),@终止程序。很简单。现在让我们考虑一下情况(A, B) = (1, 0):

红色路径仍然对应IP 0,我为IP添加了绿色路径1。我们看到,(这次)?读取后,切换到从右上角开始的IP。这意味着可以读取()。现在将其递增到,这样左上角的不会执行任何操作,而我们保留IP 。在打印出与IP环绕左斜。仍然不执行任何操作并终止该程序。A1#?B0)1#1!1#@
最后,这是两个输入都为的真正奇怪的情况1:

这次,第二个输入也是,1并将其)递增到2。这意味着#左上角的导致另一个 IP切换到IP 2,以蓝色表示。在那条路径上,我们首先将其进一步递增3(尽管无关紧要),然后?第三次通过。由于我们现在已经达到了EOF(即输入已用尽),因此?return 0,!打印出来并@终止程序。
值得注意的是,这是该门的唯一6字节解决方案。
0011: 一种
? !
@ . .
. .
这很简单,我们不需要图:?读取A,!打印,@终止。
这是此门的唯一3字节解决方案。(原则上,也可以这样做,;@,但是搜索不包括;,因为我认为它无法!为此任务节省字节数。)
0100:B而不是A
+ ?
| @ !
? .
这比它的“兄弟”简单得多0010。控制流程实际上与上面0001(And)看到的相同。如果为A = 0,则IP越过下一行,B在终止之前读取并打印该行。如果A = 1这样,则IP再次遍历第一行,也进行读取B,但是+将两个未使用的存储器边缘相加0,因此将当前值重置为,以便!始终打印0。
有很多6字节替代方案(总共42个)。首先,有大量的解决方案与上述相同。我们可以再次在|和之间自由选择>,并且+可以用任何其他给我们空白的命令代替:
"?|@!? &?|@!? '?|@!? *?|@!? +?|@!? -?|@!? ^?|@!? {?|@!? }?|@!?
"?>@!? &?>@!? '?>@!? *?>@!? +?>@!? -?>@!? ^?>@!? {?>@!? }?>@!?
另外,我们也可以使用]代替?。]移至下一个IP(即选择IP 1),因此该分支将重新使用?右上角的。这给出了另外18个解决方案:
"?|@!] &?|@!] '?|@!] *?|@!] +?|@!] -?|@!] ^?|@!] {?|@!] }?|@!]
"?>@!] &?>@!] '?>@!] *?>@!] +?>@!] -?>@!] ^?>@!] {?>@!] }?>@!]
然后还有其他六种解决方案,它们在不同程度的疯狂情况下都可以发挥不同的作用:
/[<@!? ?(#!@] ?(#>@! ?/@#/! [<<@!? [@$\!?
0101:B
? ?
! @ .
. .
Woohoo,另一个简单的方法:读取A,读取B,打印B,终止。尽管实际上有替代方法。由于A只有一个字符,因此我们也可以使用,以下命令阅读它:
,?!@
还可以选择使用单个?镜像,并使用镜像两次遍历它:
?|@! ?>@!
0110:异或
? < @
! ! < _
\ ~ ( . .
. . . .
. . .
就像我在上面说的那样,这是不适合边长2的唯一门,因此这是FryAmTheEggman和我本人的手写解决方案,而且很有可能不是最佳选择。有两种情况可以区分。如果A = 0控制流程非常简单(因为在这种情况下,我们只需要打印B):

我们从红色的道路开始。?读取A,<是一个偏左零的分支。IP包裹到底部,然后_是另一个镜像,当IP碰到角落时,它包裹到左上角并继续在蓝色路径上。?读取B,!打印。现在(减少它。这很重要,因为它可以确保该值是非正值(是0或-1现在)。这使IP包装到右上角,从而@终止程序。
当A = 1事情变得棘手时。在那种情况下,我们要打印not B,这本身并不太困难,但是执行路径有点混乱。

这次,<偏转IP权限,然后<仅充当镜像。因此,IP反向遍历相同的路径,再次B遇到时将读取?。IP绕到右上角,并在绿色路径上继续。它接下来遇到(~这是“递减,乘以-1”,这互换0和1,因此计算not B。\只是一面镜子,并!打印出所需的结果。然后?尝试返回另一个数字,但返回零。IP现在在蓝色路径的左下角继续。(减少,<反映,(再次递减,以使IP拐角时当前值为负。它在右下角的对角线上移动,然后最后点击@以终止程序。
0111: 要么
? <
< @ !
. .
更短路。

这种A = 0情况(红色路径)在这里有点令人困惑。IP偏左,缠绕到左下角,立即被反射<并返回?到读取B。然后,换到rigt角落,打印B与!和终止。
的A = 1情况下(绿色通道)是有点简单。该<分支偏转知识产权权利,所以我们简单地打印!,转回到左上角,并在终止@。
只有另一个5字节解决方案:
\>?@!
它的工作原理基本相同,但是实际的执行路径却大不相同,它使用转角而不是进行分支<。
1000:否
) \
! # ?
@ {
这可能是我在此搜索中找到的最喜欢的程序。最酷的是,这种实现nor实际上最多可用于5个输入。我将不得不对内存模型的细节进行一些解释。因此,作为快速入门,Hexagony的内存模型是一个单独的六边形网格,其中每个边都保留一个整数值(最初全为零)。有一个内存指针(MP),用于指示边缘和沿该边缘的方向(这样,在当前边缘的前面和后面都有两个相邻的边缘,左右两个邻居有意义)。这是我们将要使用的边缘的示意图,MP以红色显示:

让我们首先考虑两个输入均为的情况0:

我们从灰色路径开始,该路径仅将边缘A增加到,1因此#切换到IP 1(即蓝色路径)从右上角开始。\在此不执行任何操作并?读取输入。我们包装到左上角,)使输入递增。现在,只要输入为零,这将导致1,因此#不会执行任何操作。然后{移动MP到左边,即从第一次迭代甲到乙。由于此边缘仍具有其初始零,因此IP回绕到右上角并位于新的内存边缘。因此,只要?读取零,此循环就会持续,将MP从B移到六边形周围到C到D等。?返回零(因为它是输入还是因为它是EOF)并不重要。
后通过这个循环反复运行六次,{返回一个。这次,边缘已经保存了1第一次迭代的值,因此IP绕到了左上角,并继续在绿色路径上继续。!简单地打印1并@终止程序。
现在,如果有任何输入是1什么?

然后在某个点?读取该1值并将)其增加到2。这意味着#现在将再次切换IP,我们将继续在红色路径的右上角。?读取另一个输入(如果有的话),这并不重要,{将一条边进一步移动。这必须是未使用的边,因此最多可用于5个输入。IP环绕在右上角,立即被反射并环绕到左上角。在未使用的边缘上!打印0并#切换回IP 0。该IP仍在等待#,一直向西南行驶(灰色路径),因此它立即命中@并终止了该程序。
总共有七个针对此门的7字节解决方案。其中5个的工作原理与此相同,只是使用其他命令移动到未使用的边缘(并可能绕着不同的六角形或沿不同的方向行走):
)\!#?@" )\!#?@' )\!#?@^ )\!#?@{ )\!#?@}
还有另一类解决方案,仅可用于两个输入,但其执行路径实际上甚至更为混乱:
?]!|<)@ ?]!|<1@
1001: 平等
( ~
? / @
# !
这也非常巧妙地使用了条件IP选择。我们需要再次区分A = 0和A = 1。在第一种情况下,我们要打印not B,在第二种情况下,我们要打印B。因为A = 0我们也区分了两种情况B。让我们开始A = B = 0:

我们从灰色的道路开始。(~可以忽略,IP换行到左角(仍在灰色路径上)并显示A为?。(递减,因此我们将-1IP包装到左下角。现在,就像我前面说的那样,在选择IP前#取值取模6,因此-1实际值IP出自IP 5,它从红色路径的左上角开始。?读取时B,(也会递减,以便在再次5命中时仍保留IP #。~取反,-1以便IP包装到右下角,打印1并终止。

现在,如果B是的话1,当前值将是第二次0点击时的值#,因此我们切换回IP 0(现在在绿色路径上)。?第三次点击,屈服0,!打印并@终止。

最后的情况是A = 1。这次,当我们#第一次点击时,当前值已经为零,因此,它永远不会切换到IP 5。我们只是立即沿着绿色道路前进。?现在不仅给出零,而是返回B。!打印它并@再次终止。
总共有三个针对此门的7字节解决方案。另外两个的工作方式大不相同(甚至彼此不同),甚至使的使用更加奇怪#。特别是,他们使用,(读取字符代码而不是整数)读取一个或多个值,然后使用该值取模6来选择IP。真是疯了。
),)#?@!
?~#,~!@
1010:不是B
? ?
| @ !
) .
这很简单。执行路径是我们之前已经知道的水平分支and。??阅读A,然后立即B。反映|并分支之后,B = 0我们将执行底部分支,在)该分支上将值递增,1然后按来打印!。在顶部分支(if B = 1)上,?只需简单地重置边缘0,然后也将边缘打印到该边缘!。
此门有八个6字节程序。其中四个几乎相同,使用>代替|或1代替)(或两者都使用):
??>@!) ??>@!1 ??|@!) ??|@!1
两个使用单个?,由于镜像而使用两次。否定再发生,因为我们没有为xor与任一(~或~)。
?>!)~@ ?>!~(@
最后,两种解决方案都使用有条件的IP交换机,因为如果复杂的解决方案也可行,为什么要使用简单的方法:
??#)!@ ??#1!@
1011:B表示A
\ #
? ? !
1 @
这使用了一些相当复杂的IP交换。A = 1这次我将从案例开始,因为它更简单:

我们从灰色路径开始,该路径读取A,?然后点击#。既然A是1这样切换到IP 1(绿色路径)。该!立即打印在于,所述IP包到左上角,读取B(不必要的),并结束。
当A = 0事情变得更加有趣时。首先让我们考虑一下A = B = 0:

这次,#什么也没做,我们仍然停留在IP 0(从该点开始的红色路径)上。?读取B并将1其转换为1。包裹到左上角后,我们#再次命中,因此我们最终会到达绿色路径,并1像以前一样打印,然后终止。
最后,这是(A, B) = (0, 1)错误的情况:

请注意,为清楚起见,我已删除了初始的灰色路径,但该程序以相同的方式开始,我们最终以红色路径结束。因此,这次第二次?返回1。现在我们遇到了1。在这一点上,重要的是要了解在六角形中实际执行的数字(到目前为止,我们仅将它们用于零):遇到数字时,将当前值乘以10,然后将数字相加。这通常用于将十进制数字逐字写入源代码,但这意味着它B = 1实际上已映射到value 11。所以,当我们到了#,这是取模6给5,因此我们切换到IP 5(而不是1像以前一样),并继续在蓝色的路径上。打?第三次返回零,因此!打印出来,在第二个之后?,IP包装到程序终止处的右下角。
有四个7字节的解决方案,它们的工作方式有所不同:
#)/!?@$ <!?_@#1 \#??!1@ |/)#?@!
1100:不是
? (
~ ! @
. .
只是一个简单的线性变量:用读取,A用?否定,用(~打印,用!终止@。
有一种替代解决方案,而与之~)相反:
?~)!@
1101:A表示B
? .
| @ !
) .
这比我们刚才谈到的相反含义要简单得多。再次是那些横向分支程序之一,例如and。如果A为0,则仅将其递增1到底部分支并打印。否则,将再次执行top分支,在该分支中?读取B并!打印。
有一吨这里的替代品(66个解决方案总),主要是由于有效的无操作自由选择。首先,我们可以采用我们可以使用的所有相同方法来改变上述解决方案and,我们还可以在)和之间进行选择1:
?.|@!) .?|@!) ?=|@!) =?|@!) ?_|@!) _?|@!) ?0|@!)
?.|@!1 .?|@!1 ?=|@!1 =?|@!1 ?_|@!1 _?|@!1 ?0|@!1
?.>@!) .?>@!) ?=>@!) =?>@!) ?_>@!) _?>@!) ?0>@!)
?.>@!1 .?>@!1 ?=>@!1 =?>@!1 ?_>@!1 _?>@!1 ?0>@!1
再有就是使用条件IP选择,其中第一个命令几乎可以任意选择不同的版本,也有之间的选择),并1为其中的一些选项:
"?#1!@ &?#1!@ '?#1!@ )?#1!@ *?#1!@ +?#1!@ -?#1!@ .?#1!@
0?#1!@ 1?#1!@ 2?#1!@ 3?#1!@ 4?#1!@ 5?#1!@ 6?#1!@ 7?#1!@
8?#1!@ 9?#1!@ =?#1!@ ^?#1!@ _?#1!@ {?#1!@ }?#1!@
"?#)!@ &?#)!@ '?#)!@ *?#)!@ +?#)!@ -?#)!@
0?#)!@ 2?#)!@ 4?#)!@ 6?#)!@
8?#)!@ ^?#)!@ _?#)!@ {?#)!@ }?#)!@
1110:南德
? $
@ # )
! <
最后一个复杂的。如果您仍在阅读,那您几乎已经做到了。:)让我们A = 0先来看:

?阅读A,然后我们点击$。这是一个跳转命令(例如Befunge的#),它会跳过下一条指令,以免我们在处终止@。而是IP继续在#。但是,既然A是0,这不会做任何事情。)将其递增到1使IP继续在1打印的底部路径上。该<偏转IP到那里换到了左路角球和程序终止的权利。
接下来,当输入时,(A, B) = (1, 0)我们会遇到这种情况:

它与以前基本相同,除了#我们切换到IP 1(绿色路径)外,但是由于我们B是在第二次命中(现在是蓝色路径)时又0切换回IP ,所以它像以前一样打印。0#1
最后,A = B = 1情况:

这次#是第二次,当前值仍然是,1因此我们不再更改IP。在<反映它和我们打第三次?我们得到了一个零。因此,IP换行到左下角,其中!打印零并结束程序。
总共有9个7字节的解决方案。第一种替代方法只是使用1代替):
?$@#1!<
然后,有两种解决方案可以帮助您解决正在发生的IP切换:
)?#_[!@ 1?#_[!@
这些实际上使我震惊:有趣的部分是IP交换可以用作延迟条件。该语言的IP切换规则使当前IP在切换发生之前又迈出了一步。如果该步骤碰巧出现在拐角处,那么当前值将决定如果我们切换回IP,IP将在哪个分支上继续。当输入为时,确实会发生这种情况A = B = 1。尽管这一切都与我设计语言的方式一致,但是我从来没有意识到规范的含义,因此当我的语言教给我一些新技巧时,这非常好:D。
然后是第三种解决方案,其IP切换量甚至更糟(尽管它没有利用延迟的条件效应):
>?1]#!@
然后还有另一个:
?$@#)!<
然后是这四个等效的解决方案,它们确实使用了一些无条件的IP交换,而是通过分支和角落实现了所有逻辑:
]<?<@!) ]<?<@!1 ]|?<@!) ]|?<@!1
1111:真
1 !
@ . .
. .
最后,您已经获得了一些简单的方法:将edge设置为1,使用print进行打印,使用end进行!终止@。:)
当然,有一种选择:
)!@
像往常一样,用Timwi的HexagonyColorer创建的所有控制流程图以及用EsotericIDE创建的内存图。