[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

James Edward Gray II wrote:

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:

I've been working on adding checkmate detection to my Bangkok-based solution from last week. I added check detection, which was easy. Checkmate seems harder, unless I'm missing something. I need to figure out all possible moves for all pieces on the checked side, then make the move and re-check the board to see if the king is still in check. Is that what I have to do, or am I without clue?

Jim

···

--
Jim Menard, jimm@io.com, http://www.io.com/~jimm
"Do Squeakers Dream of Electric Mice?" -- Mike Thomas
     (http://www.squeak.org)

That's how I did it. I believe that's about the best method because you have to consider things like moving a piece in to block the check.

James Edward Gray II

···

On Jun 20, 2005, at 3:56 PM, Jim Menard wrote:

I've been working on adding checkmate detection to my Bangkok-based solution from last week. I added check detection, which was easy. Checkmate seems harder, unless I'm missing something. I need to figure out all possible moves for all pieces on the checked side, then make the move and re-check the board to see if the king is still in check. Is that what I have to do, or am I without clue?

James Edward Gray II wrote:

I've been working on adding checkmate detection to my Bangkok-based solution from last week. I added check detection, which was easy. Checkmate seems harder, unless I'm missing something. I need to figure out all possible moves for all pieces on the checked side, then make the move and re-check the board to see if the king is still in check. Is that what I have to do, or am I without clue?

That's how I did it. I believe that's about the best method because you have to consider things like moving a piece in to block the check.

James Edward Gray II

It would seem that the space of "all possible moves by all possible pieces" could be reduced greatly be examining whether or not a given "checked" piece could possibly move to a space that blocks an attack on the king by an attacking piece. A relatively small number of spaces meet this criteria compared to the size of the board, and a relatively small number of pieces are likely to meet the criteria.

If the attacking piece were a knight or fairy, the possibility of moving a piece other than the king can be rejected out of hand, as can the case where two checking pieces simultaneously check the king.

I could easily be missing something. Hasn't been a sharp week for me! But wait, it's only Monday...

Cheers,

Jim

···

On Jun 20, 2005, at 3:56 PM, Jim Menard wrote:

I completely agree. It's just trickier and checking all the moves is plenty fast enough, for a two player game, so I didn't bother.

James Edward Gray II

···

On Jun 20, 2005, at 5:22 PM, Jim Van Fleet wrote:

It would seem that the space of "all possible moves by all possible pieces" could be reduced greatly be examining whether or not a given "checked" piece could possibly move to a space that blocks an attack on the king by an attacking piece.

Jim Van Fleet wrote:

If the attacking piece were a knight or fairy, the possibility of moving a piece other than the king can be rejected out of hand, as can the case where two checking pieces simultaneously check the king.

It's not that simple. It may be possible to capture the attacking piece without moving the king. If two pieces are attacking, capturing one of the pieces may block the other piece's attack.

···

--
Glenn Parker | glenn.parker-AT-comcast.net | <http://www.tetrafoil.com/&gt;

Double check rules out everything but moving the King, so that should be an easy enough special case to handle, if you can spot it to begin with.

James Edward Gray II

···

On Jun 20, 2005, at 6:14 PM, Glenn Parker wrote:

It's not that simple. It may be possible to capture the attacking piece without moving the king. If two pieces are attacking, capturing one of the pieces may block the other piece's attack.

James Edward Gray II wrote:

···

On Jun 20, 2005, at 6:14 PM, Glenn Parker wrote:

It's not that simple. It may be possible to capture the attacking piece without moving the king. If two pieces are attacking, capturing one of the pieces may block the other piece's attack.

Double check rules out everything but moving the King, so that should be an easy enough special case to handle, if you can spot it to begin with.

Um, no. Double check does not rule out everything but moving the king. Read the last sentence of my original reply again.

--
Glenn Parker | glenn.parker-AT-comcast.net | <http://www.tetrafoil.com/&gt;

I'm a tournament chess player and I assure you it's only possible to leave double check by moving the king (in standard chess). I do invite you to show a position that proves otherwise though... :wink:

James Edward Gray II

···

On Jun 20, 2005, at 8:10 PM, Glenn Parker wrote:

Um, no. Double check does not rule out everything but moving the king. Read the last sentence of my original reply again.

If capturing a piece blocks the other piece's attack, then the original
piece must necessarily have been blocking the other piece's attack too
(at least with the standard piece set and rules). The one loophole might
have been a pawn jumping two squares, imposing both direct and
discovered check, and being captured en passant in such a way that the
discovered check is blocked (that's the only instance where a capturing
piece doesn't occupy the square of the piece it captured), but looking
at the way the pieces move that's impossible too.

martin

···

Glenn Parker <glenn.parker@comcast.net> wrote:

James Edward Gray II wrote:
> On Jun 20, 2005, at 6:14 PM, Glenn Parker wrote:
>
>> It's not that simple. It may be possible to capture the attacking
>> piece without moving the king. If two pieces are attacking,
>> capturing one of the pieces may block the other piece's attack.
>
> Double check rules out everything but moving the King, so that should
> be an easy enough special case to handle, if you can spot it to begin
> with.

Um, no. Double check does not rule out everything but moving the king.
  Read the last sentence of my original reply again.

James Edward Gray II wrote:

···

On Jun 20, 2005, at 8:10 PM, Glenn Parker wrote:

Um, no. Double check does not rule out everything but moving the king. Read the last sentence of my original reply again.

I'm a tournament chess player and I assure you it's only possible to leave double check by moving the king (in standard chess).

Well, I didn't think we were talking about (just) standard chess here. The point of the two-part quiz was to examine the flexibility necessary to handle chess variants. If one assumes that check situations can always be simplified according to standard chess logic, then that seems like a potential weakness in the system.

--
Glenn Parker | glenn.parker-AT-comcast.net | <http://www.tetrafoil.com/&gt;

Well, I didn't think we were talking about (just) standard chess here.

Very true, changing the rules of the game does complicate this.

If one assumes that check situations can always be simplified according to standard chess logic, then that seems like a potential weakness in the system.

On the other hand, it's impossible to plan for all the variations of chess, so we can't let that bug us too much. Some variations do away with check entirely (like Extinction Chess in this week's quiz).

It's probably more important to ensure that check is extendable and/or replaceable, as needed. See my solution to Fairy Chess for an example of this.

James Edward Gray II

···

On Jun 21, 2005, at 9:47 AM, Glenn Parker wrote: