123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- module ChessData
- # A PositionDefinition is a collection of criteria (matchers) which define
- # a valid type of position.
- #
- # e.g. some kind of Rook endings.
- #
- # database.select do
- # at_least 5, "P"
- # exactly 1, "R"
- # at_most 4, "p"
- # exactly 1, "r"
- # end
- #
- class PositionDefinition
- # The constructor evaluates the provided _block_, to set up the user's
- # board criteria. It then sets up some default criteria for the king's and
- # pieces not covered by the block.
- def initialize(&block)
- @matchers = []
- instance_eval(&block)
- # fill in a default matcher for any not present
- ["K", "k"].each do |piece|
- unless @matchers.any? {|matcher| matcher.piece == piece}
- exactly 1, piece
- end
- end
- ["P", "p", "N", "n", "B", "b", "R", "r", "Q", "q"].each do |piece|
- unless @matchers.any? {|matcher| matcher.piece == piece}
- exactly 0, piece
- end
- end
- end
- # Checks that all the criteria are matched by the given board.
- def check board
- @matchers.all? do |matcher|
- matcher.check board
- end
- end
- private
- # following methods used in block to constructor as DSL
- # for a pattern definition
- def exactly n, *pieces
- pieces.each do |piece|
- @matchers << ExactCount.new(n, piece)
- end
- end
- def at_least n, *pieces
- pieces.each do |piece|
- @matchers << AtLeastCount.new(n, piece)
- end
- end
- def at_most n, *pieces
- pieces.each do |piece|
- @matchers << AtMostCount.new(n, piece)
- end
- end
- end
- # parent class for the different types of count comparators
- class Counter
- attr_reader :piece
- # Each counter has a target _piece_ and reference number _n_.
- def initialize n, piece
- @n = n
- @piece = piece
- end
- end
- # The ExactCount class checks that there are exactly _n_ of the
- # named piece on the board.
- class ExactCount < Counter
- # Returns true if board contains _n_ of _piece_
- def check board
- board.count(@piece) == @n
- end
- end
- # The AtLeastCount class checks that there are at least _n_ of the
- # named piece on the board.
- class AtLeastCount < Counter
- # Returns true if board contains at least _n_ of _piece_
- def check board
- board.count(@piece) >= @n
- end
- end
- # The AtMostCount class checks that there are at most _n_ of the
- # named piece on the board.
- class AtMostCount < Counter
- # Returns true if board contains at most _n_ of _piece_
- def check board
- board.count(@piece) <= @n
- end
- end
- end
|