import numpy as np
import matplotlib.pyplot as plt
import datetime
15wk-2: 기말고사
제출은 *.ipynb
, *.html
, *.pdf
파일로 제출할 것
ipynb
파일형태제출을 권장함.
imports
1
. 묵찌빠 (150점)
묵찌빠는 가위바위보의 변형 놀이이다. 보통 가위바위보의 게임과 연이어 진행되는데, 가위바위보 승부 이후 이긴 사람이 공격권을 가지고, 묵(바위)/찌(가위)/빠(보자기) 가운데 하나를 외치는 동시에 말한 것과 일치하도록 손 모양을 바꾼다. 공격권을 가진 사람의 손 모양이 상대(수비권을 가진 사람)의 손 모양과 일치하면 공격권을 가진 사람의 승리한다. 승부가 갈리지 않았을 경우에는 다시 가위바위보를 하는 것이 아니라, 현 상태에서 가위바위보 규칙 상 이긴 사람이 공격권을 가져가게 된다.
(1)
아래는 RPS_BASE 클래스의 구현예시이다.
class RPS_BASE:
def __init__(self,candidate):
self.candidate = candidate
self.actions = list()
def __setitem__(self,index,val):
self.actions[index] = val
def __getitem__(self,item):
return self.actions[item]
def __len__(self):
return len(self.actions)
def __eq__(self,other):
return self[-1] == other[-1]
def __gt__(self,other):
return [self[-1],other[-1]] in [['묵','찌'],['찌','빠'],['빠','묵']]
def __ge__(self,other):
return (self == other) or (self > other)
def __lt__(self,other):
return not (self >= other)
def __le__(self,other):
return (self == other) or (self < other)
def _repr_html_(self):
= """
html_str 낼 수 있는 패: {} <br/>
기록: {}
"""
return html_str.format(self.candidate,self.actions)
def pick(self):
self.actions.append(np.random.choice(self.candidate))
이 클래스에서 아래와 같은 2명의 플레이어 인스턴스를 생성하라.
a
: [‘묵’,‘찌’] 중에 하나를 랜덤으로 선택b
: [‘찌’,‘빠’] 중에 하나를 랜덤으로 선택
두 인스턴스를 100회 랜덤대결하고 결과를 기록하라. 어떠한 플레이어가 더 유리한가?
답안은 100회중 a몇회 승리, b몇회 승리와 같은 숫자형식으로만 나오면 인정한다. (코드를 정리하거나 별도의 클래스를 만드는 것을 요구하지 않음)
(2)
RPS_BASE에서 아래와 같은 두명의 플레이어 인스턴스를 생성하라.
a
: [‘묵’,‘찌’,‘빠’] 중 하나를 랜덤으로 선택b
: [‘찌’,‘빠’] 중 하나를 랜덤으로 선택
아래와 같은 a,b의 attribute을 변경하라.
= [None]
a.modes = [None]
a.actions = [None]
b.modes = [None] b.actions
플레이어 a,b를 이용하여 반복적으로 가위바위보 대결을 수행하고 아래와 같이 대결결과에 따라 공격권을 결정하는 함수 mul
을 만들어라.
경우1: 플레이어 a가 승리할 경우
- a가 공격모드, b가 수비모드가 된다.
a.modes
에는 ‘Attack’ 이b.modes
에는Defence
가 추가된다.a.actions
와b.actions
는 각각의 플레이어가 선택한 패(묵,찌,빠)가 기록된다.
경우2: 플레이어 b가 승리할 경우
- b가 공격모드, a가 수비모드가 된다.
b.modes
에는 ‘Attack’ 이a.modes
에는Defence
가 추가된다.a.actions
와b.actions
는 각각의 플레이어가 선택한 패(묵,찌,빠)가 기록된다.
경우3: 비길경우
- 공격권의 변화는 없다.
a.modes
,b.modes
는 각각 이전의 값이 추가된다.a.actions
와b.actions
는 각각의 플레이어가 선택한 패(묵,찌,빠)가 기록된다.
아래는 함수 mul을 사용한 예시이다.
시점1: 둘다 찌를 내어 공격권을 아무도 획득하지못함
mul(a,b)
a
기록: [None, '찌']
b
기록: [None, '찌']
a.modes
[None, None]
b.modes
[None, None]
시점2: 이번에도 둘다 찌를 내어 아무도 공격권을 획득하지 못함
mul(a,b)
a
기록: [None, '찌', '찌']
b
기록: [None, '찌', '찌']
a.modes
[None, None, None]
b.modes
[None, None, None]
시점3: 이번에는 a가 공격권을 획득 (묵>찌)
mul(a,b)
a
기록: [None, '찌', '찌', '묵']
b
기록: [None, '찌', '찌', '찌']
a.modes
[None, None, None, 'Attack']
b.modes
[None, None, None, 'Defence']
시점4: 이번에는 b가 공격권을 획득 (찌>빠)
mul(a,b)
a
기록: [None, '찌', '찌', '묵', '빠']
b
기록: [None, '찌', '찌', '찌', '찌']
a.modes
[None, None, None, 'Attack', 'Defence']
b.modes
[None, None, None, 'Defence', 'Attack']
(3)
RPS_BASE를 상속받아 MookjjibbaPlayer라는 새로운 클래스를 정의하라. MookjjibbaPlayer 클래스에서 아래의 메소드를 새롭게 정의 혹은 재정의하여
__init__
_repr_html_
__mul__
reset
인스턴스가 아래와 같은 동작을 하도록 설계하라.
시점0: 생성예시 (__init__
)
=MookjjibbaPlayer(['묵','찌','빠'])
a=MookjjibbaPlayer(['묵','찌','빠']) b
a.actions
[None]
a.modes
[None]
__init__
의 동작
- 슈퍼클래스(RPS_BASE)의
__init__
을 동작시킴 - MookjjibbaPlayer의 인스턴가 가지는 actions, modes 값을 [None] 으로 초기화
시점0: 출력예시(_repr_html_
)
a
기록: [None]
모드: [None]
b
기록: [None]
모드: [None]
_repr_html_
의 동작
위와 같이 “낼 수 있는 패”, “기록”, “모드” 가 함께 출력되도록 설계할 것
시점1: 대결 및 결과출력 (__mul__
, _repr_html_
)
*b a
a
기록: [None, '묵']
모드: [None, None]
b
기록: [None, '묵']
모드: [None, None]
__mul__
의 동작
- 두 플레이어의 대결을 진행
- 결과를 보고 modes 의 값을 update
위의 상황은 두 플레이어 모두 “묵”을 내어 어느쪽도 공격권을 가지지 못한 상태를 의미
시점2: 대결 및 결과출력 (__mul__
, _repr_html_
)
*b a
a
기록: [None, '묵', '묵']
모드: [None, None, 'Defence']
b
기록: [None, '묵', '빠']
모드: [None, None, 'Attack']
__mul__
의 동작
- 두 플레이어의 대결을 진행
- 결과를 보고 modes 의 값을 update
위의 상황은 a가 묵, b가 빠를 내어 b가 공격권을 획득한 상황을 의미
시점3: 대결결과의 초기화 (reset
)
a
기록: [None, '묵', '묵']
모드: [None, None, 'Defence']
a.reset()
a
기록: [None]
모드: [None]
reset
의 동작
- 플레이어의 기록을 초기화
- 플레이어의 모드를 초기화
(4)
(3)
에서 생성된 MookjjibbaPlayer의 두 개의 인스턴스 a,b를 입력으로 받고 최초공격권을 결정하는 함수 jumpball
을 설계하라.
아래는 jumpball함수의 사용예시이다.
a
기록: [None]
모드: [None]
b
기록: [None]
모드: [None]
jumpball(a,b)
a
기록: [None, '찌', '찌', '찌']
모드: [None, None, None, 'Defence']
b
기록: [None, '찌', '찌', '묵']
모드: [None, None, None, 'Attack']
hint: 아래의 코드를 관찰
= []
a = []
b 0,1,2]))
a.append(np.random.choice([0,1,2]))
b.append(np.random.choice([while a==b:
0,1,2]))
a.append(np.random.choice([0,1,2])) b.append(np.random.choice([
a
[0, 0, 0, 1]
b
[0, 0, 0, 0]
(5)
지금까지 코드를 바탕으로
- a: [‘묵’,‘찌’] 중 하나를 랜덤으로 고르는 플레이어
- b: [‘찌’,‘빠’] 중 하나를 랜덤으로 고르는 플레이어
를 설정하여 100회 가상대결을 진행하라. 100회 가상대결결과를 제시하라.
(참고) – 아래는 제가 구현한 예시입니다. 참고용일 뿐이며 이와 같은 방식으로 구현할 필요는 없습니다.
1. a,b 두명의 플레이어 생성
=MookjjibbaPlayer(['묵','찌'])
a=MookjjibbaPlayer(['찌','빠']) b
a
기록: [None]
모드: [None]
b
기록: [None]
모드: [None]
a,b 플레이어가 초기화
2. a,b 두명의 플레이어를 입력으로 하여 게임1을 생성후 1회 게임진행
= PlayMookjjibba(a,b) game
game.play()
a
기록: [None, '찌', '묵', '묵', '찌']
모드: [None, 'Attack', 'Defence', 'Defence', 'Defence']
b
기록: [None, '빠', '빠', '빠', '찌']
모드: [None, 'Defence', 'Attack', 'Attack', 'Attack']
a가 찌, b가 빠를 내어 최초 공격권을 a가 획득하였지만 이후 공격권을 상실한 상실함. 이후 4번째 가위바위보에서 b가 a가 동시에 찌를 내며 b의 승리로 마무리됨
3. game.records 에 b의 승리가 기록되어 있음
game.records
['b']
4. 1회 대결기록을 삭제하고 또 다른 게임을 진행: 이번에는 a의 승리
game.reset_player_history()
a
기록: [None]
모드: [None]
b
기록: [None]
모드: [None]
game.play()
a
기록: [None, '찌', '찌', '찌']
모드: [None, None, 'Attack', 'Attack']
b
기록: [None, '찌', '빠', '찌']
모드: [None, None, 'Defence', 'Defence']
공격권은 2번만에 A가 획득, 1번의 공격을 통하여 마무리
5. 이번에는 a의 승리가 기록됨
game.records
['b', 'a']
2
. 종합문항 (50점)
(1)
LinearRegression 이라는 이름의 클래스를 만들고 아래의 기능을 넣어라.
__init__
: “클래스 \(\to\) 인스턴스” 인 시점에 길이가 \(n\)인 numpy array \({\bf x}=(x_1,\dots,x_n)\), \({\bf y}=(y_1,\dots,y_n)\)을 입력으로 받아 내부에 저장한다.
fit
: fit은 내부에 저장된 \({\bf x}\), \({\bf y}\)를 이용하여 \(\hat{\bf y}=(\hat{y}_1,\dots,\hat{y}_n)\)을 계산하는 역할을 한다. 계산은 아래의 수식을 이용한다. \[\hat{\bf y}= {\bf X}({\bf X}^T {\bf X})^{-1}{\bf X}^T {\bf y}, \quad {\bf X}=\begin{bmatrix} 1 & x_1 \\ 1 & x_2 \\ \dots \\ 1 & x_n \end{bmatrix}\]
plot
: plot은 \((x_i,y_i)\)와 \((x_i,\hat{y}_i)\)를 시각화하는 역할을 한다.
아래의 자료를 LinearRegression의 입력으로 받고 시각화하는 분석을 수행하라.
= np.linspace(0,1,100)
x = 2*x + np.random.normal(size=100)
y 'o') plt.plot(x,y,
(2)
앞면과 뒷면이 나올 확률이 각각 1/2인 동전을 생각하자. 하니와 규빈은 이 동전을 연속으로 던져서 아래와 같은 룰을 정하여 내기를 하였다.
- 동전을 연속으로 반복하여 던진다. 최근 2회의 결과가 (뒷면,앞면) 이 나오면 하니의 승리
- 동전을 연속으로 반복하여 던진다. 최근 2회의 결과가 (뒷면,뒷면) 이 나오면 규빈의 승리
이 내기는 하니가 유리한가? 규빈이 유리한가? 시뮬레이션을 통해 검증하라.
hint: 똑같이 유리하다
(3)
앞면과 뒷면이 나올 확률이 각각 1/2인 동전을 생각하자. 하니와 규빈은 이 동전을 연속으로 던져서 아래와 같은 룰을 정하여 내기를 하였다.
- 동전을 연속으로 반복하여 던진다. 최근 2회의 결과가 (앞면,뒷면) 이 나오면 하니의 승리
- 동전을 연속으로 반복하여 던진다. 최근 2회의 결과가 (뒷면,뒷면) 이 나오면 규빈의 승리
이 내기는 하니가 유리한가? 규빈이 유리한가? 시뮬레이션을 통해 검증하라.
hint: 이 내기는 하니가 유리하다.
(4)
Time을 상속받아 Init 클래스를 만들고 __repr__
을 조작하여 아래와 같이 인스턴스 생성시점을 출력하는 기능을 구현하라.
class Time:
def time(self):
return datetime.datetime.now().strftime('%y-%m-%d %X')
= Init() a
a
인스턴스생성시점: 23-06-16 10:27:19
= Init() b
a,b
(인스턴스생성시점: 23-06-16 10:27:19, 인스턴스생성시점: 23-06-16 10:27:28)
(5)
tuple 클래스와 아래의 Check를 상속받아 아래와 같은 역할을 하는 새로운 Tuple 클래스를 만들라.
class Check:
def ckeck(self):
return [l for l in dir(self) if l[0]!='_']
= Tuple('asdfassdfsasdf')
tpl # 값과 함께 사용가능한 메소드가 함께 출력 tpl
('a', 's', 'd', 'f', 'a', 's', 's', 'd', 'f', 's', 'a', 's', 'd', 'f')
methods=['ckeck', 'count', 'freq', 'index']
tpl.freq()
{'d': 3, 'a': 3, 's': 5, 'f': 3}
(6)
아래와 같은 클래스를 고려하자.
class Init(object):
def __init__(self,value):
self.value = value
class Times2(Init):
def __init__(self,value):
super().__init__(value)
self.value = self.value * 2
class Plus5(Init):
def __init__(self,value):
super().__init__(value)
self.value = self.value + 5
Plus5
와 Times2
를 상속하여 적당한 클래스 Times2Plus5
를 정의하고 생성과 동시에 \(x \to (x\times 2)+5\) 를 수행도록 하라.
사용예시
=Times2Plus5(0)
a a.value
5
=Times2Plus5(1)
a a.value
7
=Times2Plus5(5)
a a.value
15
(7)
아래의 함수가 있다고 하자.
def f(x):
return np.sin(x)
적당한 함수 derivate
를 정의하여 함수를 입력으로 받으면 그 도함수를 출력으로 리턴하도록 하라. 아래의 코드를 이용하여 검증하라.
= np.linspace(-6,6,100)
x =r'$f(x)=\sin(x)$')
plt.plot(x,f(x),label=r'$f\'(x)=\cos(x)$')
plt.plot(x,(derivate(f))(x),label plt.legend()
<matplotlib.legend.Legend at 0x7f236da92ee0>
(8)
Student 클래스를 생성지침 및 사용예시를 참고하여 설계하라.
생성지침
attributes
name
: 이름을 저장하는 변수age
: 나이를 저장하는 변수semester
: 학기를 저장하는 변수
methods
__init__
: name, age, semester 세 가지 매개변수를 입력받아 인스턴스의 attribute로 저장__str__
: 인스턴스의 정보(이름,나이,학기)를 문자열 형태로 반환
사용예시
# 사용 예시
= Student(name='김보람', age=20, semester=1)
boram print(boram)
이름: 김보람
나이: 20
학기: 1
(9)
8의 클래스를 상속받아 Student2 만들라. __add__
재정의하여 Student2의 인스턴스가 아래와 같이 동작하도록 하라.
= Student2() boram
입학을 축하합니다. 당신의 나이는 20.0이고 현재 학기는 0학기 입니다.
+ '등록'+ '휴학' + '등록' + '휴학'
boram boram
학기: 2
4학기가 지났으므로 나이는 22살이 된다. 4학기중 2학기만 등록하였으므로 현재는 2학기를 마친상태이다.
(10)
적당한 클래스를 선언하여 \(f(x)=x+{\tt const}\)를 수행하는 함수를 생성하도록 하라.
사용예시1
= AddConstant(5) # f(x) = x+5 f
10) f(
15
사용예시2
= AddConstant(-3) # f(x) = x-3 f
10) f(
7