(RoR) Ruby on Rails Chess Game: Method doesn't work as intended.
I am working on some Ruby logic for a student project making a chess game. I am currently trying to write the logic needed to execute a rocking engine. According to my tests, castling should work, but playing the game it seems like only the white side can successfully lock. When the black side tries to block, it is considered an invalid move. I'm wondering, is not my method castle!
in a model king.rb
called the method is not correct move_to!
, located in the model pieces.rb
, or if there is a big problem with the way the methods that determine which player it includes (see. pass_turn!
In game.rb
)? I realize this question is a bit vague, but I'm pretty stuck and can use some help in figuring out what's going on here.
king model
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
piece model
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
game model pass_turn! Method
def pass_turn!(color)
player_turn = color == 'WHITE' ? 'BLACK' : 'WHITE'
update(user_turn: player_turn)
end
source to share
No one has answered this question yet
Check out similar questions: