n진수 게임 문서의 문제 1 풀이 코드다. if __name__ == "__main__": 아래가 자체 테스트다.

"""n진수 게임 (프로그래머스 17687) 풀이와 검증."""
import random


def solution(n, t, m, p):
    digits = "0123456789ABCDEF"

    def to_base(x):
        if x == 0:
            return "0"
        s = ""
        while x > 0:
            x, r = divmod(x, n)
            s = digits[r] + s
        return s

    parts, length, num = [], 0, 0
    while length < t * m:
        part = to_base(num)
        parts.append(part)
        length += len(part)
        num += 1
    seq = "".join(parts)
    return seq[p - 1::m][:t]


def game(n, t, m, p):
    """사람을 한 명씩 돌리며, 말할 숫자를 한 글자씩 넘긴다."""
    digits = "0123456789ABCDEF"

    def conv(x):
        return "0" if x == 0 else conv_rec(x)

    def conv_rec(x):
        return "" if x == 0 else conv_rec(x // n) + digits[x % n]

    said, num, buf, turn = [], 0, "", 1
    while len(said) < t:
        if not buf:
            buf = conv(num)
            num += 1
        ch, buf = buf[0], buf[1:]
        if turn == p:
            said.append(ch)
        turn = turn % m + 1
    return "".join(said)


if __name__ == "__main__":
    assert solution(2, 4, 2, 1) == "0111"
    assert solution(16, 16, 2, 1) == "02468ACE11111111"
    assert solution(16, 16, 2, 2) == "13579BDF01234567"
    assert solution(10, 3, 3, 2) == "147"
    rng = random.Random(17687)
    for _ in range(2000):
        n, m = rng.randint(2, 16), rng.randint(2, 10)
        p, t = rng.randint(1, m), rng.randint(1, 60)
        assert solution(n, t, m, p) == game(n, t, m, p), (n, t, m, p)
    # 2·8·16진수 전체 줄을 format과 비교 (m=1, p=1이면 전체 줄 앞부분이 그대로 나온다)
    for base, fmt in ((2, "b"), (8, "o"), (16, "X")):
        want = "".join(format(x, fmt) for x in range(300))
        assert solution(base, len(want), 1, 1) == want[:len(want)]
    print("ALL CHECKS PASSED")