일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- wetube
- crud
- react
- 튜플
- 중급파이썬
- pandas
- Class
- NeXT
- MongoDB
- git
- TypeScript
- socket io
- RDS
- docker
- 채팅
- lambda
- SAA
- SSA
- flask
- node
- 카톡
- merge
- AWS
- dict
- EC2
- async
- S3
- 파이썬
- Vue
- Props
- Today
- Total
초보 개발자
세 번째 개인 과제 고블린 사냥 본문
import random
class Object():
def __init__(self, name, hp, power):
self.name = name
self.hp = hp
self.power = power
self.critic_damage = 10
self.amor = 0
self.miss = 0
def attack(self, enemy):
critic_per = random.randrange(1,11)
if critic_per <= 3:
miss_per = random.randrange(1,101)
if miss_per < enemy.miss:
print(f'{self.name}이/가 {enemy.name}을/를 공격 했지만 회피하였습니다.')
return
else:
enemy.hp -= (self.power + self.critic_damage - self.amor)
else:
enemy.hp -= self.power
if enemy.hp <= 0:
enemy.hp = 0
print(f'{self.name}이/가 {enemy.name}을/를 공격 했고 {enemy.name} 체력이 {enemy.hp} 남아 전사하였습니다.')
if type(enemy).__name__ =='Monster':
if enemy.item =='고블린소드':
self.power += 20
print(f'{self.name}이/가 고블린 소드를 얻어 공격력이 20 증가하였습니다.')
elif enemy.item == '꿀열매':
self.hp += 10
print(f'{self.name}이/가 꿀열매 먹어 체력이 10 증가하였습니다.')
elif enemy.item == '팔목보호대':
self.amor += 10
print(f'{self.name}이/가 팔목보호대를 얻어 방어력이 10 증가하였습니다.')
else:
self.amor += 20
print(f'{self.name}이/가 쉴드를 얻어 방어력이 20 증가하였습니다.')
return
else:
if critic_per <= 3:
print(f'{self.name}이/가 {enemy.name}을/를 크리티컬!!! 공격 했고 {enemy.name} 체력이 {enemy.hp} 남았습니다.')
else:
print(f'{self.name}이/가 {enemy.name}을/를 공격 했고 {enemy.name} 체력이 {enemy.hp} 남았습니다.')
class Player(Object):
def __init__(self):
super().__init__('전사',100,10)
def magic(self,enemy):
enemy.hp -= 50
if enemy.hp <= 0:
enemy.hp = 0
print(f'{self.name}가 마법공격을 했고 {enemy.name}의 체력이 {enemy.hp} 남아 전사 하였습니다.')
if type(enemy).__name__ =='Monster':
if enemy.item =='고블린소드':
self.power += 20
print(f'{self.name}이/가 고블린 소드를 얻어 공격력이 20 증가하였습니다.')
elif enemy.item == '꿀열매':
self.hp += 10
print(f'{self.name}이/가 꿀열매 먹어 체력이 10 증가하였습니다.')
else:
self.amor += 10
print(f'{self.name}이/가 팔목보호대를 얻어 방어력이 10 증가하였습니다.')
return
print(f'{self.name}가 마법공격을 했고 {enemy.name}의 체력이 {enemy.hp} 남았습니다.')
class Monster(Object):
def __init__(self,name,hp,power,item):
super().__init__(name,hp,power)
self.item = item
def wait(self):
print(f'{self.name}이 대기 했습니다.')
def heal(self):
self.hp += 10
print(f'{self.name}이 자신의 체력을 10만큼 회복 했습니다.')
class Flayable_Monster(Monster):
def __init__(self,name,hp,power,item):
super().__init__(name,hp,power,item)
self.miss = 50
print(self.name,self.miss)
def who(goblins,name):
for i in goblins:
if i.name == name:
return i
def init():
super_goblin = Monster('슈퍼고블린',50,50,'고블린소드')
normal_goblin = Monster('고블린',30,30,'팔목보호대')
mini_goblin = Monster('미니고블린',10,10,'꿀열매')
fly_goblin = Flayable_Monster('대왕고블린',100,40,'쉴드')
goblin_party = [super_goblin,normal_goblin,mini_goblin,fly_goblin]
worrier = Player()
return worrier , goblin_party
def print_status(worrier, goblin_party):
print('--------------------------')
print('체력표시')
print('--------------------------')
print(f'전사: {worrier.hp}\n')
for goblin in goblin_party:
print(f'{goblin.name}: {goblin.hp}')
print('--------------------------')
def worrier_targeting():
while True:
attack_or_magic = input('[공격과 마법] 어떤 걸 사용하시겠습니까? : ')
if attack_or_magic in ['공격','마법']:
break
print('[공격과 마법]중에서만 적어주세요.')
while True:
whom = input('고블린의 이름을 말씀해 주십시오. : ')
if whom in ['슈퍼고블린', '고블린','미니고블린','대왕고블린']:
break
print('[슈퍼고블린', '고블린','미니고블린,대왕고블린]중에서만 적어주세요.')
return whom , attack_or_magic
def worrier_fighting(goblin_party,whom,worrier,attack_or_magic):
print('--------------------------')
print('전투시작 - 전사')
print('--------------------------')
whom = who(goblin_party, whom)
if (attack_or_magic == '공격'):
worrier.attack(whom)
else:
worrier.magic(whom)
if whom.hp <= 0:
goblin_party.remove(whom)
if len(goblin_party) == 0:
print('승리')
return 1
def goblins_fighting(goblin_party,worrier):
print('--------------------------')
print('전투시작 - 고블린')
print('--------------------------')
for goblin in goblin_party:
ran = random.randrange(0, 3)
if ran == 0:
goblin.wait()
elif ran == 1:
goblin.heal()
else:
goblin.attack(worrier)
if worrier.hp <= 0:
print('패배')
return 1
worrier, goblin_party = init()
while True:
print_status(worrier, goblin_party)
target, attack_or_magic = worrier_targeting()
flag = worrier_fighting(goblin_party, target, worrier, attack_or_magic)
if flag == 1:
break
flag = goblins_fighting(goblin_party,worrier)
if flag == 1:
break
클래스는 활용해 보는 시간이었다. 나도 코딩님께서 클래스를 아주 쉽게 설명해주셔서 듣기 편했다.
파이썬 코딩 무료 강의 (기본편) - 6시간 뒤면 여러분도 개발자가 될 수 있어요 [나도코딩] - YouTube
클래스를 상속받아서 생성자 함수를 만들 때는 아래와 같다.
class Person():
def __init__(self,name,height,weight)
self.name = name
self.height = height
self.weight = weight
class FastPerson(Person):
def __init__(self,name,height,speed)
# Person에서 받은 초기값을 설정한다.
# 이 값을 FastPerson이 생성하면서 받아와서 (self,name,height,speed)
# 집어 넣어도되고 그냥 80처럼 고정값을 넣어도됨
Person.__init__(self,name,height,80)
# FastPerson 클래스 만의 초기값
self.speed = speed
enemy(클래스 객체)를 받아와서 체력을 깎을 때 enemy.hp -= 50 이렇게 코드를 작성하였는데.. 이게 되는걸까???
이 부분에 대한 나의 생각은 아래에 적어두었다.
게임 진행을 while문에 다 적어놔서 좀 지저분해보이는데 이번 과제에서는 따로 명시사항이 없어서 그냥 다듬지 않고 제출하였다. 고블린 이름을 받아와서 해당하는 고블린에 데미지를 입히는 과정에서 고블린 이름은 'str' 인데 저장해놓은 고블린은 class 객체 인데 단순히 list.index()로 찾으려고 했었다. ㅋㅋ
어떻게 할지 고민좀 하다가 그냥 함수를 하나 만들어서 return해주는 방식을 활용하였다.
def who(goblins,name):
for i in goblins:
if i.name == name:
return i
goblins에는 고블린들을 담은 list가 들어온다. 그리고 name에는 입력받은 고블린 이름('str')이 들어온다.
i.name 과 name을 비교하니까 이젠 'str' 끼리 비교가 가능해지니까 같다면 return해주는 형식으로 풀어봤다.
추가적으로 죽이면 아이템, 회피, 아머, 크리티컬 등을 추가해보았다.
클래스의 상속에 대해서 좀 더 많은 공부가 필요할 것 같다.
--------------------------------------------------------------------------------------------------------------------------
a = 10
def change(num):
num = 15
change(a)
print(a)
이런 코드가 있을경우 a의 값이 바뀔까?
바뀔 리가 없다.
a = [1,2,3]
def change(arr):
arr[0] = 4
change(a)
print(a)
그렇다면 이 코드는 a의 값이 바뀔까? 바뀐다. a의 값을 출력해보면 놀랍게도 [4,2,3]이 출력된다.
C언어에서는 이게 가능하려면 단순히 값을 가져오는 것이 아닌 포인터를 활용해서 그 변수가 가리키고 있는 주소에 가서 그 주소에 있는 값을 바꾸어야 이게 가능하다. 근데 파이썬에서는 변수가 포인터의 역할도 하는 것 같다. 여기서 이제 헷갈리기 시작한다.
a = 10
def change(num):
num = 15
change(a)
print(a)
이 경우에 상수는 이뮤터블객체이다. 즉 변경할 수 없는 객체이다. 그림으로 설명해보자면 처음은 다음과 같을 것이다.
a → 10
num ↗
num이라는 변수에 a의 값을 참조해오기 때문에 위와 같은 상황이 나타난다. 여기서 말했던 것처럼 이뮤터블 객체는 변경이 불가능하기에,
a → 10
num → 15
이런식으로 새로운 상수를 만들어버린다. 따라서 print(a)를 했을 경우에 온전히 a는 10으로 남아있는 상태이다.
자 그럼 다음은 어떨까?
a = [1,2,3]
def change(arr):
arr[0] = 4
change(a)
print(a)
아까와 마찬가지로 처음 arr은 아래와 같은 상황일 것이다.
a → [1,2,3]
num ↗
다만 여기서 arr[0] =4를 실행하고 나면 놀랍게도 아래와 같이 변해있다.
a → [4,2,3]
num ↗
이 부분에 관해서는 전에 살짝 공부해 본 적이 있었다.
2021.12.15 - [Python/윤성우 열혈 파이썬] - 3강 깊은 복사와 얕은 복사
이번 세 번째 개인 과제를 진행하면서 나는 이 부분이 다시 헷갈리기 시작했다.
def magic(self,enemy):
enemy.hp -= 50
enemy.hp는 상수잖아? 기존의 값을 변경하니 새로운 id값에 생기겠네?
goblin.hp → 50
enemy.hp ↗
그럼 결국 처음에 있던 goblin.hp는 그대로 이지 않을까?
goblin.hp → 50
enemy.hp → 0
따라서 magic 메소드 안에 있을 때 enemy.hp로 goblin.hp를 참조 하는 동안만 바뀌고 실질적으로 goblin.hp는 그대로 일거라고 생각했다.
근데 !?
게임을 진행하다보니까 goblin.hp도 0으로바뀌었잖아... 나는 내가 코드를 작성했지만 바뀌지 않을거라고 생각했는데 바뀌었다. 심지어 id도 바뀌었다... ??????? 이러면 안되는거아니야???
--------공격전 goblin.hp----------
슈퍼고블린 의 생성되었을 때 hp의 id 값 2840662601552
--------공격----------------------
마법 공격 전 슈퍼고블린 hp의 id 2840662601552 (goblin.hp)
슈퍼고블린 의 공격 받기 전 hp의 id 값 2840662601552 (enemy.hp)
----------------------------------------------------
슈퍼고블린 의 공격 받은 후 hp의 id 값 2840662599952 (enemy.hp)
전사가 마법공격을 했고 슈퍼고블린 체력이 0 남아 전사 하였습니다.
--------공격 끝-------------------
마법 공격 후 슈퍼고블린 hp의 id 2840662599952 (goblin.hp)
즉 나의 머릿 속에서는 아래와 같은 상황이 벌어진 것이다. 이러면 안되잖아..
a = 10 # (a의 id를 123이라고 가정)
def change(num):
num = 15 # (num의 id를 345라고 가정)
change(a)
print(a)
# a는 15를 출력하고 id값또한 345로 바뀐 것
결론부터 말하면 반은 맞고 반은 틀린 것 같다.
고민을 하다가 문득 든 생각이
리스트의 요소는 바뀔 수 있다 → 리스트의 주소는 안바뀐다 → 요소의 주소도 안바뀔까? → 요소는 상수라 주소도 바뀔걸? 이걸 해결하면 지금 고민하는 문제도 해결할 수 있지 않을까? 라는 생각에 arr를 변화를 샅샅히 뒤져보았다.
함수시작전 a의 주소 2840663649088
함수시작전 a[0]의 주소 2840662599984
-------------------
함수시작 후 변경 전 ref의 주소 2840663649088
함수시작 후 변경 전 ref[0]의 주소 2840662599984
함수시작 후 변경 전 글로벌 변수 a의 값 2840663649088
함수시작 후 변경 전 글로벌 변수 a[0]의 값 2840662599984
함수시작 후 변경 후 ref의 주소 2840663649088
함수시작 후 변경 후 ref[0]의 주소 2840662600080
함수시작 후 변경 후 글로벌 변수 a의 값 2840663649088
함수시작 후 변경 후 글로벌 변수 a[0]의 값 2840662600080
-------------------
함수 내 ref의 변경 값 [4, 2, 3]
함수 내 글로벌 변수 a의 값 [4, 2, 3]
-------------------
함수 끝 a의 값 [4, 2, 3]
함수 종료후 a의 주소 2840663649088
함수 종료후 a[0]의 주소 2840662600080
여기서 ref[0] = 4로 넣는 순간 글로벌 변수인 a에서도 a[0]의 주소값이 실시간으로 바뀐 것을 보았다.
이렇게 확인해보니 리스트의 주소는 바뀌지 않았지만 그 요소에는 새로운 값의 주소가 들어오고 그 리스트의 자리(index)가 그 주소를 참조하고 있는 것이다.
나는 enemy.hp가 단순히 상수인 줄로만 알았다. 이 부분에서 궁금증이 시작된 것같다. 근데 enemy.hp는 클래스의 속성이다. 구글링 해보니까 사용자 지정 클래스는 뮤터블이라고 한다.
따라서 클래스도 리스트와 마찬가지로 상수자체의 값은 바꾸지 못하지만 바뀐 상수의 주소가 리스트의 index처럼 클래스의 자리에도 들어온 것이 아닐까? 라는 생각을 하였다.
즉 리스트도 리스트 그 자체의 주소는 바뀌지 않지만 요소의 주소는 바뀌는 것처럼, 클래스도 인스턴스 자체의 주소는 바뀌지 않지만 인스턴스가 가진 속성은 주소가 바뀔 수 있다.
'AI 웹개발 트랙 - 내배캠 > 2주차' 카테고리의 다른 글
5번째 과제 인스타 화면 구현 및 튜터님 코드 분석 1 (0) | 2021.12.24 |
---|---|
네 번째 과제 카카오톡 프로필 구현 그리고 반응형 웹 ( %, vw, vh, em, rem) (0) | 2021.12.23 |
두 번째 개인 과제 베스킨 라빈스 31 게임 (0) | 2021.12.21 |
2주차 링크드리스트 (0) | 2021.12.20 |
첫 개인과제 up_and_down (0) | 2021.12.20 |