"""
Problem 1:

"""
def all_the_kwargs(**kwargs):
    """
    Accepts any number of keyword arguments and returns the count of them.

    :param kwargs: Arbitrary keyword arguments.
    :return: The number of keyword arguments passed in.
    """
    return len(kwargs)

"""
Problem 2:
"""
def number_generator(N):
    """
    Generates numbers from 0 through N (inclusive).

    :param N: The upper limit of the range (inclusive).
    :yield: Numbers from 0 to N.
    """
    for num in range(N+1):
        yield num
        
"""
Problem 3
"""
def almost_fibonacci(N):
    """
    Generates the first N numbers of a sequence similar to the Fibonacci sequence,
    where each number (after the first three) is the sum of the previous three numbers.

    The sequence starts with: 0, 1, 1.

    :param N: The number of terms to generate.
    :yield: The first N numbers of the modified Fibonacci sequence.
    """
    a, b, c = 0, 1, 1  # Initial values
    for _ in range(N):
        yield a
        a, b, c = b, c, a + b + c  # Update values for the next iteration


"""
Problem 4
"""
def first_word_of_each_line(filepath):
    """
    Reads a file line by line and yields the first word of each line.

    :param filepath: The path to the file to be read.
    :yield: The first word of each line, if present.
    """
    with open(filepath, 'r', encoding='utf-8') as file:
        for line in file:
            words = line.strip().split()  # Split line into words      
            if words:  # Check if the line is not empty
                yield words[0]  # Yield the first word

def word_n_of_each_line(n):
    """
    Returns a generator function that reads a file line by line and yields the nth word of each line.

    :param n: The position of the word to return (1-based index).
    :return: A generator function that takes a filepath argument.
    """
    def generator(filepath):
        with open(filepath, 'r', encoding='utf-8') as file:
            for line in file:
                words = line.strip().split()  # Split line into words
                yield words[n - 1] if len(words) >= n else None  # Yield nth word or None if line is too short

    return generator


# Testing the function
if __name__ == "__main__":
    # Create a test file
    test_filepath = "test_file.txt"
    with open(test_filepath, 'w', encoding='utf-8') as f:
        f.write("This is the first line.\n")
        f.write("Second line with more words.\n")
        f.write("Short line.\n")
        f.write("Another example of a line with many words.\n")

    # Test first_word_of_each_line
    print("First word of each line:")
    for word in first_word_of_each_line(test_filepath):
        print(word)

    # Test word_n_of_each_line for different values of n
    for n in [2, 3, 5]:
        print(f"\n{n}th word of each line:")
        nth_word_generator = word_n_of_each_line(n)  # Get generator for nth word
        for word in nth_word_generator(test_filepath):
            print(word)

