깃허브 리포지토리는 여기
어쩌다 보니 공을 튀기는 것만 세 번째 하게 됐다. 16년도, 학교 기숙사에 살 때 룸메이트랑 종종 내기 피카츄 배구를 하곤 했는데, 거의 이겨본 적이 없었다(지금도 마찬가지임). 이후 둘 다 전역하고 자율로봇지능 강의를 함께 들었는데, 그 학기가 끝나고 피카츄 배구 강화 학습을 해보자는 아이디어가 나왔다. 나는 이길 수 없지만 내가 학습시킨 지상 최강의 피카츄는 다르지 않을까?
피카츄 배구 원작 게임을 리버스 엔지니어링해 자바스크립트로 만든 이 리포지토리의 코드가 이미 있어 이를 파이썬으로 재작성(Pykachu ㅋㅋ)하기만 하면 됐지만, 파이썬으로 화면을 어떻게 그리는지를 몰라 만들다가 도중에 그만 뒀었다. 예전에 올린 포켓볼 시뮬레이터와 마찬가지로, 이번에 경험 정리 겸 깃허브에 방치해놨던 코드들을 정리하면서 다시 만들었다.
이 리포지토리 의 코드를 바탕으로, 강화 학습을 위한 gymnasium
라이브러리에 맞게 파이썬으로 재작성했습니다. 지금은 멀티-에이전트가 아니라, 원래 게임에 구현되어 있는 컴퓨터를 상대로 하는 싱글-에이전트 학습 환경입니다. 멀티-에이전트 학습 환경은 추후 pettingzoo
를 사용해 추가될 예정입니다.
나타나는 화면은 pygame
을 이용해 구현했습니다. 개발은 다음과 같은 환경에서 진행됐습니다.
env | version |
---|---|
Ubuntu | 22.04 |
Python | 3.10.12 |
gymnasium | 0.29.1 |
pygame | 2.5.2 |
numpy | 1.26.4 |
#this is in sample.py
import gymnasium as gym
import pykachu_env
env = gym.make('PykachuVolleyball-v0',
render_mode= "human",
is_player_2_computer=False)
리포지토리에 있는 sample.py
를 참고합시다. 학습 환경은 패키지를 임포트한 후, gym.make('PykachuVolleyball-v0')
를 통해 만듭니다. 추가적으로 render_mode
, is_player_2_computer
옵션을 줄 수 있습니다. is_player_2_computer
는 두 플레이어 중 어느 쪽이 상대편인 컴퓨터가 될지를 결정합니다.
Action Space | MultiDiscrete([3, 3, 1]) |
Observation Space | (432, 304, 3) |
Observation High | 255 |
Observation Low | 0 |
action space는 MultiDiscrete([3, 3, 1])
로, 각각 순서대로 좌우 이동, 상하 이동, 강타?의 입력에 해당합니다.
action_space[0]
(좌우 이동)Value | Meaning |
---|---|
0 | input left movement |
1 | NOOP |
2 | input right movement |
action_space[1]
(상하 이동)Value | Meaning |
---|---|
0 | input up movement |
1 | NOOP |
2 | input down movement |
action_space[2]
(강타)Value | Meaning |
---|---|
0 | NOOP |
1 | input power hit |
observation space는 Box(low=0, high=255, shape=(432, 304, 3), dtype=np.uint8)
로, 그려진 화면의 RGB값 배열에 해당합니다.
#this is in sample.py
for episode in range(5):
env.reset()
while True:
env.render()
action = env.action_space.sample()
state, reward, terminated, info = env.step(action)
if terminated:
break
env.close()
step()
함수는 observation
뿐만 아니라, reward
, terminated
, info
도 반환합니다.
reward
학습 중인 플레이어가 이기면 +1
, 지면 -1
의 보상을 받습니다.
terminated
공이 땅에 닿아 새 라운드가 시작되어야 하면 True
, 그렇지 않으면 False
가 됩니다.
info
info
에는 아래와 같은 추가 정보들이 들어있습니다.
{
"player1": {
"x": player1.x,
"y": player1.y,
"dive_direction" : player1.dive_direction
},
"player2":{
"x": player2.x,
"y": player2.y,
"dive_direction" : player2.dive_direction
},
"ball": {
"x": ball.x,
"x_velocity": ball.x_velocity,
"y": ball.y,
"y_velocity": ball.y_velocity,
}
}
코드가 gymnasium
API와 완전히 호환되지는 않을 수 있기 때문에, 버그가 발생하거나 추가적인 구현이 필요한 경우는 알려주세요
Pykachu라.. 작명센스 좋네ㅛ