1 # Copyright (c) 2009 Paolo Capriotti <p.capriotti@gmail.com>
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
8 require 'games/chess/san'
14 def initialize(rep, validator_factory,
15 move_factory, piece_factory,
18 @validator = validator_factory
20 @piece = piece_factory
24 def serialize(move, ref)
27 ysize = ref.board.size.y
28 result = move.src.to_coord(ysize) + move.dst.to_coord(ysize)
29 result += '=' + @piece.symbol(move.promotion) if move.promotion
32 san move, ref, lambda{|t| @piece.symbol(t) }
34 san move, ref, lambda{|t| "{#{t.to_s}}" }
38 def deserialize(s, ref)
39 notation = @notation.read(s)
40 read_san ref, notation if notation
43 def read_san(ref, san)
45 return candidate unless san[:dst] or san[:castling]
46 validate = @validator.new(ref)
49 # find king starting position
50 src = Point.new(ref.board.size.x / 2, ref.row(0, ref.turn))
51 dst = src + (san[:castling] == :king ? Point.new(2, 0) : Point.new(-2, 0))
53 return candidate unless king.type == :king
54 candidate = @move.new(src, dst)
55 candidate if validate[candidate]
56 elsif san[:src] and san[:src].x and san[:src].y
57 mv = @move.new(san[:src], san[:dst], :promotion => san[:promotion])
60 ref.board.each_square do |p|
61 mv = @move.new(p, san[:dst], :promotion => san[:promotion])
63 if p =~ san[:src] and piece and
64 piece.type == san[:type] and
65 piece.color == ref.turn
80 def san(move, ref, sym)
81 piece = ref.board[move.src]
83 return "" unless piece
84 return "0-0" if move.type == :king_side_castling
85 return "0-0-0" if move.type == :queen_side_castling
87 capture_square = ref.capture_square(move)
88 captured = ref.board[capture_square]
91 ysize = ref.board.size.y
93 if piece.type == :pawn
95 result = Point.new(move.src.x, nil).to_coord(ysize) + 'x'
99 result += move.dst.to_coord(ysize)
101 result = sym[piece.type]
102 san = minimal_notation ref,
107 result += san[:src].to_coord(ysize) if san[:src]
108 result += 'x' if captured
109 result += san[:dst].to_coord(ysize)
113 result += '=' + sym[move.promotion]
119 def minimal_notation(ref, san)
120 @notation.each_alternative(san) do |alternative|
121 return alternative if read_san(ref, alternative)