-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathboard.rb
189 lines (141 loc) · 4.49 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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
require './pieces'
require 'colorize'
class Board
attr_accessor :cursor, :player_moves
attr_reader :grid
def self.new_game(grid = Array.new(8) { Array.new(8, nil) })
board = Board.new(grid)
8.times do |idx|
Pawn.new(board, [idx, 1], :black)
end
8.times do |idx|
Pawn.new(board, [idx, 6], :white)
end
Rook.new(board, [0, 0], :black)
Rook.new(board, [7, 0], :black)
Rook.new(board, [0, 7], :white)
Rook.new(board, [7, 7], :white)
Knight.new(board, [1, 0], :black)
Knight.new(board, [6, 0], :black)
Knight.new(board, [1, 7], :white)
Knight.new(board, [6, 7], :white)
Bishop.new(board, [2, 0], :black)
Bishop.new(board, [5, 0], :black)
Bishop.new(board, [2, 7], :white)
Bishop.new(board, [5, 7], :white)
King.new(board, [4, 0], :black)
King.new(board, [4, 7], :white)
Queen.new(board, [3, 0], :black)
Queen.new(board, [3, 7], :white)
board
end
def initialize(grid)
@grid, @cursor, @player_moves = grid, [0, 0], []
end
def [](position)
x, y = position
@grid[y][x]
end
def []=(position, piece)
x, y = position
@grid[y][x] = piece
end
def to_s
color = :white
board_str = Array.new(8) { Array.new(8, " ") }
pieces.each do |piece|
x, y = piece.position
board_str[y][x] = " #{piece} ".blue if piece.color == :white
board_str[y][x] = " #{piece} ".red if piece.color == :black
end
@grid.each_with_index do |row, row_idx|
row.each_with_index do |tile, col_idx|
piece = board_str[row_idx][col_idx]
piece = piece.on_light_white if color == :white
piece = piece.on_black if color == :black
board_str[row_idx][col_idx] = piece
color = color == :white ? :black : :white unless col_idx == 7
end
end
if !@player_moves.empty?
selected_tile = board_str[@player_moves.first[1]][@player_moves.first[0]]
selected_tile = selected_tile.on_green
board_str[@player_moves.first[1]][@player_moves.first[0]] = selected_tile
valid_moves = self[@player_moves.first].valid_moves
valid_moves.each do |move|
x, y = move
board_str[y][x] = board_str[y][x].on_yellow
end
end
board_str.each_with_index { |row, idx| row << (" #{idx + 1}")}
board_str << (' a '..' h ').to_a
board_str[@cursor[1]][@cursor[0]] = board_str[@cursor[1]][@cursor[0]].on_cyan
board_str.map { |row| row.join("") }.join("\n")
end
def is_valid?(position)
x, y = position
x.between?(0, 7) && y.between?(0, 7)
end
def in_check?(color)
king = king(color)
opp_pieces = pieces_for(other_color(color))
opp_pieces.any? do |piece|
piece.moves.include?(king.position)
end
end
def pieces
@grid.flatten.compact
end
def pieces_for(color)
pieces.select { |piece| piece.color == color }
end
def other_color(color)
color == :white ? :black : :white
end
def king(color)
pieces.find { |piece| piece.is_a?(King) && piece.color == color }
end
def move(start_position, end_position)
current_piece = self[start_position]
raise MoveError.new("Invalid start position!") if current_piece.nil?
unless current_piece.valid_moves.include?(end_position)
raise MoveError.new("Invalid ending position!")
end
current_piece.position = end_position
self[start_position] = nil
check_for_queen_status(current_piece, end_position)
self[end_position] = current_piece
end
def move!(start_position, end_position)
current_piece = self[start_position]
raise MoveError.new("Invalid start position!") if current_piece.nil?
if !current_piece.moves.include?(end_position)
raise MoveError.new("Invalid ending position!")
end
current_piece.position = end_position
self[start_position] = nil
check_for_queen_status(current_piece, end_position)
self[end_position] = current_piece
end
def checkmate?(color)
pieces_for(color).all? do |piece|
piece.valid_moves.empty?
end
end
def check_for_queen_status(current_piece, end_position)
if current_piece.is_a?(Pawn) &&
(end_position[1] == 0 ||
end_position[1] == 7)
current_piece = Queen.new(self, end_position, current_piece.color)
end
end
def dup
new_grid = @grid.map do |row|
row.map { |item| item.nil? ? nil : item.dup }
end
new_board = Board.new(new_grid)
new_board.pieces.each { |piece| piece.board = new_board }
new_board
end
end
class MoveError < ArgumentError; end