阿弥陀签(Amidakuji)的简化


10

如果您曾经接触过日本或东亚文化,那么您肯定会遇到过Amidakuji游戏:

在此处输入图片说明

正如Wikipedia解释的那样,这是一种抽签在纸上的彩票,用于随机选择N个项目的排列。

例如,它可以用于将开始顺序随机分配给N个人,或者将N个奖赏分配给N个人,依此类推。

了解游戏为何代表排列的诀窍是要意识到每个水平笔划(称为“腿”)都会将其两个项目交换到位。

同一Wikipedia页面还解释了N个项的每个排列P对应于无数个Amidakuji图。水平笔画(腿)最少的那个被称为那个特定排列P的“素数”。

您的任务是使用以下格式(减去字母)接收带有2条或更多垂直线(在本示例中为6条)的Amidakuji图:

A B C D E F
| | | | | |
|-| |-| |-|
| |-| |-| |
| | | | |-|
| |-| |-| |
| | |-| |-|
| | |-| | |
|-| | |-| |
|-| |-| | |
| |-| | |-|
| | | | | |
B C A D F E

并产生其素数之一(再次减去字母):

A B C D E F
| | | | | |
|-| | | |-|
| |-| | | |
| | | | | |
B C A D F E

带有字母的第一行和最后一行不是该格式的一部分。我在这里添加了它们以显示排列。它也没有要求在第一个或最后行包含没有腿|-|也不使输出是尽可能紧凑。

这个特定的输入示例是Wikipedia页面顶部的Amidakuji图的(无限)ASCII表示之一。

关于这些ASCII图,有一个非显而易见的规则:禁止相邻的边。

|-|-|  <-  NO, this does not represent a single swap!

Wikipedia解释了一种从图表中获取素数的标准过程,称为“起泡”,该过程包括一遍又一遍地应用以下简化:

1)右叉到左叉:

| |-|      |-| |
|-| |  ->  | |-|
| |-|      |-| |

2)消除双打:

|-|        | |
|-|   ->   | |

我不确定这种解释是否明确。您的代码可以使用该技术或产生所需素数的任何其他算法。

最短的代码获胜。

适用标准规则和标准津贴。(如果输入无效,则程序可能会着火。输入/输出格式可能是stdin / stdout,字符串参数,行列表,字符矩阵,最适合您的方法等)

在此处输入图片说明


3
这是一个非常有趣的挑战。我可能会花一些时间来解决问题,嘿。
JosiahRyanW

输出是否需要尽可能紧凑,或者只要支脚数量最少,是否允许任何垂直空间?
Laikoni '18

@Laikoni允许任何垂直空间。
Tobia '18

起泡和逆起泡都达到相同的结果吗?
l4m2 '18 -10-22

@ l4m2什么是逆泡化?
托比亚

Answers:


4

Python 2中322个 240字节

def f(X):
 X=[[c>' 'for c in s.split('|')]for s in X.split('\n')];h=L=len(X[0])-1;p=range(L)
 for x in X:p=[a-x[a]+x[a+1]for a in p]
 while h:h=i=0;exec"if p[i]>p[i+1]:print'|'+i*' |'+'-|'+(L-i-2)*' |';h=p[i],p[i+1]=p[i+1],p[i]\ni+=1\n"*~-L

在线尝试!

该函数采用指定格式的字符串,并以该格式打印简化的Amidakuji。

这里的基本思想是首先将输入转换为排列(在for x in X循环中);然后将其转换为排列。然后在while循环中执行这种排列的冒泡排序,因为正如Wikipedia文章所指出的那样,这会导致“原始” Amidakuji。


哇。我花了很长时间制作Python 3版本,但它是526字节,呵呵。
JosiahRyanW

我刚刚将数百张随机图添加到您的代码中,并且可以确认它输出正确的素数!
托比亚

3

Haskell 288字节

p x(_:[])=x
p(x:y:z)(_:b:c)|b=='-'=y:p(x:z)c|0<1=x:p(y:z)c
c 0='-'
c _=' '
_#1="|"
m#n='|':c m:(m-1)#(n-1)
p?q=(p:fst q,snd q)
f%b|b==f b=b|0<1=f%f b
f l=reverse$snd$(g 0)%(foldl p[1..n]l,[])where n=1+div(length$l!!0)2;g b((x:y:z),a)|x>y=y?g(b+1)(x:z,a++[b#n])|0<1=x?g(b+1)(y:z,a);g _ x=x

在线尝试!

说明

-- the function p performs the permutation of a list
-- according to a single line from amidakuji board
p x (_:[]) = x
p (x:y:z) (_:b:c)
    | b == '-' = y : p (x : z) c
    | otherwise = x : p (y : z) c

-- helper to select either leg '-' or empty cell
c 0 = '-'
c _ = ' '

-- the # operator generates an amidakuji line containing one leg
-- which corresponds to one swap during bubble sort

-- terminal case, just one edge left
_ # 1 = "|"
-- each cell contains an edge '|' and either space or a '-' for the "active" cell
m # n = '|' : c m : (m - 1) # (n - 1)

-- helper to find the limit value of a function iteration
f % b
    | b == f b = b  -- return the value if it is unchanged by the function application 
    | otherwise = f % f b -- otherwise repeat

-- helper to appropriately combine q which is the result of invocation of 
-- the function g (see below), and a character p
p ? q = (p : fst q, snd q)

-- the function that does the work
f l = reverse $ snd $ (g 0) % (foldl p [1..n] l, []) where
    -- number of lines on the board
    n = 1 + div (length $ l !! 0) 2
    -- apply one iteration of bubble sort yielding (X, Y)
    -- where X is partially sorted list and Y is the output amidakuji
    g b ((x:y:z), a)
        -- if we need to swap two elements, do it and add a line to our board
        | x > y = y ? g (b + 1) (x:z, a ++ [b # n])
        -- if we don't need to, just proceed further
        | otherwise = x ? g (b + 1) (y:z, a)
    -- terminal case when there is only one element in the list
    g _ x = x

做得好!我向您的代码提供了数千张随机图,它解决了所有问题。
Tobia '18

(_:[])可以是公正的[_]p?q=(p:fst q,snd q)可以是公正的p?(f,s)=(p:f,s)。而不是定义c 0='-';c _=' ';然后使用c m" -"!!(0^abs m)应该可以工作。
Laikoni '18

(g 0)不需要括号且let护罩中的a小于where。总共274个字节:在线尝试!
Laikoni '18

您的定位点函数%可以用内联until(\x->g 0 x==x)(g 0)
Laikoni '18 -10-16

2

视网膜0.8.2,105字节

$
¶$%`
r`.?.\G
 1$.'$*
+r-1=`\|(-?.?[- 1]*¶.*)(1+)
$2$1
-
 
1G`
;{`\b(1+) \1
$1-$1
*`1+
|
(1+)-(1+)
$2 $1

在线尝试!说明:

$
¶$%`

复制最后一行。

r`.?.\G
 1$.'$*

在最后一行中对列编号。

+r-1=`\|(-?.?[- 1]*¶.*)(1+)
$2$1

向上移动数字,直到它们到达第一行。在每次迭代中,仅最右边的数字-1=被移动。|除非它前面有-,否则它将移动到最右边|。(这r表示正则表达式的处理就像是在后面一样,这使得在这种情况下的匹配稍微容易一些。)这将计算Amidakuji转换为排序顺序的排列。

-
 
1G`

仅保留数字列表,删除-s和第一行之后的所有内容。

;{`

然后,重复执行程序的其余部分,将列表重新排序,但最终列表未打印,但是Retina 0.8.2需要迭代才能注意到列表是按顺序排列的,因此没有分支的行是最后产生的,我相信这是可以接受的。

\b(1+) \1
$1-$1

-s 标记所有可用的成对的相邻未排序数字。

*`1+
|

打印支脚,但数字用|s 代替。

(1+)-(1+)
$2 $1

实际执行交换。


您对如何使用Retina.exe运行代码有任何建议吗?我认为我有正确的来源(105个字节),但没有输出。我从Retina示例中尝试了Hello World ,它可以工作。如果我的编码有误,可以将源代码上传到某个地方,或对Base64进行编码并将其放入pastebin中吗?
Tobia '18

@Tobia抱歉,但是我不记得如何使用Retina.exe;我想我可能曾经使用过一两次,但是现在我只使用在线试用。
尼尔

哈哈,我笨!我使用的是一些最先进的版本,而不是0.8.2。现在,我掌握了将数百张随机图输入到您的代码中的方法,并且可以确认它始终输出正确的素数。做得好!
托比亚

@Tobia感谢您的测试!视网膜1所需的调整:$**; -1=0; 1_; ;.(大致); **\
尼尔

1

Python 3中524个 488 486字节

-38字节感谢ovs!

from numpy import*
A=array;E=array_equal
K=[0]
def r(a,m,n):
	X=len(m);Y=len(m[0]);W,H=a.shape
	for x in range(W-X+1):
		for y in range(H-Y+1):
			if E(a[x:x+X,y:y+Y],A(m)):a[x:x+X,y:y+Y]=A(n)
	return a
def p(a):
	b=A([[j>" "for j in i]for i in[i.split("|")for i in a.split("\n")]])
	while E(a,b)<1:a=b;Z=K*3;O=[0,1,0];T=[K+O,O+K]*2;D=[O,O],[Z,Z];P=[Z,O],[O,Z];*R,_=T;_,*L=T;b=r(r(r(r(r(r(a[any(a,1)],R,L),*D),*P),L,R),*D),*P)
	for i in a:print("",*[" -"[j]for j in i[1:-1]],"",sep="|")

在线尝试!

这会将Amidakuji转换为2D二进制数组,并使用规则直接将其减少。


我对您的做法感到好奇;我会看一看!在此期间,您可以通过更换节省一些字节" "+i.replace("|","")+" "i.split("|")英寸 您p功能的第一行...
Chas Brown

一些标准的python golfing调整到479字节
Chas Brown


是的,不知道为什么会这样...
Chas Brown '18

并非总是...有时候右叉到左叉是不可行的,但是左叉到右叉是可行的。在这种特定情况下,只需要在那做相反的事情即可。也许我需要两者都做?
JosiahRyanW

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.