(RoR)Ruby on Rails国际象棋游戏:方法无法按预期工作。

时间:2017-04-02 02:18:57

标签: ruby-on-rails ruby

我正在为构建国际象棋游戏的学生项目研究一些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

0 个答案:

没有答案