I don't want to spoil all the fun, in case anyone is still attempting this quiz, but here's my solution to four of the seven variations:
#!/usr/local/bin/ruby -w
# blackhole_chess
···
#
# Created by James Edward Gray II on 2005-06-20.
# Copyright 2005 Gray Productions. All rights reserved.
require "chess"
# An enhanced chess board for playing Blackhole Chess.
class BlackholeChess < Chess::Board
#
# A general purpose test to see if a _test_ square is between _start_ and
# _finish_ squares, on a rank, file or diagonal.
#
def self.between?( start, finish, test )
test_rank, test_file = test[1, 1].to_i, test[0]
start_rank, start_file = start[1, 1].to_i, start[0]
finish_rank, finish_file = finish[1, 1].to_i, finish[0]
( test_rank == start_rank and test_rank == finish_rank and
test_file >= [start_file, finish_file].min and
test_file <= [start_file, finish_file].max ) or
( test_file == start_file and test_file == finish_file and
test_rank >= [start_rank, finish_rank].min and
test_rank <= [start_rank, finish_rank].max ) or
( (start_file - finish_file).abs == (start_rank - finish_rank).abs and
(start_file - test_file).abs == (start_rank - test_rank).abs and
(test_file - finish_file).abs == (test_rank - finish_rank).abs and
test_file >= [start_file, finish_file].min and
test_file <= [start_file, finish_file].max and
test_rank >= [start_rank, finish_rank].min and
test_rank <= [start_rank, finish_rank].max )
end
# End the game if a King goes missing.
def in_checkmate?( who = @turn )
if find { |(s, pc)| pc and pc.color == who and pc.is_a? Chess::King }
super
else
true
end
end
# Eliminate any piece moving through the blackholes.
def move( from_square, to_square, promote_to = nil )
if self.class.between?(from_square, to_square, "d5") or
self.class.between?(from_square, to_square, "f5")
@squares[from_square] = nil
next_turn
else
super
end
self
end
# Board display with two added blackholes.
def to_s( )
super.sub( /^(5\s+\|(?:[^|]+\|){3})[^|]+\|([^|]+\|)[^|]+\|/,
"\\1 * |\\2 * |" )
end
end
board = BlackholeChess.new
# insert my chess inteface code (see Summary) here, with a minor addition to spot
# a king that falls into a blackhole
__END__
#!/usr/local/bin/ruby -w
# fairy_chess
#
# Created by James Edward Gray II on 2005-06-20.
# Copyright 2005 Gray Productions. All rights reserved.
require "chess"
#
# The container for the behavior of a chess fairy. Fairies are simply treated
# as both a Queen and a Knight.
#
class Fairy < Chess::Queen
#
# Returns all the capturing moves for a Fairy on the provided _board_
# at the provided _square_ of the provided _color_.
#
def self.captures( board, square, color )
captures = Chess::Queen.captures(board, square, color)
captures += Chess::Knight.captures(board, square, color)
captures.sort
end
#
# Returns all the non-capturing moves for a Fairy on the provided
# _board_ at the provided _square_ of the provided _color_.
#
def self.moves( board, square, color )
moves = Chess::Queen.moves(board, square, color)
moves += Chess::Knight.moves(board, square, color)
moves.sort
end
end
# Make the Chess::King aware of the Fairy.
class FairyAwareKing < Chess::King
# Enhance in_check? to spot special Fairy moves.
def self.in_check?( bd, sq, col )
return true if Chess::Knight.captures(bd, sq, col).any? do |name>
bd[name].is_a?(Fairy)
end
Chess::King.in_check?( bd, sq, col )
end
# Make this piece show up as a normal King.
def to_s( )
if @color == :white then "K" else "k" end
end
end
# An enhanced chess board for playing Fairy Chess.
class FairyChess < Chess::Board
# Setup a normal board, then replace the queens with fairies.
def setup( )
super
@squares["d1"] = Fairy.new(self, "d1", :white)
@squares["d8"] = Fairy.new(self, "d8", :black)
@squares["e1"] = FairyAwareKing.new(self, "e1", :white)
@squares["e8"] = FairyAwareKing.new(self, "e8", :black)
end
end
board = FairyChess.new
# insert my chess inteface code (see Summary) here
__END__
#!/usr/local/bin/ruby -w
# fibonacci_chess
#
# Created by James Edward Gray II on 2005-06-20.
# Copyright 2005 Gray Productions. All rights reserved.
require "chess"
# An enhanced chess board for playing Fibonacci Chess.
class FibonacciBoard < Chess::Board
# Setup chess board and initialize move count sequence.
def initialize( )
super
@fib1 = nil
@fib2 = nil
@count = 1
end
# Advance turn, as players complete moves in the Fibonacci sequence.
def next_turn( )
if @fib1.nil?
@fib1 = 1
elsif @fib2.nil?
@fib2 = 2
next_turn if in_check?(@turn == :white ? :black : :white)
elsif @count.zero? or in_check?(@turn == :white ? :black : :white)
@fib1, @fib2 = @fib2, @fib1 + @fib2
@count = @fib2 - 1
else
@count -= 1
return
end
super
end
# Return a String description of the moves remaining.
def moves_remaining( )
if @fib1.nil? or @fib2.nil? or @count.zero?
"last move"
else
"#{@count + 1} moves"
end
end
end
board = FibonacciBoard.new
# insert my chess inteface code (see Summary) here
__END__
#!/usr/local/bin/ruby -w
# gun_chess
#
# Created by James Edward Gray II on 2005-06-20.
# Copyright 2005 Gray Productions. All rights reserved.
require "chess"
# An enhanced chess board for playing Gun Chess.
class GunChess < Chess::Board
# Returns a numerical count of all the pieces on the board.
def count_pieces( )
find_all { |(square, piece)| piece }.size
end
# Make standard chess moves, save that capturing pieces do not move.
def move( from_square, to_square, promote_to = nil )
old_count = count_pieces
super # normal chess move
if count_pieces < old_count # if it was a capture...
move(to_square, from_square) # move the piece back
next_turn # fix the extra turn change
end
self
end
end
board = GunChess.new
# insert my chess inteface code (see Summary) here, with a minor addition to
# promote pawns on moves only, never captures
__END__
You can download the complete files here:
http://rubyquiz.com/ruby_quiz_chess.zip
I was surprised that this wasn't harder. I didn't tailor my library to the variations and I chose random variations to solve. I expected the library would need enhancements for some, but that didn't seem to be the case, at least for these four variations.
James Edward Gray II