我正在为构建国际象棋游戏的学生项目研究一些Ruby逻辑。目前我正在尝试编写执行castling移动所需的逻辑。
根据我的测试,castling应该可以工作,但是当玩游戏时,似乎只有白方可以成功城堡。当黑方试图城堡时,它被视为无效移动。我想知道castle!
模型中的方法king.rb
是否未在move_to!
模型中的pieces.rb
方法中正确调用,或者是否存在更大的问题确定哪个玩家转向的方法(参见pass_turn!
中的game.rb
)?我意识到这个问题有点模糊,但我很困惑,可以用一些帮助搞清楚这里发生了什么。
王模特
class King < Piece
def valid_move?(x, y)
if super(x, y)
if legal_castle_move?
castle!
true
else
return standard_king_move?(x, y)
end
end
false
end
def checkmate?
# example logic
end
def castle!
if can_castle_queenside?
castle_queenside
else can_castle_kingside?
castle_kingside
end
end
def can_castle_kingside?
rook = game.pieces.where(piece_type: 'Rook', x_position: 7, state: 'unmoved').take
if rook.nil?
return false
else
legal_castle_move? && no_kingside_obstruction?
end
end
def castle_kingside
rook = game.pieces.where(piece_type: 'Rook', x_position: 7).take
king = game.pieces.where(piece_type: 'King', x_position: 4).take
if rook.color == 'WHITE' && king.color == 'WHITE'
rook.update_attributes(x_position: 5, state: 'moved')
king.update_attributes(x_position: 6, state: 'moved')
else rook.color == 'BLACK' && king.color == 'BLACK'
rook.update_attributes(x_position: 5, state: 'moved')
king.update_attributes(x_position: 6, state: 'moved')
end
rook.reload
king.reload
end
def can_castle_queenside?
rook = game.pieces.where(piece_type: 'Rook', x_position: 0, state: 'unmoved').take
if rook.nil?
return false
else
legal_castle_move? && no_queenside_obstruction?
end
end
def castle_queenside
rook = game.pieces.where(piece_type: 'Rook', x_position: 0).take
king = game.pieces.where(piece_type: 'King', x_position: 4).take
if rook.color == 'WHITE' && king.color == 'WHITE'
rook.update_attributes(x_position: 3, state: 'moved')
king.update_attributes(x_position: 2, state: 'moved')
else rook.color == 'BLACK' && king.color == 'BLACK'
rook.update_attributes(x_position: 3, state: 'moved')
king.update_attributes(x_position: 2, state: 'moved')
end
rook.reload
king.reload
end
def no_kingside_obstruction?
(5..6).each do |x|
return false if space_occupied?(x, y_position)
end
true
end
def no_queenside_obstruction?
(1..3).each do |x|
return false if space_occupied?(x, y_position)
end
true
end
private
def standard_king_move?(x, y)
dx = (x - x_position).abs
dy = (y - y_position).abs
if dx >= 2 || dy >= 2
return false
elsif dx == 0 && dy == 0
return false
else (dx <= 1) && (dy <= 1) && (dx + dy > 0)
return true
end
end
def legal_castle_move?
king = game.pieces.where(piece_type: 'King').take
rook = game.pieces.where(piece_type: 'Rook').take
if (king.state == 'unmoved') && (rook != nil) && (rook.state == 'unmoved')
return true
else
return false
end
end
end
片模型
def move_to!(x, y)
if color == game.user_turn
if valid_move?(x, y) && space_available?(x, y) && not_into_check?(x, y)
capture_piece_at!(x, y) if occupied_by_opposing_piece?(x, y)
game.pass_turn!(game.user_turn)
change_location(x, y)
elsif !occupied_by_opposing_piece?(x, y)
false
elsif piece_type == 'King' && valid_move?(x, y) && space_available?(x, y) && not_into_check(x, y)
if legal_castle_move?
if castle!
game.pass_turn!(game.user_turn)
end
else
standard_king_move?(x, y)
game.pass_turn!(game.user_turn)
end
else
false
end
end
end
def not_into_check?(x,y)
!move_causes_check?(x,y)
end
def valid_move?(x, y)
return false if is_obstructed?(x, y)
return false if occupied_by_mycolor_piece?(x, y)
within_chessboard?(x, y)
end
def self.piece_types
%w(Pawn Knight Bishop Rook Queen King)
end
def within_chessboard?(x, y)
(x >= 0 && y >= 0 && x <= 7 && y <= 7 && x != nil && y != nil)
end
def horizontal_obstruction?(x_end, _y_end)
# movement: right to left
if x_position < x_end
(x_position + 1).upto(x_end - 1) do |x|
return true if space_occupied?(x, y_position)
end
# movement: left to right
elsif x_position > x_end
(x_position - 1).downto(x_end + 1) do |x|
return true if space_occupied?(x, y_position)
end
end
false
end
def vertical_obstruction(x_end, y_end)
# path is vertical down
if y_position < y_end
(y_position + 1).upto(y_end - 1) do |y|
return true if space_occupied?(x_position, y)
end
# path is vertical up
elsif y_position > y_end
(y_position - 1).downto(y_end + 1) do |y|
return true if space_occupied?(x_position, y)
end
end
false
end
def diagonal_obstruction(x_end, y_end)
# path is diagonal and down
if x_position < x_end
(x_position + 1).upto(x_end - 1) do |x|
delta_y = x - x_position
y = y_end > y_position ? y_position + delta_y : y_position - delta_y
return true if space_occupied?(x, y)
end
# path is diagonal and up
elsif x_position > x_end
(x_position - 1).downto(x_end + 1) do |x|
delta_y = x_position - x
y = y_end > y_position ? y_position + delta_y : y_position - delta_y
return true if space_occupied?(x, y)
end
end
false
end
def is_obstructed?(x, y)
x_end = x
y_end = y
path = check_path(x_position, y_position, x_end, y_end)
return horizontal_obstruction?(x_end, y_end) if path == 'horizontal'
return vertical_obstruction(x_end, y_end) if path == 'vertical'
return diagonal_obstruction(x_end, y_end) if path == 'diagonal'
false
end
def can_be_blocked?(color)
checked_king = game.find_king(color)
obstruction_array = obstructed_squares(checked_king.x_position, checked_king.y_position)
opponents = game.opponents_pieces(!color)
opponents.each do |opponent|
next if opponent.piece_type == 'King'
obstruction_array.each do |square|
return true if opponent.valid_move?(square[0], square[1])
end
end
false
end
def move_causes_check?(x, y)
state = false
ActiveRecord::Base.transaction do
change_location(x,y)
state = game.in_check?(color)
raise ActiveRecord::Rollback
end
reload
state
end
def space_occupied?(x, y)
game.pieces.where(x_position: x, y_position: y).present?
end
def check_path(x_position, y_position, x_end, y_end)
if y_position == y_end
'horizontal'
elsif x_position == x_end
'vertical'
elsif (y_end - y_position).abs == (x_end - x_position).abs
'diagonal'
end
end
def capture_piece_at!(x, y)
piece_at(x, y).update_attributes(x_position: nil, y_position: nil)
end
def unoccupied?(x, y)
!space_occupied?(x, y)
end
def occupied_by_mycolor_piece?(x, y)
space_occupied?(x, y) && (piece_at(x, y).color == color)
end
def occupied_by_opposing_piece?(x, y)
space_occupied?(x, y) && (piece_at(x, y).color != color)
end
def piece_at(x, y)
game.pieces.find_by(x_position: x, y_position: y)
end
def diagonal_move?(x, y)
(y_position - y).abs == (x_position - x).abs
end
def vertical_move?(x, y)
x_position == x && y_position != y
end
def horizontal_move?(x, y)
(y_position == y) && (x_position != x) ? true : false
end
def available_moves
Game.all_board_coordinates.select do |coordinate_pair|
valid_move?(coordinate_pair[0], coordinate_pair[1]) &&
!is_obstructed?(coordinate_pair[0], coordinate_pair[1]) &&
!occupied_by_mycolor_piece?(coordinate_pair[0], coordinate_pair[1])
end
end
private
def change_location(x,y)
update_attributes(x_position: x, y_position: y)
end
def space_available?(x,y)
!occupied_by_mycolor_piece?(x, y)
end
def space_occupied?(x, y)
game.pieces.where(x_position: x, y_position: y).present?
end
游戏模型pass_turn!方法
def pass_turn!(color)
player_turn = color == 'WHITE' ? 'BLACK' : 'WHITE'
update(user_turn: player_turn)
end