THIS IS SPRKY

Online Chess—Ruby on Rails Style.

Handcrafted App

For the capstone of The Firehose Project we hand-crafted an open source chess application using Ruby on Rails. With Test Driven Development (TDD) as our guide, we crafted every element of the application from the ground up. Committed to sharpening our Ruby chops, we collaborated on pull requests to refactor and refine our code. We kept the red-green-refactor cycle tight, and above all we kept on shipping.

CODE

Some highlights of our craft

        def attempt_move(params)
          Piece.transaction do
            return false unless moving_own_piece?
            fail ActiveRecord::Rollback unless move_to(params)
            fail ActiveRecord::Rollback if game.check?(color)

            # update current state of check, checkmate, etc.
            game.update_state(color)
          end
        end
          

Attempting a Move

While many illegal moves are caught before writing to the database, some are not detected until after - a player moving into check for example. For cases such as these, Activerecord transactions were used to ensure that all database updates would rollback to the previous move.


            def check?(color)
              king = pieces.find_by(type: 'King', color: color)
              opponents = pieces_remaining(!color)

              opponents.each do |piece|
                if piece.valid_move?(king.x_position, king.y_position)
                  @piece_causing_check = piece
                  return true
                end
              end
              false
            end

            def checkmate?(color)
              checked_king = pieces.find_by(type: 'King', color: color)

              return false unless check?(color)
              return false if checked_king.can_move_out_of_check?
              return false if @piece_causing_check.can_be_captured?
              return false if @piece_causing_check.can_be_blocked?(checked_king)

              true
            end
          

Check and Checkmate

An integral part of the chess game, check and checkmate gave us our biggest logic challenge. Through several iterations and a number of refactors we eventually landed on two elegant and simple methods.

Check

In order to determine check, we looped through all opponent's pieces to see if any piece can legally move to the king's position. The check method runs before and after a move transaction is completed. This ensures a player doesn't move themselves into check and also determines if the opponent is in check.

Checkmate

Once a player is in check we determined that there are three ways to get out of check. If any of those moves are possible, the game is not in a state of checkmate. We set up ActiveRecord transactions to examine two levels of moves without altering the database. This allowed us to simulate a move and then verify if a state of check exists after the move.


            function sendMove ($piece, $destination) {
              var piece = {
                id: $piece.data('piece-id'),
                x_position: $destination.data('x-position'),
                y_position: $destination.data('y-position')
              }

              if ( isPawnPromotion($piece, piece.y_position)) {
                openModal('#promo-modal', function(pieceType) {
                  piece.type = pieceType;
                  submitPieceUpdate(piece);
                });

              } else {
                submitPieceUpdate(piece);
              }
            }

            function selectPiece($piece) {
              var isPlayersTurn = $('#gameboard').data('your-turn');

              if (isPlayersTurn) {
                $piece.addClass('selected');
              }
            }
          

Javascript

To reduce http requests we implemented some front-end logic which made extensive use of data attributes. This allowed us to create a seamless integration between our front-end and back-end logic and maintain a snappy user experience

In order to select a piece, the code checks that there is a piece assigned to the square and that it's currently that player's turn. Another javacript function determines a destination and triggers sendMove.

The sendMove function sends an AJAX call to our PiecesController with an updated x and y position. Upon success the controller returns with the correct URL for an updated game board (games/:id) and the page is reloaded.

One planned enhancement is to return an updated gameboard partial rather than trigger a full page reload.

Tools

In coding as in carpentry, the right tool for the job
Version Control:
Continuous Integration:
Team Communication:
Project Management:
Code Analyzer: