From: James Edward Gray II Date: 2005-06-21T05:26:53+09:00 Subject: [SOLUTION] Chess Variants (II) (#36) 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