On 12/15/06, Ruby Quiz <james / grayproductions.net> wrote:
> 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.

I just did up a random generator using the die-rolling method
mentioned on Wikipedia.  As such, it's not deterministic, so my boards
can't be referenced by number.

After my Chess360 class is a Camping app to host it - my current code
is live at http://tracefunc.com:3301/ - the images were shamelessly stolen from
http://www.pmwiki.org/wiki/Cookbook/ChessMarkup, and the whole thing
(code plus images) can be downloaded from
http://tracefunc.com/chess960.zip - I'd've attached it but ruby-talk
rejected it as too large a message.

- Jamie


class Chess960
  attr_reader :board_id, :board

  def initialize
    @board = generate_board(bodlaender_line)
  end

  def generate_board(white)
    # Black's starting line is mirror of white's
    black = white.map{|piece| piece.downcase}

    # middle of board is always the same
    middle = [
      %w(p p p p p p p p),
      %w(_ _ _ _ _ _ _ _),
      %w(_ _ _ _ _ _ _ _),
      %w(_ _ _ _ _ _ _ _),
      %w(_ _ _ _ _ _ _ _),
      %w(P P P P P P P P)
    ]

    # add back rows
    [black] + middle + [white]
  end

  def bodlaender_line
    free = (0...8).to_a
    white = []

    dark_bishop = rand(4) * 2
    light_bishop = rand(4) * 2 + 1
    white[dark_bishop] = 'B'
    white[light_bishop] = 'B'
    free.delete(dark_bishop)
    free.delete(light_bishop)

    queen = rand(6)
    white[free[queen]] = 'Q'
    free.delete_at(queen)

    knight1 = rand(5)
    white[free[knight1]] = 'N'
    free.delete_at(knight1)
    knight2 = rand(4)
    white[free[knight2]] = 'N'
    free.delete_at(knight2)

    white[free[0]] = 'R'
    white[free[1]] = 'K'
    white[free[2]] = 'R'
    white
  end
end

###########

require 'rubygems'
require 'camping'
require 'chess960'

Camping.goes :Chess

module Chess::Controllers
  # main page
  class Index < R '/'
    def get
      @chess = Chess960.new
      render :index
    end
  end

  # image passthrough
  class Images < R '/images/(.+)'
    MIME_TYPES = {'.png' => 'image/png'}
    PATH = __FILE__[/(.*)\//, 1]

    def get(path)
      @headers['Content-Type'] = MIME_TYPES[path[/\.\w+$/, 0]] || "text/plain"
      unless path =~ /\.\./ # sample test to prevent directory traversal attacks
        @headers['X-Sendfile'] = "#{PATH}/images/#{path}"
      else
        "404 - Invalid path"
      end
    end
  end
end

module Chess::Views
  def layout
    html do
      body do
        style :type => 'text/css' do
          "#chess { border-collapse: collapse;
                    float: left; margin-right: 2em; } " +
          ".dark { background-color: #888; } " +
          ".light { background-color: #ddd; } " +
          ".thin { width: 50em; } "
        end
        self << yield
      end
    end
  end

  def index
    c = 0
    table.chess! do
      @chess.board.each do |row|
        c = 1 - c
        tr do
          row.each do |tile|
            c = 1 - c
            td :class => c==0 ? 'light' : 'dark' do
              img :src => "images/#{tile}.png"
            end
          end
        end
      end
    end
    h1 "Chess 960"
    div.thin do
      text "<p>Randomly created board, using the #{a 'Bodlaendar', :href =>
         "http://en.wikipedia.org/wiki/Chess960#Determining_a_starting_position"}
         method for generating piece order.</p>"
      p "Result was #{@chess.board.last.join(", ")}."
    end
  end
end