改进工作 "Bulgarian Solitaire" J 动词

Improve a working "Bulgarian Solitaire" J verb

"Bulgarian Solitaire" 是一种数学好奇心。它是用一副 45 张(任何三角形数字都可以)未标记的牌来玩的。将它们放入随机大小的堆中。然后,要玩一轮,从每堆中取出一张牌,并用取出的牌创建一个新牌堆。重复此步骤最终得到配置 1 2 3 4 5 6 7 8 9(对于 45 张牌),这显然是游戏的固定点,因此单人纸牌游戏结束。我想在J中模拟这个游戏。

经过几天的思考和对 J 动名词的一些期待已久的洞察,我想出了一个解决方案,我想听听一些意见。它以这个动词开头:

bsol =: ((#~ ~:&0) , #)@:(-&1)^:(<_)

给定一个正整数向量,其总和为三角形,这个动词 returns 一个 2 阶数组,显示产生的单人纸牌轮数。我也想出了这个动词来生成初始配置,但我对此不太满意:

t     =: 45 & - @ (+/) NB. Would work with any triangular number
cards =: (]`(]@,>:@?&t@]))@.(0&<@t)^:_

给定一个由正整数组成的向量 yt returns 45 的缺陷,即 45 - +/ y 的牌数未计入所代表的牌堆中由论据。使用 t,动词 cards 向这样的向量 y 重复添加来自 >: i. t y 的整数,直到缺陷为 0。

显式扩展t,我得到

cards =: (]`(]@,>:@?&(45 & - @ (+/))@]))@.(0&<@(45 & - @ (+/)))^:_

我觉得这不是很简短,而且括号可能过分了。但它确实有效,完整的解决方案现在看起来像这样:

bsol @ cards @ >: @ ? 44 NB. Choose the first pile randomly from >: i. 44

没有命名动词:

(((#~ ~:&0) , #)@:(-&1)^:(<_)) @: ((]`(]@,>:@?&(45 & - @ (+/))@]))@.(0&<@(45 & - @ (+/)))^:_)@>:@? 44

对J习语了解不多,我对此也有同感:不是很简短,肯定是多余的(这里用t这样的地方动词会不会更好,因为它重复了,例如?),并且可能过度括号。我有什么机会改进这个程序?

您可以通过

改进 t
t =: 45 - +/ 

使用 46 - +/ 会节省一些 >:

您可以用递归定义替换cards

cards =: }.`(($:@] , -) ?)@.(0&<)

现在,cards n 生成总和为 n 的初始配置。

bsol 中,如果删除 (-.) 零并重新排列,则不需要 -&1

 bsol =: (0 -.~ [:  (, #) <:)^:(<_)