(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

      

+3


source to share





All Articles