def _check_project_unhappy(project, student):
    """ Determine whether ``project`` is unhappy because either:
        - they and their supervisor are under-subscribed;
        - they are under-subscribed, their supervisor is full, and either
          ``student`` is in the supervisor's matching or the supervisor prefers
          ``student`` to their worst current matching;
        - ``project`` is full and their supervisor prefers ``student`` to the
          worst student in the matching of ``project``.
    """
    supervisor = project.supervisor
    project_undersubscribed = len(project.matching) < project.capacity
    both_undersubscribed = project_undersubscribed and len(supervisor.matching
        ) < supervisor.capacity
    supervisor_full = len(supervisor.matching) == supervisor.capacity
    swap_available = (student in supervisor.matching and student.matching !=
        project or supervisor.prefers(student, supervisor.get_worst_match()))
    project_upsetting_supervisor = len(project.matching
        ) == project.capacity and supervisor.prefers(student, project.
        get_worst_match())
    return (both_undersubscribed or project_undersubscribed and
        supervisor_full and swap_available or project_upsetting_supervisor)
