Pieces are demoted when captured.
[kaya.git] / lib / games / shogi / state.rb
blob03dee3a1146a58fce6ab6c5f56a7351181fb6637
1 require 'games/state_base'
2 require 'point'
4 module Shogi
5   class State < StateBase
6     def initialize(board, pool_factory, move_factory, piece_factory)
7       super(board, move_factory, piece_factory)
8       @pools = to_enum(:each_color).inject({}) do |res, c|
9         res[c] = pool_factory.new
10         res
11       end
12       @turn = :black
13     end
14     
15     def initialize_copy(other)
16       super
17       @pools = to_enum(:each_color).inject({}) do |res, c|
18         res[c] = other.pool(c).dup
19         res
20       end
21     end
22     
23     def pool(color)
24       @pools[color]
25     end
26     
27     def setup
28       each_color do |color|
29         (0...@board.size.x).each do |i|
30           @board[Point.new(i, row(2, color))] = piece_factory.new(color, :pawn)
31         end
32         
33         r = row(0, color)
34         set_piece = lambda do |x, type|
35           @board[Point.new(x, r)] = piece_factory.new(color, type)
36         end
37         set_piece[0, :lance]
38         set_piece[1, :horse]
39         set_piece[2, :silver]
40         set_piece[3, :gold]
41         set_piece[4, :king]
42         set_piece[5, :gold]
43         set_piece[6, :silver]
44         set_piece[7, :horse]
45         set_piece[8, :lance]
46         
47         r = row(1, color)
48         @board[Point.new(r, r)] = piece_factory.new(color, :rook)
49         @board[Point.new(@board.size.x - r - 1, r)] = piece_factory.new(color, :bishop)
50       end
51     end
52     
53     def each_color(&blk)
54       yield :black
55       yield :white
56     end
57     
58     def row(i, color)
59       color == :black ? @board.size.y - 1 - i : i
60     end
61     
62     def opposite_color(color)
63       color == :black ? :white : :black
64     end
65     
66     def direction(color)
67       Point.new(0, color == :black ? -1 : 1)
68     end
69     
70     def perform!(move)
71       if move.dropped
72         pool(turn).remove(move.dropped)
73         board[move.dst] = move.dropped
74       else
75         captured = basic_move(move)
76         if move.promote?
77           board[move.dst] = promoted(board[move.dst])
78         end
79         if captured
80           piece = piece_factory.new(turn, captured.type)
81           pool(turn).add(demoted(piece))
82         end
83         switch_turn!
84       end
85     end
86     
87     def switch_turn!
88       @turn = opposite_color(@turn)
89     end
90     
91     def in_promotion_zone?(p, color)
92       (row(6, color) <=> p.y) != (color == :black ? -1 : 1)
93     end
94     
95     def promoted(piece)
96       piece_factory.new(
97         piece.color, 
98         ('promoted_' + piece.type.to_s).to_sym)
99     end
100     
101     def demoted(piece)
102       piece_factory.new(
103         piece.color,
104         piece.type.to_s.gsub(/^promoted_/, '').to_sym)
105     end
106     
107     def promoted_type?(type)
108       type.to_s =~ /^promoted_/
109     end
110     
111     def promoted?(piece)
112       promoted_type? piece.type
113     end
114   end