Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

6 모듈

Updated: 10 mrt 2026

이전 장에서 함수가 반복되는 명령문을 묶어 재사용성과 가독성을 높이는 방법임을 살펴보았다. 이제 한 걸음 더 나아가, 관련된 함수, 변수, 그리고 나중에 배울 클래스 정의를 파일 단위로 묶어 관리하는 모듈module을 소개한다.

모듈은 함수, 변수, 클래스 등의 정의를 담고 있는 소스코드 파일이며, 파일 확장자는 .py이다. 이 절에서는 다음 세 모듈을 예로 들어 모듈 활용의 기본 방법을 설명한다.

  • time 모듈: 시간과 관련된 유용한 함수 제공

  • random 모듈: 무작위 수 생성 및 계산에 필요한 다양한 함수 제공

  • math 모듈: 수학에서 자주 쓰는 함수와 상수 제공

모듈은 상황에 따라 다음 세 가지 중 하나의 방식으로 활용하면 된다.

  • import 모듈명

  • from 모듈명 import ...

  • import 모듈명 as 모듈별칭

6.1모듈 활용법 1: import 모듈명

time 모듈은 시간과 관련된 유용한 함수를 제공한다. 여기서는 sleep(), time(), ctime() 함수의 간단한 사용법을 소개한다.

time.sleep() 함수

time 모듈의 sleep() 함수는 초 단위로 지정된 정수 인자와 함께 호출되면 파이썬 실행기를 지정된 시간만큼 작동을 멈추게 한다. 예를 들어 아래 코드는 0부터 4까지의 정수를 1초에 하나씩 출력한다.

import time
for sec in [0, 1, 2, 3, 4]:
    print(sec, end=", ")
    time.sleep(1)
0, 1, 2, 3, 4, 

time.time() 함수

time 모듈의 time() 함수는 인자없이 호출되면 컴퓨터 시간의 시작시점부터 흐른 시간을 부동소수점으로 반환한다.

time.time()
1743836997.7193384

time.ctime() 함수

ctime() 함수는 인자없이 호출되면 현재 시각을 서양식으로 보여준다.

time.ctime()
'Sat Apr 5 16:09:57 2025'

ctime() 함수는 또한 부동소수점과 함께 호출되면 인자로 지정된 부동소수점을 컴퓨터 시간의 기원부터 흐른 시간에 해당하는 시각을 서양식으로 보여준다.

t = time.time()
time.ctime(t)
'Sat Apr 5 16:09:57 2025'

ctime() 함수의 인자를 0으로 지정한 후에 호출하면 컴퓨터 시간의 시작시점을 확인할 수 있다.

time.ctime(0)
'Thu Jan 1 09:00:00 1970'

리눅스 등 UNIX 계열의 컴퓨터는 1970년 1월 1일을 컴퓨터 시간의 기원으로 사용한다. 반면에 윈도우 계열의 컴퓨터는 1601년 1월 1일을 컴퓨터 시간의 기원으로 사용한다. 위 코드의 결과는 1970년 1월 1일 0시가 아니라 오전 9시를 보여준다. 하지만 이는 한국시간으로 변환된 시간이며 그리니치 표준시, 즉 영국 시간으로는 1970년 1월 1일 0시를 가리킨다.

6.2모듈 활용법 2: from 모듈명 import ...

예를 들어 1부터 5까지의 정수 중에서 무작위로 하나의 정수를 계산하는 함수가 필요할 때 random 모듈의 randint() 함수를 활용할 수 있다. 이를 위해 먼저 random 모듈을 불러온다.

import random

이제 randint() 함수를 다음과 같이 호출할 때마다 1부터 5까지의 정수 중에서 하나의 정수가 무작위로 반환된다.

random.randint(1, 5)
1
random.randint(1, 5)
1

그리고 random 모듈의 random() 함수는 구간 [0, 1), 즉 0 이상, 1 미만 사이의 구간에서 무작위로 하나의 부동소수점을 생성한다. 아래 코드는 random() 모듈을 세 번 호출할 때마다 매번 무작위로 새로운 부동소수점이 생성됨을 보여준다.

for i in [0, 1, 2]:
    print(random.random())
0.5085376586716734
0.8223720932929772
0.24539440595990647

즉 모듈에 포함된 함수를 사용하려면 점을 사이에 두고 모듈 이름과 함수를 함께 표현한다.

random.seed() 함수

random 모듈에 포함된 함수들은 기본적으로 호출될 때마다 무작위로 수를 생성하기에 호출될 때마다 다른 값을 반환한다. 실제로는 파이썬 실행기가 무작위 수 생성 기능의 사용 횟수에 따라 함수가 반환해야 하는 값을 차례대로 지정한다.

따라서 무작위로 수를 생성하는 함수를 실행할 때마다 동일한 값이 생성되도록 하려면 무작위수 생성 기능의 사용 횟수를 초기화하면 된다. 이를 위해 random.seed() 함수를 이용한다. 인자는 0보다 같거나 큰 정수가 사용된다. 예를 들어 아래 코드는 무작위수 생성 기능이 17번 사용되었다고 가정하도록 한다.

random.seed(17)

random.seed() 함수와 함께 random 모듈의 함수를 호출하면 항상 동일한 결과를 얻는다. 아래 코드는 random.seed() 함수를 이용하면 매번 동일한 결과가 나온다는 사실을 보여준다.

for i in [0, 1, 2]:
    random.seed(17)
    print(random.random())
0.5219839097124932
0.5219839097124932
0.5219839097124932

random.seed() 함수의 인자를 달리하면 다른 결과를 얻는다.

for i in [0, 1, 2]:
    random.seed(0)
    print(random.random())
0.8444218515250481
0.8444218515250481
0.8444218515250481

그런데 만약 randint() 함수를 자주 사용한다면 random.randint()처럼 매번 random 모듈명과 함께 호출하는 게 불편할 수 있다. 그런 경우 from ... import ... 명령문을 사용하면 보다 편리하게 자주 활용하는 함수를 호출할 수 있다. 예를 들어 아래 코드는 random 모듈에서 randint() 함수와 seed() 함수만 따로 불러온다.

from random import randint, seed

그러면 모듈명 없이 randint() 함수를 사용할 수 있다.

seed(10)

for i in [0, 1, 2]:
    print(randint(1, 100))
74
5
55

반면에 random 모듈의 다른 함수는 항상 모델명과 함께 사용해야 한다. 그렇지 않으면 아래처럼 함수가 정의되지 않았다는 의미의 NameError 오류가 발생한다.

random()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[16], line 1
----> 1 random()

TypeError: 'module' object is not callable. Did you mean: 'random.random(...)'?

6.3모듈 활용법 3: import 모듈명 as 모듈별칭

수학에서 많이 사용되는 log, sin, cos 등의 함수의 정의는 math 모듈에 포함되어 있다. 예를 들어 아래 코드는 정수 2의 자연로그값을 계산한다.

import math

math.log(2)
0.6931471805599453

math 모듈엔 원주율 pi와 같은 중요한 상수도 변수로 정의되어 있으며 사용방법은 동일하다. 단 변수는 소괄호 기호가 사용되지 않는다.

math.pi
3.141592653589793

sin(), cos() 등의 함수도 제공된다. 아래 두 코드는 앞서 언급한 원주율 변수 math.pi를 인자로 활용한다.

math.sin(math.pi/2)
1.0
math.cos(math.pi)
-1.0

그런데 만약에 예를 들어 log() 함수와 pi 변수를 자주 사용한다면 매번 math.log(), math.pi 등으로 모듈명을 함께 사용하는 일이 귀찮을 수 있다. 특히 모듈명이 긴 경우가 그렇다. 이럴 때는 모듈명에 보다 간단한 별칭을 대신 지정하여 함수 호출에 활용할 수 있다. 예를 들어 아래 코드는 math 모듈의 별칭을 m으로 지정하면서 불러온다.

import math as m

그러면 math 모듈에 포함된 모든 함수와 변수를 m.log(), m.pi 등으로 사용할 수 있다.

m.log(2)
0.6931471805599453
m.pi
3.141592653589793
m.sin(m.pi/2)
1.0
m.cos(m.pi)
-1.0

6.4예제

예제 1

(1) random 모듈의 randrange() 함수를 이용하여 0부터 5까지의 정수 중에서 무작위로 하나의 정수를 생성하는 함수를 세 번 호출하라. 단, random 모듈은 아래와같이 불러온다.

import random

답:

randrange() 함수는 하나의 양의 정수 n과 함께 호출되면 0부터 n-1 까지의 정수 중에서 무작위로 하나의 정수를 반환한다. 따라서 0부터 5까지의 정수 중에서 하나를 무작위로 생성하려면 6을 인자로 사용해서 호출한다.

random.randrange(6)
5
random.randrange(6)
3
random.randrange(6)
5

(2) random 모듈의 randrange() 함수를 이용하여 5부터 10까지의 정수 중에서 무작위로 하나의 정수를 생성하는 함수를 세 번 호출하라. 단, random 모듈은 아래와같이 불러온다.

import random

답:

randrange() 함수는 두 개의 양의 정수 n, m과 함께 호출되면 n부터 m-1 까지의 정수 중에서 무작위로 하나의 정수를 반환한다. 따라서 5부터 10까지의 정수 중에서 하나를 무작위로 생성하려면 5와 11을 인자로 사용해서 호출한다.

random.randrange(5, 11)
8
random.randrange(5, 11)
10
random.randrange(5, 11)
6

(3) 아래 코드의 실행 결과를 이용하여 randrange() 함수를 세 개의 인자와 함께 호출되었을 때의 기능을 설명하라.

import random
for _ in [0, 1, 2, 3, 4]:
    print(random.randrange(1, 10, 2))
7
1
1
9
1
for _ in [0, 1, 2, 3, 4]:
    print(random.randrange(0, 10, 3))
6
0
3
3
6

답:

randrange(a, b, c) 형식으로 함수 호출이 되면 a에서 b 이전 까지의 구간에서 값을 무작위로 선택할 때 아래에 언급된 값 중에서 하나 선택한다.

a, a+c, a+2*c, a+3*c, ...

따라서

  • randrange(1, 10, 2): 1부터 9까지의 홀수 중에서 무작위로 하나 선택

  • randrange(0, 10, 3): 0부터 9까지의 수 중에서 3의 배수를 무작위로 하나 선택

예제 2

random 모듈의 randrange() 함수와 randint() 함수의 공통점과 차이점을 예를 이용하여 설명하라.

답:

randint() 함수는 randrange() 함수를 이용해서 다음과 같이 정의되었다.

randint(a, b) = randrange(a, b+1)

따라서 randint(a, b)로 호출되면 무작위로 선택할 수 있는 정수의 구간이 a에서 b까지이다. 반면에 randrange(a, b)로 호출되면 b는 포함되지 않는다.

예를 들어 아래 코드는 실행할 때마다 1 또는 2가 반환값으로 지정된다.

import random

random.randint(1, 2)
2
import random

random.randint(1, 2)
2
import random

random.randint(1, 2)
1

반면에 아래 코드는 항상 1만 생성된다. 이유는 탐색 구간에 2는 포함되지 않기 때문이다.

import random

random.randrange(1, 2)
1
import random

random.randrange(1, 2)
1
import random

random.randrange(1, 2)
1

예제 3

random 모듈의 randint() 함수를 이용하여 주사위 던지기를 시뮬레이션 하는 코드를 구현하라.

답 1:

주사위는 1부터 6까지의 숫자로 표기된 6개의 면을 갖는 정육면체다. 주사위 자체는 생략하고 주사위를 던진 결과만을 고려한다면 randint(1, 6) 함수 표현식으로 주사위를 대신할 수 있다. 이유는 언급된 표현식을 실행할 때마다 1부터 6 사이의 정수가 하나 선택되는데 이 과정을 주사위를 던져서 하나의 수를 얻는 과정에 비유할 수 있기 때문이다.

아래 코드를 실행할 때마다 1에서 6 사이의 정수 하나가 선택된다. 즉, 아래 코드가 주사위 던지기를 시뮬레이션 한다.

import random

print("주사위를 던집니다.")

dice_number = random.randint(1, 6)
print(dice_number, "이(가) 나왔습니다.")
주사위를 던집니다.
4 이(가) 나왔습니다.

답 2:

반면에 정육면체 주사위까지는 아니지만 주사위를 던졌을 때 윗쪽면에 보여지는 숫자 이미지를 모방하는 문자열을 이용하여 주사위 던지기를 아래처럼 시뮬레이션 할 수 있다.

숫자:

   1           2           3           4           5           6

숫자 이미지:

|     |     |0    |     |0    |     |0   0|     |0   0|     |0   0|
|  0  |     |     |     |  0  |     |     |     |  0  |     |0   0|
|     |     |    0|     |    0|     |0   0|     |0   0|     |0   0|

아래 prince_dice() 함수는 지정된 숫자의 이미지를 출력한다.

def print_dice(dice_number):
    if dice_number == 1:
        print("|     |")
        print("|  0  |")
        print("|     |")
    if dice_number == 2:
        print("|0    |")
        print("|     |")
        print("|    0|")
    if dice_number == 3:
        print("|0    |")
        print("|  0  |")
        print("|    0|")
    if dice_number == 4:
        print("|0   0|")
        print("|     |")
        print("|0   0|")
    if dice_number == 5:
        print("|0   0|")
        print("|  0  |")
        print("|0   0|")
    if dice_number == 6:
        print("|0   0|")
        print("|0   0|")
        print("|0   0|")
  • 1에 해당하는 이미지

print_dice(1)
|     |
|  0  |
|     |
  • 3에 해당하는 이미지

print_dice(3)
|0    |
|  0  |
|    0|
  • 6에 해당하는 이미지

print_dice(6)
|0   0|
|0   0|
|0   0|

위 함수를 이용하여 주사위 던지기를 최종적으로 아래 코드로 구현한다. 아래 코드는 실행할 때마다 무작위로 1부터 6 사이의 값에 해당하는 이미지를 출력한다.

import random

print("주사위를 던집니다.")
print("\n")

dice_number = random.randint(1, 6)

print_dice(dice_number)
주사위를 던집니다.


|0   0|
|  0  |
|0   0|
import random

print("주사위를 던집니다.")
print("\n")

dice_number = random.randint(1, 6)

print_dice(dice_number)
주사위를 던집니다.


|     |
|  0  |
|     |

예제 4

이전 예제의 주사위 던지기 코드를 수정하여 사용자로부터 Y를 입력받는 동안 주사위를 반복해서 던지는 프로그램을 구현하라.

힌트: while 반복문과 input() 함수 활용

답:

이전 코드는 주사위를 한 번 던지는 것을 구현한다. 그리고 사용자로부터 입력받은 문자열이 Y인 동안 반복해서 주사위를 던지려면 이전 코드를 while 반복문의 본문으로 사용한다.

while 논리식에 사용되는 논리식은 사용자가 입력한 알파벳이 'Y'인지 여부를 판단해야 한다. 예를 들어 rolling 변수가 사용자의 입력값을 가리킨다고 가정할 때 다음과 같이 while 반복문을 시작할 수 있다.

while rolling == 'Y':
    본문

또한 while 반복문의 본문에서 주사위 한 번 던지기가 완료되면 곧바로 주사위를 계속해서 던질지 여부를 묻고 그 결과를 rolling 변수에 재할당한다. 그러면 사용자의 답변 여부에 따라 주사위 던지기를 반복할지가 결정된다.

위 설명을 정리하면 다음과 같이 주사위 반복 던지기를 구현할 수 있다.

import random

rolling = input("주사위 던지기를 시작하려면 Y를 누르세요! ")

while rolling == "Y":
    print("주사위를 던집니다.")
    print("\n")

    dice_number = random.randint(1, 6)

    print_dice(dice_number)
    print("\n")

    rolling = input("계속하고 싶으면 Y를 누르세요: ")
주사위 던지기를 시작하려면 Y를 누르세요! Y
주사위를 던집니다.


|0   0|
|     |
|0   0|


계속하고 싶으면 Y를 누르세요: Y
주사위를 던집니다.


|0   0|
|  0  |
|0   0|


계속하고 싶으면 Y를 누르세요: N

예제 5

random 모듈의 randrange() 함수, 따라서 randint() 함수는 지정된 정수 구간에서 균등한 확률로 하나의 정수를 선택한다. 이를 확인하는 코드를 작성하라. 예를 들어 randint(1, 6)을 10만 번 호출했을 때 1이 선택되는 경우가 전체의 1/6, 즉 0.1666 정도임을 확인하는 코드를 작성하라.

1/6
0.16666666666666666

힌트: while 반복문, random.randint() 함수 활용

답:

random.randint(1, 6)를 10만 번 호출해서 반환값이 1인지 여부를 확인하는 코드는 다음과 같다.

total = 100_000

toss = 0
while toss < total:
    random.randint(1, 6) == 1
    toss += 1

1부터 6까지의 정수 중에서 무작위로 선택된 값이 1인 경우가 몇 번이었는지를 기억하는 변수 count를 추가한다. while 반복문이 시작하기 전에 0으로 초기화 한 다음에 해당 경우가 발생할 때마다 1씩 커지도록 하면 된다.

total = 100_000
count = 0

toss = 0
while toss < total:
    if random.randint(1, 6) == 1:
        count += 1
    toss += 1

끝으로 count에 저장된 값을 10만으로 나누면 1이 나온 비율이 계산된다. 지금까지의 설명을 코드로 구현하면 다음과 같다.

# import random

total = 100_000
count = 0

toss = 0
while toss < total:
    if random.randint(1, 6) == 1:
        count += 1
    toss += 1

print("1이 나온 비율:", count/total)
1이 나온 비율: 0.16746

동전 던지기를 많이 할 수록 1이 나온 비율이 보다 1/6에 가까워진다.

  • 1백만 번 던질 때

# import random

total = 1_000_000
count = 0

toss = 0
while toss < total:
    if random.randint(1, 6) == 1:
        count += 1
    toss += 1

print("1이 나온 비율:", count/total)
1이 나온 비율: 0.166421
  • 1천만 번 던질 때

# import random

total = 10_000_000
count = 0

toss = 0
while toss < total:
    if random.randint(1, 6) == 1:
        count += 1
    toss += 1

print("1이 나온 비율:", count/total)
1이 나온 비율: 0.1666665

예제 6

컴퓨터는 일반적으로 명령문을 가능한 한 빠르게 실행하려 한다. 하지만 의도적으로 천천히 일을 진행시켜야 하는 경우 time 모듈의 sleep() 함수를 유용하게 활용할 수 있다.

예를 들어 아래 코드를 실행하면 매우 빠르게 실행된다.

count = 0

while count < 5:
    print(count)
    count += 1
0
1
2
3
4

반면에 아래 코드를 실행하면 1초에 한 번 count를 재할당하여 5초 정도 걸린다.

import time

count = 0
while count < 5:
    print(count)
    count += 1
    time.sleep(1)
0
1
2
3
4

time 모듈의 time() 함수를 이용하여 위 두 코드의 실행시간을 비교하라.

답:

time 모듈의 time() 함수는 호출되는 순간 컴퓨터 시간의 기원으로부터 흐른 시간을 초 단위의 부동소수점으로 계산해서 반환한다. 이 점을 이용하여 코드의 처음과 끝에서 time() 함수를 호출하여 차이를 계산하면 코드의 실행시간이 계산된다.

  • 첫째 코드 실행시간: 약 1만 분의 5초

start = time.time()

count = 0

while count < 5:
    print(count)
    count += 1

end = time.time()

print("코드 실행시간:", end - start, "초")
0
1
2
3
4
코드 실행시간: 7.271766662597656e-05 초
  • 둘째 코드 실행시간: 약 5초

start = time.time()

count = 0
while count < 5:
    print(count)
    count += 1
    time.sleep(1)

end = time.time()

print("코드 실행시간:", end - start, "초")
0
1
2
3
4
코드 실행시간: 5.108473062515259 초

예제 7

베스킨라빈스 31 게임은 두 사람이 참여하며 마지막에 31을 부른 사람이 지는 게임으로 규칙은 다음과 같다.

  • 참여자들은 번갈아가며 1부터 31까지의 수를 순서대로 부른다.

  • 한번에 1~3개의 수를 부를 수 있다.

예를 들어, playerA가 1, 2, 3을 부르면, playerB는 4 또는 4, 5 또는 4, 5, 6을 부를 수 있다.

playerA와 playerB가 번갈아서 1에서 3 사이의 수를 입력하면 다음처럼 1부터 31 사이의 정수를 차례대로 지정된 수 만큼 언급하는 코드를 작성하라.

playerA 차례입니다.
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 3
playerA: 1
playerA: 2
playerA: 3

playerB 차례입니다.
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 2
playerB: 4
playerB: 5

playerA 차례입니다.
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 1
playerA: 6

등등

답:

베스킨라빈스 31 게임의 진행에 필요한 구성 요소를 확장하면서 프로그램을 완성한다.

구성요소 1: 원하는 수 만큼의 숫자 이어 부르기

먼저 몇 개의 수를 부를지 선택한 다음 마지막으로 언급된 숫자 다음부터 차례대로 언급한 수 만큼의 숫자를 출력하는 코드는 다음과 같다. 아래 코드는 마지막으로 언급된 숫자가 22라고 가정하고 두 개의 숫자를 부르겠다고 지정한 결과를 보여준다.

  • call = 22: 마지막으로 언급된 숫자

call = 22   # 마지막으로 언급된 숫자 기억

number = int(input("부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): "))

count = 0
while count < number:
    call += 1
    print(call)
    count += 1
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 2
23
24

구성요소 2: 게임 참여자 두 명이 번갈아 가며 원하는 수 만큼의 숫자 이어 부르기

아래 코드는 두 명의 게임 참여자가 번갈아 가며 원하는 수 만큼이 숫자를 차례대로 언급하도록 한다. 시작은 0부터 출발하여 게임 진행을 단순화하기 위해 7을 부르는 사람이 지도록 하였다.

  • final = 7: 언급되면 지는 숫자

참고:

코드에 사용된 break 명령문은 누군가 31을 부르는 순간 해당 break 명령문을 포함한 while 명령문이 더 이상 실행되지 않도록 한다.

import random

final = 7 # 언급되면 지는 숫자
call = 0  # 마지막으로 언급된 숫자 기억

while call < final:

    number = int(input("부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): "))

    count = 0
    while count < number:
        call += 1
        print(call)
        if call == final:
            print("졌습니다.")
            break
        count += 1

    print("\n")
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 2
1
2


부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 1
3


부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 3
4
5
6


부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 2
7
졌습니다.


구성요소 3: 숫자를 불러야 하는 참여자 지정

아래 코드는 게임이 진행되는 동안 숫자를 부를 참여자를 지정하는 방식을 보여준다.

  • player = 0: 숫자를 불러야 하는 게임 참여자. 0은 playerA, 1은 playerB.

  • player = (player + 1) % 2: 게임이 진행될 때마다 숫자를 부를 게임 참여자 바꾸기

import random

final = 7  # 언급되면 지는 숫자
call = 0   # 마지막으로 언급된 숫자 기억
player = 0 # 숫자를 불러야 하는 게임 참여자. 0은 playerA, 1은 playerB.

while call < final:

    if player == 1:
        player_name = 'playerB'
    else:
        player_name = 'playerA'

    print(player_name + " 차례입니다.")

    player = (player + 1) % 2

    call += 1
playerA 차례입니다.
playerB 차례입니다.
playerA 차례입니다.
playerB 차례입니다.
playerA 차례입니다.
playerB 차례입니다.
playerA 차례입니다.

게임 완성

앞서 설명한 3 개의 게임 구성요소를 종합하여 베스킨라벤스 31 게임을 다음과 같이 구현한다.

import random

final = 31 # 언급되면 지는 숫자
call = 0   # 마지막으로 언급된 숫자 기억
player = 0 # 숫자를 불러야 하는 게임 참여자. 0은 playerA, 1은 playerB를 가리킴.

while call < final:

    if player == 1:
        player_name = 'playerB'
    else:
        player_name = 'playerA'

    print(player_name + " 차례입니다.")

    number = int(input("부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): "))

    count = 0
    while count < number:
        call += 1
        print(player_name+":", call)
        if call == final:
            print(player_name+": 졌습니다")
            break
        count += 1

    print("\n")

    player = (player + 1) % 2
playerA 차례입니다.
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 3
playerA: 1
playerA: 2
playerA: 3


playerB 차례입니다.
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 3
playerB: 4
playerB: 5
playerB: 6


playerA 차례입니다.
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 2
playerA: 7
playerA: 8


playerB 차례입니다.
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 1
playerB: 9


playerA 차례입니다.
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 3
playerA: 10
playerA: 11
playerA: 12


playerB 차례입니다.
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 3
playerB: 13
playerB: 14
playerB: 15


playerA 차례입니다.
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 2
playerA: 16
playerA: 17


playerB 차례입니다.
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 1
playerB: 18


playerA 차례입니다.
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 3
playerA: 19
playerA: 20
playerA: 21


playerB 차례입니다.
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 3
playerB: 22
playerB: 23
playerB: 24


playerA 차례입니다.
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 1
playerA: 25


playerB 차례입니다.
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 3
playerB: 26
playerB: 27
playerB: 28


playerA 차례입니다.
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 3
playerA: 29
playerA: 30
playerA: 31
playerA: 졌습니다


예제 8

사람 대 컴퓨터의 베스킨라벤스 31 게임을 구현하라. 단, 사람이 먼저 시작하고 컴퓨터는 임의로 1~3개의 수를 부르도록 한다. 또한 사람이 항상 이기는 전략이 있는지 확인한 후에 해당 전략을 활용하여 게임을 진행하라.

답:

사람과 컴퓨터 구분

숫자를 부를 차례가 사람이면 몇 개를 부를지 지정하라 하고 컴퓨터 차례이면 부를 숫자의 개수를 random.randint() 함수를 이용하여 1에서 3 사이에서 무작위로 선택하도록 한다.

  • 사람이 숫자를 부를 차례인 경우

player = 0

if player == 0:
    number = int(input("부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): "))
else:
    number = random.randint(1, 3)

print("부를 숫자의 개수:", number, "개")
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 2
부를 숫자의 개수: 2 개
  • 컴퓨터가 숫자를 부를 차례인 경우

player = 1

if player == 0:
    number = int(input("부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): "))
else:
    number = random.randint(1, 3)

print("부를 숫자의 개수:", number, "개")
부를 숫자의 개수: 3 개

승리 전략

사람이 playerA, 컴퓨터가 playerB 역할을 수행하도록 한다. 그리고 사람이 항상 4로 나눌 때 나머지가 2인 수까지만 부르는 전략을 따르면 항상 이긴다. 이유는 다음과 같다.

  • 컴퓨터가 31을 부르도록 하기 위해 사람이 30을 불러야 한다.

  • 컴퓨터가 30을 부르지 못하도록 하기 위해 사람이 26을 불러야 한다.

  • 컴퓨터가 26을 부르지 못하도록 하기 위해 사람이 22을 불러야 한다.

  • ...

  • 컴퓨터가 6을 부르지 못하도록 하기 위해 사람이 2을 불러야 한다.

  • 사람이 처음 시작할 때 1과 2를 부른다.

아래 코드를 실행할 때 사람이 먼저 1과 2를 부르고 앞서 설명한 전략을 이용하여 컴퓨터가 부르는 숫자의 개수에 대응하도록 하면 반드시 컴퓨터가 지게 됨을 확인할 수 있다. 즉, 사람은 어떤 경우에도 2, 4, 8, ..., 26, 30을 부르면 반드시 게임을 이긴다.

import random

final = 31 # 언급되면 지는 숫자
call = 0   # 마지막으로 언급된 숫자 기억
player = 0 # 숫자를 불러야 하는 게임 참여자. 0은 playerA, 1은 playerB를 가리킴.

while call < final:

    if player == 1:
        player_name = 'playerB'
    else:
        player_name = 'playerA'

    print(player_name + " 차례입니다.")

    if player == 0:
        number = int(input("부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): "))
    else:
        number = random.randint(1, 3)

    count = 0
    while count < number:
        call += 1
        print(player_name+":", call)
        if call == final:
            print(player_name+": 졌습니다.")
            break
        count += 1

    print("\n")

    player = (player + 1) % 2
playerA 차례입니다.
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 2
playerA: 1
playerA: 2


playerB 차례입니다.
playerB: 3


playerA 차례입니다.
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 3
playerA: 4
playerA: 5
playerA: 6


playerB 차례입니다.
playerB: 7
playerB: 8


playerA 차례입니다.
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 2
playerA: 9
playerA: 10


playerB 차례입니다.
playerB: 11
playerB: 12


playerA 차례입니다.
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 2
playerA: 13
playerA: 14


playerB 차례입니다.
playerB: 15


playerA 차례입니다.
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 3
playerA: 16
playerA: 17
playerA: 18


playerB 차례입니다.
playerB: 19
playerB: 20
playerB: 21


playerA 차례입니다.
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 1
playerA: 22


playerB 차례입니다.
playerB: 23


playerA 차례입니다.
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 3
playerA: 24
playerA: 25
playerA: 26


playerB 차례입니다.
playerB: 27


playerA 차례입니다.
부를 숫자의 개수를 입력하세요 (1, 2, 3만 입력 가능): 3
playerA: 28
playerA: 29
playerA: 30


playerB 차례입니다.
playerB: 31
playerB: 졌습니다.


6.5연습문제