6 def initialize(piece_factory, size)
7 @piece_factory = piece_factory
11 def from_scanner(scanner)
12 if scanner.scan(/([PRNBKQ])?([a-wyzA-Z]?\d*|x\d+)([-x@])?([a-zA-Z]\d+)(=?([RNBKQrnbkq]))?[+#]?[\?!]*/)
13 { :type => @piece_factory.type_from_symbol(scanner[1] || 'P'),
14 :drop => drop = scanner[3] == '@',
15 :src => (Point.from_coord(scanner[2], @size.y) unless drop),
16 :dst => Point.from_coord(scanner[4], @size.y),
17 :promotion => (@piece_factory.type_from_symbol(scanner[6]) if scanner[6]) }
18 elsif scanner.scan(/^[oO0]-?[oO0]-?[oO0][+#]?/)
19 { :castling => :queen }
20 elsif scanner.scan(/[oO0]-?[oO0][+#]?/)
21 { :castling => :king }
23 scanner.scan(/none/) # possibly consume 'none'
29 from_scanner(StringScanner.new(str))
41 def each_alternative(san)
42 # try notation without starting point
43 yield san.dup.tap{|s| s[:src] = nil }
46 yield san.dup.tap{|s| s[:src] = Point.new(s[:src].x, nil) }
48 # add column indication
49 yield san.dup.tap{|s| s[:src] = Point.new(nil, s[:src].y) }