알고리즘

[기술 테스트 과제] 핑퐁게임_python

작은코딩 2022. 5. 9. 04:55

🔒 문제

https://codingdojang.com/scode/514?answer=17578 

 

코딩도장

프로그래밍 문제풀이를 통해서 코딩 실력을 수련

codingdojang.com

 

일련의 숫자가 있고, 이 숫자는 1씩 증가, 또는 감소한다. n번째의 숫자가 있을 시에, 이 숫자가 7의 배수(7, 14, 21,...)거나 7이란 숫자를 포함할 시에 (7, 17, 27,...) 방향을 바꾼다.

즉, 다음과 같이 숫자는 진행한다.

1,2,3,4,5,6,[7],6,5,4,3,2,1,[0],1,2,[3],2,1,0,[-1],0,1

(첫 번째 7은 7번째, 두번째 0은 14번째, 세번째 3은 17번째, 네번째 -1은 21번째)

이와 같은 pingpong(x)의 함수를 작성하라. 예시의 인풋과 아웃풋은 다음과 같다.

pingpong(8) = 6
pingpong(22) = 0
pingpong(68) = 2
pingpong(100) = 2

심화학습

위 문제에 다음과 같은 제약을 추가하여 다시 풀어보자.

  • For Loop 또는 Array를 쓰지 말 것
  • Assignment를 쓰지 말 것, 즉, 변수 할당을 하지 말 것.
  • String을 쓰지 말 것

🔓 풀이

🔑 문제 해결 / 코드

"""
2. 핑퐁 게임 (반드시 Python으로 작성할 것)

일련의 숫자가 있고, 이 숫자는 1씩 증가, 또는 감소한다. N 번째의 숫자가 있을 시에,
이 숫자가 7의 배수(7, 14, 21)이거나 7이란 숫자를 포함할 시에 (7, 17, 27) 방향을 바꾼다.
즉, 1, 2, 3, 4, 5, 6, [7], 6, 5, 4, 3, 2, 1, [0], 1, 2, [3], 2, 1, 0, [-1], 0, 1
과 같이 숫자는 진행한다. (첫번째 7은 7번째, 두번째 0은 14번째, 세번째 3은 17번째, 네번째 -1은 21번째)

다음의 제약 하에 pingpong(x)의 함수를 작성하라. 예시의 인풋과 아웃풋은 다음과 같다.
pingpong(8) = 6
pingpong(22)=0
pingpong(68)=2
pingpong(100)=2

@@@@       주의사항       @@@
-	For Loop / While 또는 Array를 쓰지 말 것
-	Assignment 를 쓰지 말 것. 즉, 변수 할당을 하지 말 것.
-	스트링을 쓰지 말 것.
"""

"""
 - 비고 - 
기본적으로는 1씩 더하지만 7의 배수 or 7이 들어간 수를 만나면 1씩 빼는 재귀함수
n = 0
m = 1
n += m // 기본

m = m * -1 
n += m 

# 주어지는 정수의 범위가 정해져있지 않아서 정수의 자릿수에 따라 조건이 바뀌게 만들어봤는데 
python에서는 최대 재귀 깊이가 1,000으로 정해져 있어서 RecursionError에러 발생

사용 가능한 정수 범위 ( N <= 997 )

"""
import math


# x 목표 반복 횟수, y 현재 반복 횟수, z 상태(+ or -), a 결과, b 현재 반복 횟수의 자릿수
def recursive(x, y, z, a, b):
    # 재귀함수 종료 조건 // 목표 반복 횟수와 현재 반복 횟수가 일치하면 종료
    if x == y:
        # 지금까지 더하거나 뺀 결과 리턴
        return a

    # 7의 배수인 경우
    if y % 7 == 0:
        # 조건 충족 시 상태를 반대로 바꿔주고 결과도 바뀐 상태 반영
        return recursive(x, y+1, -z, a-z, int(math.log10(y+1)))
    # 끝자리가 7인경우
    elif y % 10 == 7:
        return recursive(x, y+1, -z, a-z, int(math.log10(y+1)))
    # 자릿수가 0보다 클때 // 반복 횟수가 10 이상인 경우
    elif b > 0:
        # 자릿수가 1: 80 > n >= 70, 2: 800 > n % 1000 >= 700
        if (8*(10**b)) > y % (10*(10**b)) >= (7*(10**b)):
            return recursive(x, y+1, -z, a-z, int(math.log10(y+1)))
    # 조건 미충족 시 상태변환 x, 결과에 그대로 반영
    return recursive(x, y+1, z, a+z, int(math.log10(y+1)))


# 사용 가능한 정수 범위 ( N <= 997 )
def pingpong(x):
    if x < 1:
        return 0
    return recursive(x, 1, 1, 1, int(math.log10(1)))


answer_dict = {8: 6, 22: 0, 68: 2, 100: 2}

for i in answer_dict:
    answer = pingpong(i)
    if answer == answer_dict[i]:
        print(f"answer: {answer} 정답")
    else:
        print(f"answer: {answer} 오답")

print(pingpong(997))

💉 피드백

주어지는 정수 N의 범위가 정해져 있지 않아서 N의 크기(자릿수)에 따라 조건문 범위를 조절하려고 머리를 쥐어짰는데 python에서 최대 재귀 깊이는 1000까지여서 쓸데없는 고민이었다.

 

그래도 math 모듈의 log10(x) 함수를 배울 수 있어서 다행

 

위 코드에서는 1000이 아닌 997을 초과한 정수를 입력하면 에러가 뜨는데 pingpong 함수가 다른 함수를 호출해서 그런 거다.