Dave R
Dave R

Reputation: 73

Improve a working "Bulgarian Solitaire" J verb

"Bulgarian Solitaire" is a mathematical curiosity. It is played with a deck of 45 (any triangular number will work) unmarked cards. Put them into randomly sized piles. Then, to play a round, remove a card from each pile and create a new pile with the removed cards. Repeating this step eventually yields the configuration 1 2 3 4 5 6 7 8 9 (for 45 cards), which is clearly a fixed point of the game and thus the end of the solitaire. I wanted to simulate this game in J.

After a couple of days thinking about it and some long-awaited insight into J gerunds, I came up with a solution, on which I would like some opinions. It starts with this verb:

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

Given a vector of positive integers whose sum is triangular, this verb returns a rank 2 array showing the rounds of the solitaire that results. I also came up with this verb to generate an initial configuration, but I'm less happy with it:

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

Given a vector y of positive integers, t returns the defect from 45, i.e., the number 45 - +/ y of cards not accounted for in the piles represented by the argument. Using t, the verb cards appends to such a vector y an integer from >: i. t y repeatedly until the defect is 0.

Expanding t explicitly, I get

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

I feel like this is not very brief, and maybe overly parenthesized. But it does work, and the complete solution now looks like this:

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

Without the named verbs:

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

Not knowing much about J idiom, I have the same feeling about this: it's not very brief, certainly redundant (would it be better to use a local verb like t here, since it's repeated, e.g.?), and probably overly parenthesized. What opportunities do I have to improve this program?

Upvotes: 3

Views: 286

Answers (1)

Eelvex
Eelvex

Reputation: 9153

You can improve t with

t =: 45 - +/ 

Using 46 - +/ will spare you some >:.

You can replace cards with a recursive definition:

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

where, now, cards n produces an initial configuration with sum n.

In bsol you don't need -&1 if you remove (-.) the zeroes and rearrange it like:

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

Upvotes: 3

Related Questions