0

Still fairly new to Rails. Working on a group project to build a chess app we've got everything working except for a transaction rollback in our checkmate? method.

Moves are saved directly to the database. Then, our check? method queries the database to see if the king is in check. This created a problem for us for two reasons - 1. if you move yourself into check the move has to be undone 2. to determine checkmate you need to move pieces on the board and see if the king is still in check. We implemented transactions for problem 1. and it works fine.

However, for checkmate the first thing we check is to see if the king can move himself out of check. This method runs through the 9 squares the king might occupy to see if any of them successfully move him out of check. I know the method is a bit sloppy now, but we're trying to get it to work then we can refactor.

Our goal is to move the king, see if it gets him out of check, then rollback the move. The rollback should happen every time but the rollback never occurs.

 # determine if king can move himself out of check
  def can_move_out_of_check?
    success = false
    y_start = y_position
    ((x_position - 1)..(x_position + 1)).each do |x|
      ((y_start - 1)..(y_start + 1)).each do |y|
        Piece.transaction do
          move_to(x, y) if valid_move?(x, y)
          # if game.check?(color) comes up false,
          # even once, assign  true
          success = true unless game.check?(color)
          # reset any attempted moves
          fail ActiveRecord::Rollback
        end
      end
    end
    success
  end

I've tried different options King.transaction ActiveRecord::Base.transaction. Per one suggestion I tried ActiveRecord::Base.transaction(require_new: true) which rolled back on each check but also wouldn't allow me to make a valid move when the king was in check.

I feel like I'm missing something really simple.

Aaron Washburn
  • 300
  • 2
  • 10
  • I rewrote the method to avoid using transactions (manually moving the king back each time) but would love to know why the transactions weren't working. – Aaron Washburn May 01 '15 at 13:39
  • Is this in specs/tests or in real usage? When you say that there is no rollback, so you mean that the log doesn't seem to contain a rollback or that some data (which data?) doesn't appear to change back? – Frederick Cheung May 01 '15 at 13:39
  • You have to `raise ActiveRecord::Rollback` for the rollback to happen. – bsvin33t May 01 '15 at 13:40
  • 1
    because you have N independent transactions, rollback of one wouldnt rollback the others – apneadiving May 01 '15 at 13:40
  • @bsvin33t I've tried both raise and fail (which our rubocop required us to change to). They appear to be equivalent. http://stackoverflow.com/questions/18811675/what-does-the-fail-keyword-do-in-ruby – Aaron Washburn May 01 '15 at 13:49
  • @FrederickCheung, we are using unit tests and they seem to pass but I suspect we're not testing for the right things to notice this glitch. Would be good to go in and test it. We noticed it in actual play. I've set a byebug flag and monitored the kings movements during a call to the function and the database never calls a rollback. – Aaron Washburn May 01 '15 at 13:52

1 Answers1

1

A working configuration would be:

  def can_move_out_of_check?
    success = false
    y_start = y_position
    ActiveRecord::Base.transaction do 
      ((x_position - 1)..(x_position + 1)).each do |x|
        ((y_start - 1)..(y_start + 1)).each do |y|
          move_to(x, y) if valid_move?(x, y)
          # if game.check?(color) comes up false,
          # even once, assign  true
          success = true unless game.check?(color)
          # reset any attempted moves
          fail ActiveRecord::Rollback
        end
      end
    end
    success
  end

Which would work because everything happens in the same transaction.

apneadiving
  • 114,565
  • 26
  • 219
  • 213
  • The trouble is we need it to rollback even if it's a successful move - this is checking to see if the king CAN move out of check (i.e. he's not in checkmate) but we don't want him to actually make the move. The player can decide where to move the king to. That's why I set it up as N different transactions. – Aaron Washburn May 01 '15 at 13:48
  • I'll try that out. I assumed by setting it up as such it wouldn't cycle through all 9 spaces. – Aaron Washburn May 01 '15 at 13:52
  • well, as long as one setup is wrong, wy do you need to check the others? err ok I understand – apneadiving May 01 '15 at 13:53
  • actually you should fail at the end of your loops, cant you do that? – apneadiving May 01 '15 at 13:56
  • I appreciate the help. That only check the first move then broke out of the loops and still didn't roll back the move. Each check has to rollback because the king needs to be in his original location to check valid_move?. I've implemented it without transactions but just want to figure out why this isn't working. – Aaron Washburn May 01 '15 at 14:02
  • yes I know, could you use `fail` at the end of all loops? – apneadiving May 01 '15 at 14:04