[QUIZ] Chess960 (#106)

R

Ruby Quiz

The three rules of Ruby Quiz:

1. Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.

2. Support Ruby Quiz by submitting ideas as often as you can:

http://www.rubyquiz.com/

3. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem helps everyone
on Ruby Talk follow the discussion. Please reply to the original quiz message,
if you can.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

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.

Output could be as follows.

Starting Position 432:

White

a1 b1 c1 d1 e1 f1 g1 h1
N B B R K R Q N

Black

a8 b8 c8 d8 e8 f8 g8 h8
N B B R K R Q N

Or some better output.
 
D

Daniel Martin

Ruby Quiz said:
Output could be as follows.

Starting Position 432:

White

a1 b1 c1 d1 e1 f1 g1 h1
N B B R K R Q N

Black

a8 b8 c8 d8 e8 f8 g8 h8
N B B R K R Q N

Or some better output.

Let me suggest that another potential output format is an html page
that when viewed in a browser looks like the opening format. I happen
to think that the chess boards shown on
http://www.pmwiki.org/wiki/Cookbook/ChessMarkup
look particularly nice, and shouldn't be too hard to duplicate.
(they're done as 8x8 tables, with the colors of the squares done by
CSS and the pieces being .png images with transparency) Presumably
some enterprising person could then churn out a Rails page that showed
a given starting position.

There's also this basic ascii art method: (black is the lowercase
letters)

nbbrkrqn
pppppppp
........
........
........
........
PPPPPPPP
NBBRKRQN

(It's traditional to show the place where white starts at the bottom,
and to number the rows upwards - that is, row "8" is at the top of the
diagram)

Then there's a FEN string inside PGN notation:

[Event "Starting Position 432"]
[SetUp "1"]
[FEN "nbbrkrqn/pppppppp/8/8/8/8/PPPPPPPP/NBBRKRQN w KQkq - 0 1" ]

The advantage of that format is that you can feed it right into
X-Board, WinBoard, or any other chess program that accepts PGN
notation, and it'll start play from that setup. (More on what that
FEN string means at
http://en.wikipedia.org/wiki/Forsyth-Edwards_Notation )
 
J

James Edward Gray II

There's also this basic ascii art method: (black is the lowercase
letters)

nbbrkrqn
pppppppp
........
........
........
........
PPPPPPPP
NBBRKRQN

Or with a touch more window dressing:

+---+---+---+---+---+---+---+---+
| n | b | b | r | k | r | q | n |
+---+---+---+---+---+---+---+---+
| p | p | p | p | p | p | p | p |
+---+---+---+---+---+---+---+---+
| | . | | . | | . | | . |
+---+---+---+---+---+---+---+---+
| . | | . | | . | | . | |
+---+---+---+---+---+---+---+---+
| | . | | . | | . | | . |
+---+---+---+---+---+---+---+---+
| . | | . | | . | | . | |
+---+---+---+---+---+---+---+---+
| P | P | P | P | P | P | P | P |
+---+---+---+---+---+---+---+---+
| N | B | B | R | K | R | Q | N |
+---+---+---+---+---+---+---+---+

James Edward Gray II
 
J

James Edward Gray II

Also, is the range of the numbers 0-956 or 1-960? I've seen things
saying that both are acceptable with no definitive answer.

Ask Ruby.

James Edward Gray II
 
M

Morton Goldberg

Ask Ruby.

I don't see how the Ruby interpreter can answer this question. How
the starting positions are to be numbered is a problem-domain-
specific issue. The interpreter knows nothing about the problem domain.

Ruby arrays being zero-based might make the range 0..959 more
convenient to use, but this certainly doesn't preclude the 1..960
numbering scheme from being adopted.

Regards, Morton
 
Z

znmeb

Quoting Morton Goldberg said:
I don't see how the Ruby interpreter can answer this question. How
the starting positions are to be numbered is a problem-domain-
specific issue. The interpreter knows nothing about the problem domain.

Ruby arrays being zero-based might make the range 0..959 more
convenient to use, but this certainly doesn't preclude the 1..960
numbering scheme from being adopted.

Regards, Morton
I believe the comment was meant to say, "write a correct Ruby program to solve
the problem and the correct number will emerge." :)
 
J

James Edward Gray II

I don't see how the Ruby interpreter can answer this question. How
the starting positions are to be numbered is a problem-domain-
specific issue. The interpreter knows nothing about the problem
domain.

Ruby arrays being zero-based might make the range 0..959 more
convenient to use, but this certainly doesn't preclude the 1..960
numbering scheme from being adopted.

0-959 was not an option in Daniel's email (look again) and I'm
confident of Ruby's ability to count to 960. ;)

James Edward Gray II
 
D

Daniel Finnie

Yeah, that was my typo.

I made my program 0 based because that is what most of the things online
seem to use, but that doesn't make it correct.

Dan
 
R

Rob Biedenharn

At the risk of being a spoiler (hint: don't go to the linked
Wikipedia article), the position 960 can also be called position 0:

The accurate sequence of White's Chess960 starting array
could be derived from its number as follows:
a) Divide the number by 960, determine the

remainder (0 ... 959) and use that number

thereafter.


-Rob

Yeah, that was my typo.

I made my program 0 based because that is what most of the things
online seem to use, but that doesn't make it correct.

Dan

http://en.wikipedia.org/wiki/Chess960_Enumbering_Scheme

Rob Biedenharn http://agileconsultingllc.com
(e-mail address removed)
 
J

Jamie Macey

Let me suggest that another potential output format is an html page
that when viewed in a browser looks like the opening format. I happen
to think that the chess boards shown on
http://www.pmwiki.org/wiki/Cookbook/ChessMarkup
look particularly nice, and shouldn't be too hard to duplicate.
(they're done as 8x8 tables, with the colors of the squares done by
CSS and the pieces being .png images with transparency) Presumably
some enterprising person could then churn out a Rails page that showed
a given starting position.

I haven't bothered generating the full table, I'm just randomly
generating the layouts. I thought the app was a bit too lightweight
for Rails, but I stole the images from pmwiki.org and set up a camping
app here: http://www.tracefunc.com:3301/ - just refresh for a
different layout.

If I can find more time this weekend, I'll see about doing the table
lookup and adding that info to the page.

- Jamie
 
R

Rob Biedenharn

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 Biedenharn http://agileconsultingllc.com
(e-mail address removed)


#!/usr/bin/env ruby -w
#
# Solution by: Rob Biedenharn
#
# From: (e-mail address removed)
# Subject: [QUIZ] Chess960 (#106)
# Date: December 15, 2006 8:50:58 AM EST
# To: (e-mail address removed)
#
# 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:
# http://en.wikipedia.org/wiki/Chess960_starting_position
#
# http://en.wikipedia.org/wiki/Chess960_Enumbering_Scheme
#
# 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__
 
D

Dave Burt

Dave said:
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
 
E

Eric I.

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.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)
 
D

Daniel Finnie

--Boundary_(ID_6svXY46JdpCkN+cKGpBBYA)
Content-type: text/plain; charset=ISO-8859-1; format=flowed
Content-transfer-encoding: 7BIT

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 http://frcec.tripod.com/fischerrandomchessstartingpositions/):
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 Capaldo 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.

Ruby said:
The three rules of Ruby Quiz:

1. Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.

2. Support Ruby Quiz by submitting ideas as often as you can:

http://www.rubyquiz.com/

3. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem helps everyone
on Ruby Talk follow the discussion. Please reply to the original quiz message,
if you can.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

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.

Output could be as follows.

Starting Position 432:

White

a1 b1 c1 d1 e1 f1 g1 h1
N B B R K R Q N

Black

a8 b8 c8 d8 e8 f8 g8 h8
N B B R K R Q N

Or some better output.

--Boundary_(ID_6svXY46JdpCkN+cKGpBBYA)
Content-type: application/x-ruby; name=arrayvalue.rb
Content-transfer-encoding: base64
Content-disposition: inline; filename=arrayvalue.rb

Y2xhc3MgQXJyYXlWYWx1ZQoJaW5zdGFuY2VfbWV0aG9kcy5lYWNoIGRvIHxtfAoJCXVuZGVm
X21ldGhvZChtKSB1bmxlc3MgbSA9fiAvXl8qKG1ldGhvZF9taXNzaW5nfHNlbmR8aWQpXyok
LwoJZW5kCgkKCWRlZiBpbml0aWFsaXplKG9yaWdBcnJheSwgb3JpZ0luZGV4KQoJCUBvcmln
QXJyYXksIEBvcmlnSW5kZXggPSBvcmlnQXJyYXksIG9yaWdJbmRleAoJZW5kCgkKCWRlZiBz
ZXQobmV3T2JqKQoJCUBvcmlnQXJyYXlbQG9yaWdJbmRleF0gPSBuZXdPYmoKCWVuZAoJCglk
ZWYgZ2V0CgkJQG9yaWdBcnJheVtAb3JpZ0luZGV4XQoJZW5kCgkKCWRlZiBtZXRob2RfbWlz
c2luZyhtZXRob2QsICphcmdzKQoJCQlnZXQuc2VuZChtZXRob2QsICphcmdzKQoJCXJlc2N1
ZQoJCQlzdXBlcgoJZW5kCgkKCWRlZmluZV9tZXRob2QoOic9ICcpIHt8b3RoZXJ8IHNldChv
dGhlcil9CmVuZAoKY2xhc3MgQXJyYXkKCWRlZiB0b19hdigpCgkJcmV0ID0gW10KCQllYWNo
X2luZGV4IHt8eHwgcmV0IDw8IEFycmF5VmFsdWUubmV3KHNlbGYsIHgpIH0KCQlyZXQKCWVu
ZAplbmQKCl9fRU5EX18KJSBjYXQgdmlldy5yYgpjbGFzcyBBcnJheVZpZXcKICBjbGFzcyBB
cnJheUluZGV4UmVmCiAgICBkZWYgaW5pdGlhbGl6ZSggYXJyYXksIGluZGV4ICkKICAgICAg
QGFycmF5ID0gYXJyYXkKICAgICAgQGluZGV4ID0gaW5kZXgKICAgIGVuZAoKICAgIGRlZiB2
YWx1ZQogICAgICBAYXJyYXlbQGluZGV4XQogICAgZW5kCgogICAgZGVmIHZhbHVlPShuZXdf
dmFsdWUpCiAgICAgIEBhcnJheVtAaW5kZXhdID0gbmV3X3ZhbHVlCiAgICBlbmQKICBlbmQK
CiAgZGVmIGluaXRpYWxpemUoIGFycmF5ICkKICAgIEBhcnJheSA9IGFycmF5CiAgICBAcmVm
ZXJlbmNlcyA9IFtdCiAgZW5kCgogIGRlZiBbXSgqYXJncykKICAgIGlmIGFyZ3MubGVuZ3Ro
ID09IDEgYW5kIGFyZ3Mua2luZF9vZj8gUmFuZ2Ugb3IgYXJncy5sZW5ndGggPiAxCiAgICAg
IEByZWZlcmVuY2VzWyphcmdzXS5tYXAgeyB8eHwgeC52YWx1ZSB9CiAgICBlbHNlCiAgICAg
IEByZWZlcmVuY2VzWyphcmdzXS52YWx1ZQogICAgZW5kCiAgZW5kCgogIGRlZiBbXT0oaW5k
ZXgsIHZhbHVlKQogICAgQHJlZmVyZW5jZXNbaW5kZXhdLnZhbHVlID0gdmFsdWUKICBlbmQK
CiAgZGVmIGVhY2gKICAgIEByZWZlcmVuY2VzLmVhY2ggZG8gfHh8CiAgICAgIHlpZWxkIHgu
dmFsdWUKICAgIGVuZAogIGVuZAoKCiAgZGVmIGFkZF9yZWYoIGluZGV4ICkKICAgIEByZWZl
cmVuY2VzIDw8IEFycmF5SW5kZXhSZWYubmV3KCBAYXJyYXksIGluZGV4ICkKICBlbmQKZW5k
CgoKY2xhc3MgQXJyYXkKICBkZWYgc2VsZWN0X3ZpZXcKICAgIHIgPSBBcnJheVZpZXcubmV3
KCBzZWxmICkKICAgIGVhY2hfd2l0aF9pbmRleCBkbyB8aXRlbSwgaW5kZXh8CiAgICAgIHIu
YWRkX3JlZiggaW5kZXggKSBpZiB5aWVsZCggaXRlbSApICAgICBlbmQKICAgIHIKICBlbmQK
ZW5kCgphID0gKDEuLjEwKS50b19hCgpwIGEKYiA9IGEuc2VsZWN0X3ZpZXcgeyB8eHwgKHgg
JSAyKS56ZXJvPyB9CmJbMF0gPSA0MgpwIGEKCiUgcnVieSB2aWV3LnJiClsxLCAyLCAzLCA0
LCA1LCA2LCA3LCA4LCA5LCAxMF0KWzEsIDQyLCAzLCA0LCA1LCA2LCA3LCA4LCA5LCAxMF0g

--Boundary_(ID_6svXY46JdpCkN+cKGpBBYA)
Content-type: application/x-ruby; name=chess960short.rb
Content-transfer-encoding: base64
Content-disposition: inline; filename=chess960short.rb

IyEgL3Vzci9iaW4vcnVieQpyZXF1aXJlICdhcnJheXZhbHVlLnJiJwoKS2VSTiA9IDw8LUVO
RC5zcGxpdCgiXG4iKS5jb2xsZWN0e3x4fCB4LnNwbGl0KCIgIil9CglOIE4gUiBLIFIKCU4g
UiBOIEsgUgoJTiBSIEsgTiBSCglOIFIgSyBSIE4KCVIgTiBOIEsgUgoJUiBOIEsgTiBSCglS
IE4gSyBSIE4KCVIgSyBOIE4gUgoJUiBLIE4gUiBOCglSIEsgUiBOIE4KCUVORAoKaWQgPSBB
UkdWWzBdLnRvX2kgJSA5NjAKb3V0ID0gQXJyYXkubmV3KDgpCjEuZG93bnRvKDApIHt8eHwg
b3V0W2lkICUgNCAqMiArIHhdID0gIkIiOyBpZCAvPSA0IH0Kb3V0LnRvX2F2LnNlbGVjdHt8
eHwgeC5uaWw/fVtpZCAlIDZdLnNldCgiUSIpOyBpZCAvPSA2CktlUk5baWRdLmVhY2h7IHxj
dXJyZW50UGllY2V8IG91dC50b19hdi5zZWxlY3R7fHh8IHgubmlsP30uZmlyc3Quc2V0KGN1
cnJlbnRQaWVjZSkgfQpwdXRzIG91dC5qb2lu

--Boundary_(ID_6svXY46JdpCkN+cKGpBBYA)--
 
D

Daniel Finnie

--Boundary_(ID_ZFfEe0zfyRXvGL7iUxL91g)
Content-type: text/plain; charset=ISO-8859-1; format=flowed
Content-transfer-encoding: 7BIT

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

Ruby said:
The three rules of Ruby Quiz:

1. Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.

2. Support Ruby Quiz by submitting ideas as often as you can:

http://www.rubyquiz.com/

3. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem helps everyone
on Ruby Talk follow the discussion. Please reply to the original quiz message,
if you can.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

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.

Output could be as follows.

Starting Position 432:

White

a1 b1 c1 d1 e1 f1 g1 h1
N B B R K R Q N

Black

a8 b8 c8 d8 e8 f8 g8 h8
N B B R K R Q N

Or some better output.

--Boundary_(ID_ZFfEe0zfyRXvGL7iUxL91g)
Content-type: application/x-ruby; name=chess960.rb
Content-transfer-encoding: base64
Content-disposition: inline; filename=chess960.rb

IyEgL3Vzci9iaW4vcnVieSAtdwpyZXF1aXJlICdhcnJheXZhbHVlLnJiJwpyZXF1aXJlICdy
dWJ5Z2VtcycKcmVxdWlyZSAnZmFjZXQvc3RyaW5nL2JyYWNrZXQnCgojIFJlcHJlc2VudHMg
YSByb3cgKCJyYW5rIikgb24gYSBjaGVzcyBib2FyZApjbGFzcyBDaGVzc1JvdyA8IEFycmF5
CglkZWYgaW5pdGlhbGl6ZQoJCXJlcGxhY2UoQXJyYXkubmV3KDgpKQoJZW5kCgkJCgkjIFNl
dHMgdGhlIHNwZWNpZmllZCB2YWNhbnQgc3F1YXJlIHRvIHRoZSBzcGVjaWZpZWQgcGllY2Us
IHdpdGggbnRoVmFjYW50IHN0YXJ0aW5nIGF0IDAuCglkZWYgc2V0VmFjYW50U3F1YXJlKG50
aFZhY2FudFNxdWFyZSwgcGllY2UpCgkJdG9fYXYuc2VsZWN0e3x4fCB4Lm5pbD99W250aFZh
Y2FudFNxdWFyZV0uc2V0KHBpZWNlKQoJZW5kCgkKCWRlZiB0b19zCgkJY29sbGVjdHt8eHwg
eC5icmFja2V0KCIgIil9LmpvaW4oInwiKS5icmFja2V0KCJ8IikKCWVuZAplbmQKCmNsYXNz
IENoZXNzOTYwUm93IDwgQ2hlc3NSb3cKCUtlUk4gPSA8PC1FTkQuc3BsaXQoIlxuIikuY29s
bGVjdHt8eHwgeC5zcGxpdCgiICIpfQoJTiBOIFIgSyBSCglOIFIgTiBLIFIKCU4gUiBLIE4g
UgoJTiBSIEsgUiBOCglSIE4gTiBLIFIKCVIgTiBLIE4gUgoJUiBOIEsgUiBOCglSIEsgTiBO
IFIKCVIgSyBOIFIgTgoJUiBLIFIgTiBOCglFTkQKCQoJZGVmIHNldEZyb21OdW0oaWQpCgkJ
IyBTZXQgdGhlIGJpc2hvcHMsIGxpZ2h0IGZpcnN0IHRoZW4gZGFyay4KCQkxLmRvd250bygw
KSBkbyB8eHwKCQkJc2VsZlsoaWQgJSA0KSoyICsgeF0gPSAiQiIKCQkJaWQgLz0gNAoJCWVu
ZAoJCQoJCSMgU2V0IHRoZSBxdWVlbgoJCXNldFZhY2FudFNxdWFyZShpZCAlIDYsICJRIikK
CQlpZCAvPSA2CgkJCgkJIyBTZXQgZXZlcnl0aGluZyBlbHNlIHVzaW5nIEtlUk4gY29kZXMu
CgkJS2VSTltpZF0uZWFjaCBkbyB8Y3VycmVudFBpZWNlfAoJCQlzZXRWYWNhbnRTcXVhcmUo
MCwgY3VycmVudFBpZWNlKQoJCWVuZAoJCXNlbGYKCWVuZAplbmQKClBhd25zID0gQ2hlc3NS
b3cubmV3LmZpbGwoInAiKS50b19zCkVtcHR5Um93cyA9IFtDaGVzc1Jvdy5uZXcuZmlsbCB7
fGl8IGkgJSAyID09IDA/ICIgIiA6ICIjIiB9LnRvX3MsCgkJCUNoZXNzUm93Lm5ldy5maWxs
IHt8aXwgaSAlIDIgPT0gMT8gIiAiIDogIiMiIH0udG9fc10KU3BhY2VyID0gIistLS0iICog
KFBhd25zLnRvX3MubGVuZ3RoIC8gNCkgKyAiKyIKCmRlZiBwYXJzZUlucHV0KGlucHV0KQoJ
Y2FzZSBpbnB1dAoJCXdoZW4gbmlsCgkJCXB1dHMgIlVzYWdlOiIsCgkJCQkiXHRjaGVzczk2
MCBhbGwgLSBQcmludCBhbGwgdGhlIHBvc3NpYmxlIENoZXNzOTYwIGxpbmV1cHMiLAoJCQkJ
Ilx0Y2hlc3M5NjAgcm5kIC0gUHJpbnQgYSByYW5kb20gQ2hlc3M5NjAgbGluZXVwIiwKCQkJ
CSJcdGNoZXNzOTYwIElEIC0gUHJpbnQgSUQgQ2hlc3M5NjAgbGluZXVwIgoJCXdoZW4gL2Fs
bC8KCQkJMC51cHRvKDk1OSkge3x4fCBwYXJzZUlucHV0KHgpIH0KCQl3aGVuIC8ocmE/bmQp
LwoJCQlwYXJzZUlucHV0KHJhbmQoOTYwKS50b19pKQoJCWVsc2UgIyBpcyBhIG51bWJlcgoJ
CQlpbnB1dCA9IGlucHV0LnRvX2kgJSA5NjAgIyBDaGFuZ2UgOTYwIGludG8gMC4KCQkJbWFp
blJvdyA9IENoZXNzOTYwUm93Lm5ldy5zZXRGcm9tTnVtKGlucHV0KS50b19zCgkJCVtpbnB1
dC50b19zICsgIjogIiwKCQkJCW1haW5Sb3cuZG93bmNhc2UsCgkJCQlQYXducy5kb3duY2Fz
ZSwKCQkJCUVtcHR5Um93cyAqIDIsCgkJCQlQYXducy51cGNhc2UsCgkJCQltYWluUm93LnVw
Y2FzZV0uCgkJCWZsYXR0ZW4uZWFjaHt8eHwgcHV0cyB4LCBTcGFjZXJ9CgllbmQKZW5kCnBh
cnNlSW5wdXQoQVJHVlswXSk=

--Boundary_(ID_ZFfEe0zfyRXvGL7iUxL91g)
Content-type: application/x-ruby; name=arrayvalue.rb
Content-transfer-encoding: base64
Content-disposition: inline; filename=arrayvalue.rb

Y2xhc3MgQXJyYXlWYWx1ZQoJaW5zdGFuY2VfbWV0aG9kcy5lYWNoIGRvIHxtfAoJCXVuZGVm
X21ldGhvZChtKSB1bmxlc3MgbSA9fiAvXl8qKG1ldGhvZF9taXNzaW5nfHNlbmR8aWQpXyok
LwoJZW5kCgkKCWRlZiBpbml0aWFsaXplKG9yaWdBcnJheSwgb3JpZ0luZGV4KQoJCUBvcmln
QXJyYXksIEBvcmlnSW5kZXggPSBvcmlnQXJyYXksIG9yaWdJbmRleAoJZW5kCgkKCWRlZiBz
ZXQobmV3T2JqKQoJCUBvcmlnQXJyYXlbQG9yaWdJbmRleF0gPSBuZXdPYmoKCWVuZAoJCglk
ZWYgZ2V0CgkJQG9yaWdBcnJheVtAb3JpZ0luZGV4XQoJZW5kCgkKCWRlZiBtZXRob2RfbWlz
c2luZyhtZXRob2QsICphcmdzKQoJCQlnZXQuc2VuZChtZXRob2QsICphcmdzKQoJCXJlc2N1
ZQoJCQlzdXBlcgoJZW5kCgkKCWRlZmluZV9tZXRob2QoOic9ICcpIHt8b3RoZXJ8IHNldChv
dGhlcil9CmVuZAoKY2xhc3MgQXJyYXkKCWRlZiB0b19hdigpCgkJcmV0ID0gW10KCQllYWNo
X2luZGV4IHt8eHwgcmV0IDw8IEFycmF5VmFsdWUubmV3KHNlbGYsIHgpIH0KCQlyZXQKCWVu
ZAplbmQKCl9fRU5EX18KJSBjYXQgdmlldy5yYgpjbGFzcyBBcnJheVZpZXcKICBjbGFzcyBB
cnJheUluZGV4UmVmCiAgICBkZWYgaW5pdGlhbGl6ZSggYXJyYXksIGluZGV4ICkKICAgICAg
QGFycmF5ID0gYXJyYXkKICAgICAgQGluZGV4ID0gaW5kZXgKICAgIGVuZAoKICAgIGRlZiB2
YWx1ZQogICAgICBAYXJyYXlbQGluZGV4XQogICAgZW5kCgogICAgZGVmIHZhbHVlPShuZXdf
dmFsdWUpCiAgICAgIEBhcnJheVtAaW5kZXhdID0gbmV3X3ZhbHVlCiAgICBlbmQKICBlbmQK
CiAgZGVmIGluaXRpYWxpemUoIGFycmF5ICkKICAgIEBhcnJheSA9IGFycmF5CiAgICBAcmVm
ZXJlbmNlcyA9IFtdCiAgZW5kCgogIGRlZiBbXSgqYXJncykKICAgIGlmIGFyZ3MubGVuZ3Ro
ID09IDEgYW5kIGFyZ3Mua2luZF9vZj8gUmFuZ2Ugb3IgYXJncy5sZW5ndGggPiAxCiAgICAg
IEByZWZlcmVuY2VzWyphcmdzXS5tYXAgeyB8eHwgeC52YWx1ZSB9CiAgICBlbHNlCiAgICAg
IEByZWZlcmVuY2VzWyphcmdzXS52YWx1ZQogICAgZW5kCiAgZW5kCgogIGRlZiBbXT0oaW5k
ZXgsIHZhbHVlKQogICAgQHJlZmVyZW5jZXNbaW5kZXhdLnZhbHVlID0gdmFsdWUKICBlbmQK
CiAgZGVmIGVhY2gKICAgIEByZWZlcmVuY2VzLmVhY2ggZG8gfHh8CiAgICAgIHlpZWxkIHgu
dmFsdWUKICAgIGVuZAogIGVuZAoKCiAgZGVmIGFkZF9yZWYoIGluZGV4ICkKICAgIEByZWZl
cmVuY2VzIDw8IEFycmF5SW5kZXhSZWYubmV3KCBAYXJyYXksIGluZGV4ICkKICBlbmQKZW5k
CgoKY2xhc3MgQXJyYXkKICBkZWYgc2VsZWN0X3ZpZXcKICAgIHIgPSBBcnJheVZpZXcubmV3
KCBzZWxmICkKICAgIGVhY2hfd2l0aF9pbmRleCBkbyB8aXRlbSwgaW5kZXh8CiAgICAgIHIu
YWRkX3JlZiggaW5kZXggKSBpZiB5aWVsZCggaXRlbSApICAgICBlbmQKICAgIHIKICBlbmQK
ZW5kCgphID0gKDEuLjEwKS50b19hCgpwIGEKYiA9IGEuc2VsZWN0X3ZpZXcgeyB8eHwgKHgg
JSAyKS56ZXJvPyB9CmJbMF0gPSA0MgpwIGEKCiUgcnVieSB2aWV3LnJiClsxLCAyLCAzLCA0
LCA1LCA2LCA3LCA4LCA5LCAxMF0KWzEsIDQyLCAzLCA0LCA1LCA2LCA3LCA4LCA5LCAxMF0g

--Boundary_(ID_ZFfEe0zfyRXvGL7iUxL91g)--
 
G

Gordon Thiesfeld

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?(p) && is_king_between_rooks?(p)
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
 
J

James Edward Gray II

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 Gray II
 
M

Morton Goldberg

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top