private void algorithmLine(int max, int min) {
		// Let's use the other algorithm to approximate the tiles that we need to check.
		algorithmWrap(max, min);
		// After calling the above function, the approximation is stored in this.result
		
		// These variables are explained when they are first set.
		// They are declared in advance only for optimisation.
		Tile tile;
		ArrayList<Tile> path;
		int source_x = this.origin.getGridX(), source_y = this.origin.getGridY(), target_x, target_y;
		int x, y, sign_x, sign_y;
		boolean steep;
		float d, dx, dy;

        tileLoop: //Simply a marker to be used later by the continue keyword.
        	// This is necessary because we have nested loops.
		for (Tile current : this.validTargetPaths.keySet()) { //loop through the approximated targets
			// And then inside the loop we check to see if that approximation is a valid target.
			path = new ArrayList<Tile>(); //This variable is used to track the tiles that have to be cross to reach the "current" tile.
			target_x = current.getGridX(); //the X position of the target that is currently being considered.
			target_y = current.getGridY(); //the Y position of the target that is currently being considered.
	        steep = false; //This variable is used to track whether the slope from the origin to the target is greater than 1
	        
	        dx = Math.abs(target_x - source_x); //The distance between the target and origin, on the X axis.
	        if (target_x - source_x > 0) {
	            sign_x = 1; //Indicates that we are operating in one of the right 2 quadrants. (In a grid that is split along the X and Y axis at 0)
	        } else {
	            sign_x = -1; //Indicates that we are operating in one of the left 2 quadrants.
	        }
	        
	        dy = Math.abs(target_y - source_y); //The distance between the target and origin, on the X axis.
	        if (target_y - source_y > 0) {
	            sign_y = 1; //Indicates that we are operating in one of the top 2 quadrants.
	        } else {
	            sign_y = -1; //Indicates that we are operating in one of the bottom 2 quadrants.
	        }
	        
	        // Using sign_x and sign_y we can determine exactly which quadrant the target tile is in, relative to the origin.
	        
	        /*
	         * As we loop through the path from the origin tile to the target tile,
	         * the x and y variables will track which tile we are currently checking.
	         * We start at the origin and move towards the target.
	         */
	        x = source_x;
	        y = source_y;
	        
	        if (dy > dx) {
	        	/*
	        	 * If operating in an environment where the slope from the origin to the target is greater than 1.
	        	 * ie. steep
	        	 * We need to reverse all our x and y coordinates.
	        	 * I can't give you a good explanation of why,
	        	 * but this is definitely this keeps the code a lot lighter than special casing for steep and not steep.
	        	 */
	            steep = true;
	            x = y;
	            y = x;
	            dx = dy;
	            dy = dx;
	            sign_x = sign_y;
	            sign_y = sign_x;
	        }
	        
	        /*
	         * Now we start looping through each tile from the origin to the target
	         * As we look at each tile we check to see if it blocks the range finding or not.
	         * 
	         * This is the point where we really use the Bresenham Line Algorithm
	         * To understand this fully you should read this,
	         * http://www.oocities.org/temerra/los_rays.html
	         */
	        d = (2 * dy) - dx;
	        for (int i = 0; i < dx; i++) {
	            if (steep) {
	            	/*
	            	 * Since the slope from the origin to the target is greater than 1, 
	            	 * we previously reversed x and y to simplify our calculations,
	            	 * however we did not reverse the board's grid system, so we should swap the x and y
	            	 * back to their original values just for this call.
	            	 */
	                tile = this.match.getBoard().getTile(y, x);
	            } else { 
	                tile = this.match.getBoard().getTile(x, y);
	            }
	            
	            if (tile == null || tile.isOfType(ability.getBlockingType(), match.getCurrentPlayer(), match.getTileOwner(tile))) {
	            	// If the tile we are checking at the moment is null, or would block this range search.
	            	// Then remove "current" target that we are considering from the list of results,
	            	// and skip back to the beginning of the first loop so we can consider the next potential target.
	            	this.validTargetPaths.remove(current);
	                continue tileLoop; // Jump back to where we set the "tileLoop:" marker
	            } else {
	            	// If the tile is valid, then add it to the path, 
	            	// which is the list of tiles that you have to cross to reach the "current" target.
	            	path.add(tile);
	            }
	            
	            // START BRESENHAM ALGORITHM
	            /* This is the core of the algorithm.
	             * Basically the point of this code is to determine precisely the next tile
	             * in the path from the origin to the target that we have to check.
	             * Once again, this site http://www.oocities.org/temerra/los_rays.html
	             * does a good job of explaining why and how.
	             */
	            while (d >= 0) {
	                y = y + sign_y;
	                d = d - (2 * dx);
	            }
	            
	            x = x + sign_x;
	            d = d + (2 * dy);
	            // END BRESENHAM ALGORITHM
	        }
	        
	        // Since the current target made it this far, that means it's valid.
	        // Store it in the results list, along with the path to reach it.
	        this.validTargetPaths.put(current, path);
		}
	}