from typing import Generator
from typing import Tuple
import math


def generate_2d_line(
    x0: int, y0: int, x1: int, y1: int, exclude_start: bool = False, exclude_end: bool = False
) -> Generator[Tuple[int, int], None, None]:
    """
    Generates a 2-dimensional line (list of points) from point1 towards point2.
    This does not use antialiasing, so the number of points will be
    amount = max(abs(x0-x1), abs(y0-y1)) + 1

    Returnvalues:
    (x: int, y: int)
    """
    if x0 == x1 and y0 == y1:
        if not (exclude_start or exclude_end):
            yield (x0, y0)
        return None
    x_diff = abs(x1 - x0)
    y_diff = abs(y1 - y0)

    start_offset = 1 if exclude_start else 0
    end_offset = 1 if exclude_end else 0

    if y_diff <= x_diff:

        m = (y1 - y0) / abs(x1 - x0)
        new_y = y0
        # Point2 lies mostly to the right of Point1
        if x1 > x0:
            for x in range(x0 + start_offset, x1 + 1 - end_offset):
                yield (x, math.floor(new_y))
                new_y += m

        # Point2 lies mostly to the left of Point1
        else:
            for x in range(x0 - start_offset, x1 - 1 + end_offset, -1):
                yield (x, math.floor(new_y))
                new_y += m
    else:
        m = (x1 - x0) / abs(y1 - y0)
        new_x = x0
        # Point2 lies mostly to the top of Point1
        if y1 > y0:
            for y in range(y0 + start_offset, y1 + 1 - end_offset):
                yield (math.floor(new_x), y)
                new_x += m

        # Point2 lies mostly to the bottom of Point1
        else:
            for y in range(y0 - start_offset, y1 - 1 + end_offset, -1):
                yield (math.floor(new_x), y)
                new_x += m
    return None