ARQ와 순서 번호 문서의 구현 코드다. if __name__ == "__main__": 아래가 자체 테스트다.

"""ARQ(정지 대기)와 순서 번호 시뮬레이션. 문서의 네 경우 (a)~(d)."""


def run(events, use_seq):
    """events: 송신 시도마다의 결과 'ok' | 'lost_frame' | 'lost_ack' | 'late_ack'.
    받는 쪽이 위로 넘긴 데이터 목록과 보낸 프레임 수를 돌려준다."""
    delivered, expected, sent = [], 0, 0
    data = ["F0", "F1", "F2"]
    i = 0; ev = iter(events)
    while i < len(data):
        e = next(ev, "ok"); sent += 1
        seq = i % 2
        if e == "lost_frame":
            continue                                        # 타임아웃 → 같은 프레임 재전송
        # 받는 쪽: 순서 번호가 있으면 중복을 버린다(ACK는 꼭 보낸다)
        if not use_seq or seq == expected:
            delivered.append(data[i]); expected ^= 1
        if e == "lost_ack":
            continue                                        # ACK가 없어 송신자는 재전송
        if e == "late_ack":
            sent += 1                                       # 타임아웃이 먼저 와서 재전송한 프레임이 하나 더 간다
            if not use_seq:
                delivered.append(data[i])
        i += 1
    return delivered, sent


def main():
    assert run(["ok", "ok", "ok"], True) == (["F0", "F1", "F2"], 3)               # (a)
    assert run(["lost_frame", "ok", "ok", "ok"], True) == (["F0", "F1", "F2"], 4)  # (b)
    # (c) ACK 분실: 순서 번호가 없으면 F0이 두 번 올라간다
    d, _ = run(["lost_ack", "ok", "ok", "ok"], False)
    assert d == ["F0", "F0", "F1", "F2"]
    d, s = run(["lost_ack", "ok", "ok", "ok"], True)
    assert d == ["F0", "F1", "F2"] and s == 4
    # (d) 타임아웃이 너무 짧아 ACK가 늦게 옴: 같은 문제
    d, _ = run(["late_ack", "ok", "ok"], False)
    assert d == ["F0", "F0", "F1", "F2"]
    d, _ = run(["late_ack", "ok", "ok"], True)
    assert d == ["F0", "F1", "F2"]
    # 정지 대기에는 순서 번호 1비트(0, 1)면 충분하다: 위 모두 0/1만 썼다
    # 카드 C2: 프레임 분실 1번, ACK 분실 1번 → 보낸 프레임 수
    assert run(["lost_frame", "ok", "lost_ack", "ok", "ok"], True)[1] == 5
    print("ALL CHECKS PASSED")


if __name__ == "__main__":
    main()