These are code samples from two of my web applications. The first app is StormyKnights, an online chess game. I was a part of a team of four developers that worked on this project. StormyKnights was the capstone app for The Firehose Project, an immersive web development program with a focus on Ruby on Rails. It can be seen live at stormy-knights.herokuapp.com.
The second app is a personal project called My Recipe Box, an app for displaying and sharing recipes. It can be seen at allmyrecipes.herokuapp.com.
This method from the chess game app determines whether the path between a piece and an intended destination is a straight line (either horizontal, vertical, or diagonal). If the path is a straight line, then it checks whether the path is obstructed by another piece. If the path is not a straight line, then it returns an error.
Enter # This method determines whether the path between instance piece and destination is obstructed by another piece.
#
# * *Args* :
# - +destination+ -> array containing x and y coordinates of the piece's intended destination
# * *Returns* :
# - True if one or more squares between the piece and the destination are occupied
# - False otherwise
# * *Raises* :
# - +RuntimeError+ -> if the path is not a straight line
def obstructed?(destination)
@game = game
# converts the location arrays into easier-to-read x and y terms
x1 = self.x_coordinates #assume starting points
y1 = self.y_coordinates
x2 = destination[0]
y2 = destination[1]
# Determines whether the line between piece1 and the destination is horizontal or
# vertical. If neither, then it calculates the slope of line between piece1 and destination.
path = check_path(x1, y1, x2, y2)
# path is horizontal and right to left
if path == 'horizontal' && x1 < x2
(x1 + 1).upto(x2 - 1) do |x|
return true if occupied?(x, y1)
end
end
# path is horizontal and left to right
if path == 'horizontal' && x1 > x2
(x1 - 1).downto(x2 + 1) do |x|
return true if occupied?(x, y1)
end
end
# path is vertical down
if path == 'vertical' && y1 < y2
(y1 + 1).upto(y2 - 1) do |y|
return true if occupied?(x1, y)
end
end
# path is vertical up
if path == 'vertical' && y1 > y2
(y1 - 1).downto(y2 + 1) do |y|
return true if occupied?(x1, y)
end
end
if path == 'horizontal' || path == 'vertical'
return false
end
# path is diagonal and down
if @slope.abs == 1.0 && x1 < x2
(x1 + 1).upto(x2 - 1) do |x|
delta_y = x - x1
y = y2 > y1 ? y1 + delta_y : y1 - delta_y
return true if occupied?(x, y)
end
end
# path is diagonal and up
if @slope.abs == 1.0 && x1 > x2
(x1 - 1).downto(x2 + 1) do |x|
delta_y = x1 - x
y = y2 > y1 ? y1 + delta_y : y1 - delta_y
return true if occupied?(x, y)
end
end
# path is not a straight line
if @slope.abs != 1.0
fail 'path is not a straight line'
else return false
end
end
These are methods used by obstructed? method shown above.
def occupied?(x, y)
game.pieces.where(x_coordinates: x, y_coordinates: y).present?
end
def check_path(x1, y1, x2, y2)
if y1 == y2
return 'horizontal'
elsif x1 == x2
return 'vertical'
else
# move diagonal
@slope = (y2 - y1).to_f / (x2 - x1).to_f
end
end
This method implements a capture if a piece lands on a square occupied by a piece of the opposite color. This is done by setting coordinates of the captured piece to nil and by setting coordinates of the capturing piece to new values.
# This method implements capturing a piece.
#
# * *Args* :
# - +new_x, new_y+ -> x and y coordinates of the piece's intended destination
# * *Returns* :
# - If intended destination is occupied by piece of the opposite color,
# then the occupying piece is removed from the board by setting its coordinates to 'nil'
#
# * *Raises* :
# - +RuntimeError+ -> if intended destination is occupied by piece of same color
def move_to!(new_x, new_y)
@game = game
if occupied?(new_x, new_y)
@piece_at_destination = @game.pieces.find_by(x_coordinates: new_x, y_coordinates: new_y)
if color == @piece_at_destination.color
fail 'destination occupied by piece of same color'
else
@piece_at_destination.update_attributes(x_coordinates: nil, y_coordinates: nil, status: 'captured')
@status = @piece_at_destination.status
@captured = true
end
else @captured = false
end
end
This method implements a move. It checks whether the intended move is valid by executing the valid_move? method belonging to the piece's subclass. If the move is a castling, then it calls the castling_to? method. It calls the move_to! method to check whether the destination is occupied and to perform a capture if appropriate.
# This method implements a move. It checks whether the intended move is valid
# by executing the valid_move? method belonging to the piece's subclass.
# If the move is a castling, then it calls the castling_to? method.
# It calls the move_to! method to check whether the destination is occupied and to
# perform a capture if appropriate.
# Assigns values to instance variables @castle (true if the move is a castling,
# @valid (true if the move does not violate the rules of chess,
# and @not_color (assigned to the color belonging to player with the next move)
#
# * *Args* :
# - +new_x, new_y+ -> x and y coordinates of the piece's intended destination
# * *Returns* :
# - Assigns values to instance variables @castle, @valid, and @not_color
#
def perform_move!(x_coordinates, y_coordinates)
valid_move_result = self.valid_move?(x_coordinates, y_coordinates)
if self.castling_to?(x_coordinates, y_coordinates)
@castle = true
castling(x_coordinates)
elsif valid_move_result
self.move_to!(x_coordinates, y_coordinates)
if update_attributes(x_coordinates: x_coordinates, y_coordinates: y_coordinates)
@valid = true
end
else
@valid = false
end
if color == 'white'
@not_color = 'black'
else @not_color = 'white'
end
end
This is the model file for Recipe class in My Recipe Box app. It contains the search method that implements a search from the input box on the title page.
class Recipe < ActiveRecord::Base
belongs_to :user
has_many :comments
validates :name, :presence => true, length: { minimum: 3 }
validates :ingredients, :presence => true
validates :instructions, :presence => true
# Implements search for recipes.
# * *Args* :
# - search query in string format
# * *Returns* :
# - returns the recipes with names that contain one or more words from the query
def self.search(query)
#where(:title, query) -> This would return an exact match of the query
where("LOWER(name) like ?", "%#{query}%")
end
# Calculates the average rating of recipe
# * *Args* :
# None
# * *Returns* :
# - average rating of recipe
def avg_rating
rating_vals = self.comments.map do |c|
c.rating[0].to_i
end
rating_vals.sum.to_f / rating_vals.length
end
end