This is my solution. It makes use of my ArrayValue class which was
discussed on the list previously. It calculate the placement of pieces
for a certain number without first calculating the placement of the
pieces for all numbers lower than it by using the following algorithm
(found at Fischer Random Chess Starting Positions):
- id % 4 * 2 = light square bishop (counting left to right
- (id / 4) % 4 * 2 + 1 = dark square bishop ^ starting at 0)
- (id / 4 / 6) % 6 = queen, number of vacant squares from the left
- (id / 4 / 6) = KeRN code of the other pieces (see the website for
more. The KeRN codes do have a pattern but I hard coded it).
First, an explaination of the ArrayValue class. The code is below:
daniel@daniel-desktop:~$ cat arrayvalue.rb
class ArrayValue
instance_methods.each do |m|
undef_method(m) unless m =~
/^*(method_missing|send|id)*$/
end
def initialize(origArray, origIndex)
@origArray, @origIndex = origArray, origIndex
end
def set(newObj)
@origArray[@origIndex] = newObj
end
def get
@origArray[@origIndex]
end
def method_missing(method, *args)
get.send(method, *args)
rescue
super
end
define_method(:'= ') {|other| set(other)}
end
class Array
def to_av()
ret = []
each_index {|x| ret << ArrayValue.new(self, x) }
ret
end
end
So, an ArrayValue stores the array and index it originally came from and
it can edit/get those values. Otherwise, an ArrayValue inherits all of
the methods of the value it represents because of the method_missing
definition. One thing missing from the ArrayValue class is what to do
if CRD (CRUD minus the U) operations are performed on the original
array. Because of this, I recommend never actually storing an
ArrayValue but creating them again every time you need one.
Also, the array class is edited to provide a to_av method, which returns
an array of ArrayValues. This is the only recommended way of creating
ArrayValues.
Note that Logan C. wrote something with the same concept but that
uses some tricks with arrays and overriding []= so that calling
ArrayValue#Set is not necessary, you just go
ArrayOfArrayValues[0]=Something and it changes the original array.
Some uses of ArrayValue:
daniel@daniel-desktop:~$ irb -r arrayvalue.rb
irb(main):001:0> ary = [1, 2, 3, “a”, :b]
=> [1, 2, 3, “a”, :b]
irb(main):002:0> ary.to_av[4].set(“c”)
=> “c”
irb(main):003:0> ary
=> [1, 2, 3, “a”, “c”]
irb(main):005:0> ary.to_av.select{|x| x.kind_of?(Numeric)}.each{|x|
x.set(42)}
=> [42, 42, 42]
irb(main):006:0> ary
=> [42, 42, 42, “a”, “c”]
irb(main):013:0> ary = [“Skip me!”, nil, nil, nil, 43]
=> [“Skip me!”, nil, nil, nil, 43]
irb(main):014:0> ary.to_av.select{|x| x.nil?}[1].set(“The 2nd nil”)
=> “The 2nd nil”
irb(main):015:0> ary
=> [“Skip me!”, nil, “The 2nd nil”, nil, 43]
Now to the real code:
daniel@daniel-desktop:~$ cat chess960short.rb
#! /usr/bin/ruby
require ‘arrayvalue.rb’
KeRN = <<-END.split(“\n”).collect{|x| x.split(" ")}
N N R K R
N R N K R
N R K N R
N R K R N
R N N K R
R N K N R
R N K R N
R K N N R
R K N R N
R K R N N
END
id = ARGV[0].to_i % 960
out = Array.new(8)
1.downto(0) {|x| out[id % 4 *2 + x] = “B”; id /= 4 }
out.to_av.select{|x| x.nil?}[id % 6].set(“Q”); id /= 6
KeRN[id].each{ |currentPiece| out.to_av.select{|x|
x.nil?}.first.set(currentPiece) }
Another, commented and not written for brevity version will be posted
shortly.