-
Notifications
You must be signed in to change notification settings - Fork 0
/
board.rb
158 lines (122 loc) · 3.73 KB
/
board.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
require_relative 'all'
require "colorize"
class Board
ROW = 10
COL = 9
attr_reader :sentinel , :grid
def initialize
@sentinel = NullPiece.instance
@grid = Array.new(ROW) { Array.new(COL, @sentinel) }
set_initial_state
end
def [](pos)
raise 'invalid pos' unless valid_pos?(pos)
row, col = pos
@grid[row][col]
end
def []=(pos, piece)
raise 'invalid pos' unless valid_pos?(pos)
row, col = pos
@grid[row][col] = piece
end
def valid_pos?(pos)
pos[0].between?(0,ROW-1) && pos[1].between?(0,COL-1)
end
def possible_moves(color)
moves = {}
pieces.each do |piece|
if piece.color == color
moves[piece.pos] = piece.valid_moves
end
end
moves
end
def empty?(pos)
self[pos] == sentinel
end
def move_piece(turn_color, start_pos, end_pos)
raise 'start position is empty' if empty?(start_pos)
piece = self[start_pos]
if piece.color != turn_color
raise 'You must move your own piece'
elsif !piece.moves.include?(end_pos)
raise 'Piece does not move like that'
end
move_piece!(start_pos, end_pos)
end
def move_piece!(start_pos, end_pos)
piece = self[start_pos]
self[end_pos] = piece
self[start_pos] = sentinel
piece.pos = end_pos
nil
end
def set_initial_state
Chariots.new(:red, self, [0,0])
Chariots.new(:red, self, [0,8])
Chariots.new(:black, self, [9,8])
Chariots.new(:black, self, [9,0])
Horse.new(:red, self, [0,1])
Horse.new(:red, self, [0,7])
Horse.new(:black, self, [9,1])
Horse.new(:black, self, [9,7])
Elephant.new(:red, self, [0,2])
Elephant.new(:red, self, [0,6])
Elephant.new(:black, self, [9,2])
Elephant.new(:black, self, [9,6])
Advisor.new(:red, self, [0,3])
Advisor.new(:red, self, [0,5])
Advisor.new(:black, self, [9,3])
Advisor.new(:black, self, [9,5])
Cannon.new(:red, self, [2,1])
Cannon.new(:red, self, [2,7])
Cannon.new(:black, self, [7,1])
Cannon.new(:black, self, [7,7])
Soldier.new(:red, self, [3,0])
Soldier.new(:red, self, [3,2])
Soldier.new(:red, self, [3,4])
Soldier.new(:red, self, [3,6])
Soldier.new(:red, self, [3,8])
Soldier.new(:black, self, [6,0])
Soldier.new(:black, self, [6,2])
Soldier.new(:black, self, [6,4])
Soldier.new(:black, self, [6,6])
Soldier.new(:black, self, [6,8])
General.new(:red, self, [0,4])
General.new(:black, self, [9,4])
end
def dup
new_board = Board.new
pieces.each do |piece|
piece.class.new(piece.color, new_board, piece.pos)
end
new_board
end
def in_check?(color)
king_pos = find_king(color).pos
pieces.any? do |p|
p.color != color && p.moves.include?(king_pos)
end
end
def checkmate?(color)
return false unless in_check?(color)
pieces.select { |p| p.color == color }.all? do |piece|
piece.valid_moves.empty?
end
end
def pieces
pieces = []
@grid.each do |row|
row.each do |piece|
if piece != sentinel
pieces << piece
end
end
end
pieces
end
def find_king(color)
king_pos = pieces.find { |p| p.color == color && p.is_a?(General) }
king_pos || (raise "#{color} lost, game over!")
end
end