본문 바로가기

Lang

[Python] 야구 게임 - 숫자 맞추기

어렸을 때 친구들이랑 야구 게임이란걸 종종 했었다.

공수를 번갈아가며 각자 상대가 생각한 숫자를 맞추는 게임인데 수비하는 자는 공격자가 추정한 수에서 자리까지 일치하면 스트라익, 자리는 틀리지만 자기가 생각한 수에 포함된 숫자면 볼로 구분하여 전체 볼 카운트를 알려주면 그것을 힌트로 정확한 숫자를 추리해야 한다.

아이가 풀고 있는 문제지에 이 야구 게임을 응용한 문제가 있어서 코딩으로 한 번 도전해봤다.

숫자는 5자리이고 각 자리의 수들은 모든 다른 수라고 할 때 다음 힌트를 가지고 정답을 찾아내야 한다.

  S B
45289 1 1
12643 2 2
70149 1 1
85201 1 1
20458 0 3
58236 1 2

성능 무시하고 일단 무식하게 짜봤다.

  1.  테이블에 있는 각 힌트값으로 후보 목록을 구한다.
    • 5자리 수 중에서 45289 가 1S1B인 숫자를 모두 구한다.
  2. 힌트별로 1의 작업 수행해서 구한 리스트에서 중복값을 찾는다.

 

# 각 자리 수가 모두 다른 수 생성
def unique_count(num):
    nlen = len(str(num))
    for i in range(num):
        if len(str(i).zfill(nlen)) == len(set(str(i).zfill(nlen))):
            yield str(i).zfill(nlen)

# 볼 카운트
def is_bc(p, q, r):
    score = [0, 0]
    for i, q_val in enumerate(q):
        for j, p_val in enumerate(list(p)):
            if q_val == p_val:
                if i == j:
                    score[0] += 1
                else:
                    score[1] += 1
    return score == r


if __name__ == '__main__':
    guess_list = [
        ['1', '2', '6', '4', '3'],
        ['2', '0', '4', '5', '8'],
        ['5', '8', '2', '3', '6'],
        ['4', '5', '2', '8', '9'],
        ['7', '0', '1', '4', '9'],
        ['8', '5', '2', '0', '1'],
    ]
    bs_counts = [
        [2, 2],
        [0, 3],
        [1, 2],
        [1, 1],
        [1, 1],
        [1, 1],
    ]

    # result = []
    # for i, q in enumerate(list(q_list)):
    #     point = unique_count(99999)
    #     result.append(list(filter(lambda x: is_bc(x, q, r_list[i]), point)))
    #
    ## 여러 리스트에서 중복된 값 찾기
    # print(set.intersection(*map(set, result)))

    answer = unique_count(99999)
    for i, q in enumerate(list(guess_list)):
        answer = list(filter(lambda x: is_bc(x, q, bs_counts[i]), answer))

    print(answer)

후보 목록들 구하는 부분의 저 무식한 루프 뻘짓이 가슴 답답하게 하지만 오늘은 여기까지. 심심할 때 한 번 개선 도전해보는걸로 하고.

추가.

매번 5자리 범위 전체 대상으로 후보 찾는게 아니라 각 힌트에서 찾은 후보 목록으로 단계별 검색 범위 줄이면 훨씬 좋아질거 같다는 생각이 불쑥 떠올라 간단하게 고쳐봤다.