Ruby, 164169 164 148 bytes
->a{s=eval a*?^
c=?@
m={}
a.map{|x|z=x-(x^s);[$><<?-*z,x-=z,s=0]if z>0
b=x.to_s 2
n=2**b.sizen=1
b.chars{|y|n/=2;[$><<eval'x&1>0?[$><<(m[n]||c.next!)*n,m[n]=!m[n]&&c*1]if y>?0}m[n]&&c*1]:0;n*=2;x/=2;'*x
puts}}
First, we initialize
- the nim-sum with
s=eval a*?^
(which is shorter thana.reduce:^
) - the variable
c
, which stores the first unused unique character - a map
m
that maps power-of-two lengths to characters used to represent them
Then, looping over each pile, we run the following:
z=x-(x^s);[$><<?-*z,x-=z,s=0]if z>0
Per Wikipedia's strategy, if nim-sum XOR pile is less than pile, we should remove stones from that pile such that its length becomes nim-sum XOR pile. By storing the difference in the variable z
, we can test to see whether this difference is positive, and if so 1.) print that many dashes, 2.) subtract it from the pile, and 3.) set the nim-sum variable to zero to prevent further stone removal.
b=x.to_s 2n=1
n=2**beval'[.size..];n*=2;x/=2;'*x
Now we convert the (remaining, if any were removed) stones to binary"loop" over each bit and calculate the valuekeep track of their values by repeatedly dividing x
by 2
and multiplying the MSB to prepare toaccumulator n
by 2
. The loop overis actually a string evaluated x
times, which is far greater than the bitslog2(x)
times it's necessary, but no harm is done (aside from inefficiency). For each bit, we divide the accumulator by 2 (to get the value of the bit in question) and run the following if the bit is 1 (x&1>0
):
$><<(m[n]||c.next!)*n
Print a character n
times. If we already printed an unpaired group of this many stones, use that character; otherwise, use the next unused character (advancing c
in-place due to the !
).
m[n]=!m[n]&&c*1
If m[n]
existed (i.e. we just completed a pair), then m[n]
is reset. Otherwise, we just started a new pair, so set m[n]
to the character we used (*1
is a short way to make a copy of c
).