Chess960 (#106)

William J. wrote:

960 such positions, thus the name Chess960.
that the king never starts on file a or h, because there would be no room for a
(k+1…7).each{|r2|
puts s.downcase,‘p’*8,(’.’*8+"\n")*4,‘P’*8,s
end } } } } } }

Using Scharnagl’s numbering.

if “all” == ARGV.first
range = (1…960)
else
n = ARGV.first
n = n && Integer( n ) || rand(960) + 1
range = (n…n)
end

def empty( ary )
ary.select{|x| x.class==Fixnum}
end

range.each{|which|
num = which % 960
row = Array.new(8){|i| i}
num, bishop = num.divmod( 4 )
row[ bishop2 + 1 ] = “B”
num, bishop = num.divmod( 4 )
row[ bishop
2 ] = “B”
num, queen = num.divmod( 6 )
row[ empty( row )[queen] ] = “Q”
avail = empty( row )
while num / (avail.size - 1 ) > 0
avail.shift
num -= avail.size
end
row[ avail.first ] = “N”
avail.shift
row[ avail[ num % avail.size ] ] = “N”
empty( row ).zip( %w(R K R) ).each{|i,piece| row[i] = piece}
puts “\nPosition #{ which }”
s = row.join
puts s.downcase,‘p’*8,(’.’*8+"\n")*4,‘P’*8,s
}

I am attaching two solutions: the first one generates all the positions
in an “unofficial” order (however, it takes advantage of symmetry and
“only” computes 480 and mirrors them) and the official one using a
“nifty” :slight_smile: algorithm (basically the wikipedia one with tables but
arithmetizing
the tables). The second one is clearer and commented

first one: simple

class Chess960
@@boards = []

def boards
@@boards
end

def initialize
board = Board.new()
(0…2).each do |lr|
board << lr
(lr+1…3).each do |k|
board << k
(k+1…7).each do |rr|
board << rr
board.free_.each do |q|
board << q
board.free_.find_all{|x| x.odd?}.each do |bb|
board << bb
board.free_.find_all{|x| x.even?}.each do |wb|
board << wb
@@boards << b = board.to_s
@@boards << board.to_s.reverse
board.pop
end # white bishop
board.pop
end # black bishop
board.pop
end # queen
board.pop
end # right rook
board.pop
end # king
board.pop
end # left rook
puts @@boards.length
end

def to_human(i)
lrow = @@boards[i]
lrow.downcase + “p” * 8 + “32” + “P” * 8 + lrow
end

def get_one
i = rand(960)
to_human(i)
end

def
return @@boards[n]
end

end

class Fixnum

def odd?
self % 2 == 0 ? false : true
end

def even?
not(self.odd?)
end

end

class Board

attr_reader :free_, :position

@@pieces = %w(R K R Q B B N N)

def initialize()
@position = []
@free_ = (0…7).to_a - @position
end

def to_s
order = “N” * 8
@position.each_with_index do |p,i|
order[p] = @@pieces[i]
end
return order
end

def <<(n)
@position << n
@free_ = @free_ - [n]
end

def pop
@free_ << @position.pop
end

end
#######
####### second one: “official” and with standard board notation
#!/usr/bin/ruby

class Chess960

private_class_method :new

@@all = []

def Chess960.setup
(0…959).each do |i|
@@all << Board.new(i)
end
true
end

def Chess960.
@@all[n]
end

def Chess960.random()
self.get(rand(960)).to_s
end

Position p is decomposed as

p = 96n + 16q + b with

(0…15) === b, (0…5) === q, and

(0…9) === n. See bottom for an

explanation

class Board

attr_reader :board

def initialize(p)
  @board = Hash.new()
  bishop = p % 16
  nights = (p - (p % 96)) / 96
  queen = ((p % 96) - bishop) / 16
  @board = iposition(bishop, nights, queen)
end

def to_s
  return "[FEN " + board.join("").downcase + "/" + "p" * 8 +
           "/8/8/8/8/" + "P" * 8 + "/" + board.join("") + " w KQkq - 

0
1]"
end

private

def bishop(i)
  white = (i - (black = i % 4)) / 4
  return ([ (white * 2), black * 2 + 1])
end

def nights(i)
  case i
  when 9
    n1, n2 = 3, 4
  when 7,8
    n1, n2 = 2, 3 + (i % 7)
  else
    n1 = ( i - i % 3) / 3
    n2 = i % 3 + 1
  end
  return ([n1,n2])
end

def queen(i) # dummy but easier to understand
  return i
end

# see the explanation at bottom for this method's algorithm
def iposition(b, n, q)
  base =  %w(R R R R R R)
  @board = %w(B B B B B B B B)
  # put the queen in its place in "all-but-bishops"
  base[queen(q)] = "Q"
  # put the knights in their place in "all-but-bishops"
  nights(n).each do |x|
    (x < queen(q) && base[x] = "N") or (base[x+1] = "N")
  end
  # place the King: substitute the middle Rook by a King
  # and finish (simpler than reading the code)
  king = false
  base.each_with_index do |p,i|
    (king == true and base[i] == "R" and base[i] = "K" and break)
    (p == "R" && king = true)
  end

  # and now put the bishops in place, ie: keeping the
  # bishops in their place, put all the other pieces
  # in their order
  minus = 0
  bish = bishop(b)
  (0..7).each do |i|
    if bish.include?(i)
      minus += 1
      next
    end
    @board[i] = base[i-minus]
  end
  return @board
end

end

true
end

explanation of p = 96n + 16q + b

Bishops’ position. Give the bottom squares (a1…h1)

the following values:

0,0,4,1,8,2,12,3

Any number b = 0…15 can be written uniquely as

b = wb + bb

with wb in a white square and bb in a black one

This gives bishops’ table.

Consider the six remaining pieces, and number a

six-row from 0 to 5 from left to right:

0,1,2,3,4,5

The position of the queen inside that row is q

Finally, let the remaining five squares be numbered

0,1,2,3,4

For the right knight, the values of each square are

-, 0, 1, 2, 3 (the first one does not count bc is

never filled by the right one)

For the left knight, the corresponding values are

0, 3, 5, 6, - (ibid.)

Now every number (0…9) can be written uniquely as

ln + rn (left knight + right knight) using two

different position on the 5-row

Place the rooks and king in the remaining three squares

following the r-k-r rule and the board is built.

Thanks for the quiz,

Pedro

Here is my solution. Run with no argument, it generates a random
initial position. Run with an argument in the range 1…960, it
provides the initial position for the specified game. It uses
Scharnagl’s method which is quite easy to implement in Ruby.

Here is what it produces when given 519 as its argument:

Initial position 519
rnbqkbnr
pppppppp




PPPPPPPP
RNBQKBNR

Regards, Morton

#! /usr/bin/env ruby -w # # Ruby Q. 106 -- Chess960 Starting Positions # Implementation uses Scharnagl's tables. See # http://en.wikipedia.org/wiki/Chess960_starting_position

class Chess960
BISHOP_TABLE = [
“BB------”, #0
“B–B----”, #1
“B----B–”, #2
“B------B”, #3
“-BB-----”, #4
“–BB----”, #5
“–B--B–”, #6
“–B----B”, #7
“-B–B—”, #8
“—BB—”, #9
“----BB–”, #10
“----B–B”, #11
“-B----B-”, #12
“—B–B-”, #13
“-----BB-”, #14
“------BB” #15
]

N5N_TABLE = [
   "NN---", #0
   "N-N--", #1
   "N--N-", #2
   "N---N", #3
   "-NN--", #4
   "-N-N-", #5
   "-N--N", #6
   "--NN-", #7
   "--N-N", #8
   "---NN"  #9
]

def initialize(number)
   q, @bishop_index = (number - 1).divmod 16
   @knight_index, @queen_index = q.divmod 6
   @white_pieces = BISHOP_TABLE[@bishop_index].split('')
   @white_pieces[nth_dash(@queen_index)] = 'Q'
   knights = N5N_TABLE[@knight_index]
   m = knights.index('N')
   n = knights.index('N', m + 1)
   m, n = nth_dash(m), nth_dash(n)
   @white_pieces[m] = 'N'
   @white_pieces[n] = 'N'
   @white_pieces[@white_pieces.index('-')] = 'R'
   @white_pieces[@white_pieces.index('-')] = 'K'
   @white_pieces[@white_pieces.index('-')] = 'R'
end

def nth_dash(n)
   dashes = []
   @white_pieces.each_with_index { |ch, i| dashes << i if ch ==

‘-’ }
dashes[n]
end

def inspect
   @white_pieces.join
end

def to_s
   white_pieces = @white_pieces.join + "\n"
   white_pawns = 'P' * 8 + "\n"
   black_pieces = white_pieces.downcase
   black_pawns = 'p' * 8 + "\n"
   empty = ('.' * 8 + "\n") * 4
   black_pieces + black_pawns + empty + white_pawns + white_pieces
end

end

if FILE == $0
begin
if ARGV.empty? then n = 1 + rand(960)
else
n = ARGV.first.to_i
raise StandardError unless (1…960).include?(n)
end
puts “Initial position #{n}”
print Chess960.new(n).to_s
rescue StandardError
puts “Usage: #{$PROGRAM_NAME} []”
puts “where is in 1…960”
puts “Omitting produces a random initial position”
end
end

I found the Wikipedia article that described the
Chess960_Enumbering_Scheme and used its direct derivation of the
placement from the number. The relevant portion of the article is
mixed in as comments in the code below.

-Rob

Rob B. http://agileconsultingllc.com
[email protected]

#!/usr/bin/env ruby -w

Solution by: Rob B.

From: [email protected]

Subject: [QUIZ] Chess960 (#106)

Date: December 15, 2006 8:50:58 AM EST

To: [email protected]

by Kieran Wild

Chess960, is a chess variant produced by Grandmaster Bobby Fischer by

formalizing the rules of Shuffle Chess. Its goal was to create a chess

variant in which chess creativity and talent would be more

important than

memorization and analysis of opening moves. His approach was to

create a

randomized initial chess position, which would thus make memorizing

chess

opening move sequences far less helpful. The initial position is

set up in a

special way and there are 960 such positions, thus the name Chess960.

The starting position for Chess960 must meet certain rules. White

pawns are

placed on the second rank as in chess. All remaining white pieces

are placed

randomly on the first rank, but with the following restrictions:

* The king is placed somewhere between the two rooks.

* The bishops are placed on opposite-colored squares.

The black pieces are placed equal-and-opposite to the white pieces.

For

example, if the white king is placed on b1, then the black king is

placed on

b8. Note that the king never starts on file a or h, because there

would be

no room for a rook

Can I suggest a nice little ruby program to generates all 960 possible

starting positions and outputs a random one on request.



From wikipedia:

Fischer random chess - Wikipedia

Fischer random chess numbering scheme - Wikipedia

Direct Derivation

The accurate sequence of White’s Chess960 starting array could be

derived

from its number as follows:

debug=ENV[‘DEBUG’]
puts “ARGV: #{ARGV.join(', ')}” if debug

starting_position = ARGV.empty? ? rand(960) : ARGV[0].to_i
string = ‘-’ * 8

a) Divide the number by 960, determine the remainder (0 … 959)

and use

that number thereafter.

temp = starting_position % 960

puts “starting_position #{starting_position}” if debug
puts “a) #{string}” if debug

b) Divide the number by 4, determine the remainder (0 … 3) and

correspondingly place a Bishop upon the matching bright square (b,

d, f, h).
temp,lb = temp.divmod 4
string[2*lb+1]=‘B’

puts “b) #{lb} #{string} #{temp}” if debug

c) Divide the number by 4, determine the remainder (0 … 3) and

correspondingly place a Bishop upon the matching dark square (a, c,

e, g).
temp,db = temp.divmod 4
string[2*db]=‘B’

puts “c) #{db} #{string} #{temp}” if debug

d) Divide the number by 6, determine the remainder (0 … 5) und

correspondingly place the Queen upon the matching of the six free

squares.
n,q = temp.divmod 6
print "d) #{q} " if debug
string.gsub!(/-/) { |p| p=‘Q’ if q.zero?; q -= 1; p }
puts “#{string} #{n}” if debug

e) Now only one digit (0 … 9) is left on hand; place the both

Knights upon

the remaining five free squares according to following scheme:

Digit Knights’ Positioning

0 N N - - -

1 N - N - -

2 N - - N -

3 N - - - N

4 - N N - -

5 - N - N -

6 - N - - N

7 - - N N -

8 - - N - N

9 - - - N N

require ‘enumerator’
class Integer
def comb(r=1)
if self < r or r < 1
elsif r == 1
0.upto(self-1) { |x| yield [x] }
else
(0…self).each_cons(1) do |i|
(self-1).comb(r-1) do |j|
next if j.last + i.last >= self-1
bump=i.last+1
yield(i + j.map! { |e| e+bump })
end
end
end
end
end

print "e) #{n} " if debug
5.comb(2) do |c|

puts “comb: #{c.join(’ ')}” if debug

if n.zero?
c.reverse.each do |q|
string.gsub!(/-/) { |p| p=‘N’ if q.zero?; q -= 1; p }
end
break
end
n -= 1
end

puts “#{string}” if debug

f) The now still remaining three free squares will be filled in the

following sequence: Rook, King, Rook.

puts “f)” if debug
%w[ R K R ].each do |p|
string[string.index(‘-’)] = p
puts " #{string}" if debug
end

fen = "#{string.downcase}/#{‘p’*8}/8/8/8/8/#{‘P’*8}/#{string} w KQkq

  • 0 1"

puts %{[Event “Starting Position #{starting_position}”]}
puts %{[SetUp “1”]}
puts %{[FEN “#{fen}”]}

END

Dave B. wrote:

D:\Docs\ruby>ruby chess960.rb
[Event “Starting Position 787”]
[SetUp “1”]
[FEN “bbrnkrqn/pppppppp/8/8/8/8/PPPPPPPP/BBRNKRQN w KQkq - 0 1” ]

My program lies about the number. I like my numbering scheme, but I
understand another is standard.

Cheers,
Dave

I decided to make a second submission that uses the official board
position numbering scheme as described on Wikipedia.

Eric

Interested in Ruby Training? See http://learnruby.com .


Generates a string that describes a given layout.

def display(layout)
[[“White”, 1], [“Black”, 8]].map do |color, rank|
color << “\n” <<
(‘a’…‘h’).map { |file| file + rank.to_s }.join(" “) << “\n” <<
layout.map{|sym| sym.to_s.upcase}.join(” “) << “\n”
end.join(”\n")
end

Places the given piece in an empty cell of positions indexed by

index.

def place_in_empty(positions, index, piece)
positions[(0…7).to_a.select { |i| positions[i].nil? }[index]] =
piece
end

index = (ARGV[0] || rand(960)).to_i
index %= 960

positions = Array.new(8)

positions[(index % 4) * 2 + 1] = :b
index /= 4

positions[(index % 4) * 2] = :b
index /= 4

place_in_empty(positions, index % 6, :q)
index /= 6

[[0, 1], [0, 2], [0, 3], [0, 4], [1, 2],
[1, 3], [1, 4], [2, 3], [2, 4], [3, 4]][index].reverse.each do |i|
place_in_empty(positions, i, :n)
end

place_in_empty(positions, 0, :r)
place_in_empty(positions, 0, :k)
place_in_empty(positions, 0, :r)

puts display(positions)

This is the full version of the quiz that I wrote first. It uses the
ArrayValues class which is described in my previous email. I think it
is adequately documented as it is, especially because the algorithm and
main logic parts are described in the previous email. Run with no
options to get the usage. One thing to say, though is that the facets
bracket method is basically this:
class String
def bracket(wrapper)
wrapper + self + wrapper
end
end

It is actually more complex, there is a second argument you can pass in.

daniel@daniel-desktop:~$ cat chess960.rb
#! /usr/bin/ruby -w
require ‘arrayvalue.rb’
require ‘rubygems’
require ‘facet/string/bracket’

Represents a row (“rank”) on a chess board

class ChessRow < Array
def initialize
replace(Array.new(8))
end

     # Sets the specified vacant square to the specified piece, with

nthVacant starting at 0.
def setVacantSquare(nthVacantSquare, piece)
to_av.select{|x| x.nil?}[nthVacantSquare].set(piece)
end

     def to_s
             collect{|x| x.bracket(" ")}.join("|").bracket("|")
     end

end

class Chess960Row < ChessRow
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

     def setFromNum(id)
             # Set the bishops, light first then dark.
             1.downto(0) do |x|
                     self[(id % 4)*2 + x] = "B"
                     id /= 4
             end

             # Set the queen
             setVacantSquare(id % 6, "Q")
             id /= 6

             # Set everything else using KeRN codes.
             KeRN[id].each do |currentPiece|
                     setVacantSquare(0, currentPiece)
             end
             self
     end

end

Pawns = ChessRow.new.fill(“p”).to_s
EmptyRows = [ChessRow.new.fill {|i| i % 2 == 0? " " : “#” }.to_s,
ChessRow.new.fill {|i| i % 2 == 1? " " : “#”
}.to_s]
Spacer = “±–” * (Pawns.to_s.length / 4) + “+”

def parseInput(input)
case input
when nil
puts “Usage:”,
“\tchess960 all - Print all the
possible Chess960 lineups”,
“\tchess960 rnd - Print a random
Chess960 lineup”,
“\tchess960 ID - Print ID Chess960
lineup”
when /all/
0.upto(959) {|x| parseInput(x) }
when /(ra?nd)/
parseInput(rand(960).to_i)
else # is a number
input = input.to_i % 960 # Change 960 into 0.
mainRow =
Chess960Row.new.setFromNum(input).to_s
[input.to_s + ": ",
mainRow.downcase,
Pawns.downcase,
EmptyRows * 2,
Pawns.upcase,
mainRow.upcase].
flatten.each{|x| puts x, Spacer}
end
end
parseInput(ARGV[0])

I wrote two solutions. The first one finds all solutions, but it is
slow (takes about 12 seconds on my machine). I got around this by
writing the results to a yaml file and using that for subsequent runs.
My second solution just picks a random permutation until if finds one
that meets the requirements.

chess960.rb

require ‘permutation’
require ‘yaml’

file = ‘positions.yml’

def create_positions_file(file, pieces)
positions = Permutation.for(pieces).map{|p| p.project}.uniq
positions = positions.select do |p|
are_bishops_on_opposite_colors?§ && is_king_between_rooks?§
end

File.open(file ,‘w+’){|f| f.write(YAML::dump(positions))}
end

def are_bishops_on_opposite_colors?(a)
(a.index(‘B’) + a.rindex(‘B’)).modulo(2) != 0
end

def is_king_between_rooks?(a)
(a.index(‘R’) < a.index(‘K’)) && (a.index(‘K’) < a.rindex(‘R’))
end

create_positions_file(file, %w{R N B K Q B N R}) unless
File.exist?(file)

positions = YAML::load_file(file)

random = rand(positions.size)
puts “Starting position #{random}:”

{1 => ‘White’, 8 => ‘Black’}.sort.each do |k, color|
place = (‘a’…‘h’).to_a.join(k.to_s + ’ ‘) + k.to_s
puts "\n#{color}\n\n#{place}\n #{positions[random].join(’ ')}"
end

#eof

#chess960_2.rb
require ‘permutation’

def bishops_on_opposite_colors?(a)
(a.index(‘B’) + a.rindex(‘B’)).modulo(2) != 0
end

def king_between_rooks?(a)
(a.index(‘R’) < a.index(‘K’)) && (a.index(‘K’) < a.rindex(‘R’))
end

pieces = %w{R N B K Q B N R}

loop do
@positions = Permutation.for(pieces).random.project(pieces)
break if bishops_on_opposite_colors?(@positions) &&
king_between_rooks?(@positions)
end

{1 => ‘White’, 8 => ‘Black’}.sort.each do |k, color|
place = (‘a’…‘h’).to_a.join(k.to_s + ’ ‘) + k.to_s
puts "\n#{color}\n\n#{place}\n #{@positions.join(’ ')}"
end

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):

  1. id % 4 * 2 = light square bishop (counting left to right
  2. (id / 4) % 4 * 2 + 1 = dark square bishop ^ starting at 0)
  3. (id / 4 / 6) % 6 = queen, number of vacant squares from the left
  4. (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.

On Dec 18, 2006, at 7:11 AM, Morton G. wrote:

  q, @bishop_index = (number - 1).divmod 16

I’m not sure why you subtract one here, but removing that seems to
put your solution inline with output of the others.

James Edward G. II

On Dec 18, 2006, at 7:11 AM, Morton G. wrote:

RNBQKBNR
But isn’t the standard position 518?

James Edward G. II

On Dec 20, 2006, at 4:10 PM, James Edward G. II wrote:


PPPPPPPP
RNBQKBNR

But isn’t the standard position 518?

Fischer random chess numbering scheme - Wikipedia

On Dec 18, 2006, at 7:11 AM, Morton G. wrote:

  q, @bishop_index = (number - 1).divmod 16

I’m not sure why you subtract one here, but removing that seems to
put your solution inline with output of the others.

The answer to both questions is: I’m just being perverse. I decided
to a use one-based numbering scheme, not a zero-based one, so the
initial positions come out numbered 1 - 960. Look at the usage output
in the rescue clause at the end of the script.

If I were to redo it, I would use the standard zero-based numbering.

Regards, Morton

On Dec 20, 2006, at 11:02 PM, Morton G. wrote:

  q, @bishop_index = (number - 1).divmod 16

I’m not sure why you subtract one here, but removing that seems to
put your solution inline with output of the others.

The answer to both questions is: I’m just being perverse. I decided
to a use one-based numbering scheme, not a zero-based one, so the
initial positions come out numbered 1 - 960.

Just FYI, a one-base numbering scheme is described on Wikipedia, but
it differs from you system.

James Edward G. II