- 내일배움캠프 11일차 목차
[오늘 한일]
- 알고리즘세션 수강
- 파이썬 팀과제(게임만들기) 진행
[오늘 배운점]
<pop을 이용한 대상 골라내기>
월~수 예비군을 다녀왔고, 어제까지 진행된 팀 과제에 합세했다.
일반 전투 부분에 약간 문제점이 있는 상황이였다.
우리는 n대n 턴제전투를 구상했고 전투 전에 몬스터 그룹이 생성된다.
4가지의 기본 몬스터 중에서 1~3마리의 몬스터를 랜덤으로 선택하게 된다.
그런데 이럴 경우 몬스터가 중복 생성되는 경우가 생겼고, (뱀, 뱀 이런식이다.)
중복으로 두마리일 경우에 두마리가 같은 몬스터라서 hp가 동시에 깎이는 문제가 생겼다.
monster_list = [
Monster("쥐", avg_lv, 70, 0, 13, 15, 10),
Monster("까치", avg_lv, 100, 0, 18, 18, 7),
Monster("바퀴벌레", avg_lv, 110, 0, 15, 30, 12),
Monster("뱀", avg_lv, 80, 0, 20, 20, 10)
]
몬스터 리스트는 이렇다.
문제 상황에서 내가 먼저 생각을 정리한 내용은 이렇다.
- 몬스터 리스트는 인스턴스의 집합이다. 그래서 각 몬스터는 고유하다.
- 그렇기 때문에 몬스터는 중복되면 안된다.
그래서 몬스터를 중복 선택하지 않으면서 그룹을 생성하는 방법을 고민했다.
기본 몬스터는 4, 선택해야 하는건 1~3마리고 선택이 랜덤이면서 중복되지 않아야한다.
그러다 아침에 배운 스택 내용 중 pop이라는 게 떠올랐다.
pop은 스택 데이터에서 데이터를 출력하면서 메모리에서는 지우는 동작을 말한다.
리스트에서 꺼내면서 지우는 방법이면 해결할수 있겠다고 생각했다.
def prebattle():
monster_list = [
Monster("쥐", avg_lv, 70, 0, 13, 15, 10),
Monster("까치", avg_lv, 100, 0, 18, 18, 7),
Monster("바퀴벌레", avg_lv, 110, 0, 15, 30, 12),
Monster("뱀", avg_lv, 80, 0, 20, 20, 10)
]
battle_monster = []
for i in range(random.randint(1,3)):
battle_monster.append(random.choice(monster_list))
기존 함수의 모습은 이렇다.
random.choice로 몬스터 리스트에서 선택해서 battle_monster에 집어넣는걸,
1~3의 랜덤한 수만큼 반복한다.
이 경우에 2,3번째 반복에서 같은 몬스터 인스턴스를 선택할 가능성이 있다.
이 부분을 이렇게 바꿨다.
for i in range(random.randint(1, 3)):
battle_monster.append(monster_list.pop(
random.randint(0, len(monster_list)-1)))
바뀐 함수 부분.
monster_list.pop(i)로 i번째 값을 뽑아내며 리스트에서는 지운다.
i는 len(monster_list)-1으로 몬스터 리스트의 수량 중 랜덤한 숫자를 쓰고,
이걸 1~3의 랜덤한 수만큼 반복한다.
이렇게 하면 뽑힌 몬스터는 몬스터 리스트에서 제외되서,
2,3번째 반복에서는 해당 몬스터가 뽑힐 수 없다.
이렇게 작성하니 의도대로 잘 동작한다.
몬스터가 제외되면 리스트 길이도 줄어드어 2,3번째 반복에서 참조할때는
len(monster_list)의 값도 자연스럽게 같이 줄어서 좋다.
무엇보다 함수가 실행될때 몬스터 리스트가 선언되니까
2차, 3차의 다음 전투에서도 문제없이 다시 몬스터 그룹을 만들어 줄수 있었다.
(반면, 그렇지 않았다면 다른 방법을 썼어야 했을 것이다.)
<딕셔너리에 함수 넣기>
def action1():
print("action1")
def action2():
print("action2")
actions = {
"1": action1,
"2": action2
}
user_input = input()
actions[user_input]()
개인과제 해설 강의를 듣고 배운 부분이다.
예비군에 다녀오느라 실시간은 못 듣고 녹화본으로 들었다.
엄청난 기능을 알게 되었는데,
딕셔너리 안에 함수를 넣을 수 있다!!
이걸 잘 활용하면 조건문을 대체할 수 있고 코드를 많이 간결하게 만들수 있다고 하셨다.
데이터 타입도 function이고, 불러와서 (인자)붙이고 사용하면 된다.
데이터 타입에 function이 있다는 사실이 놀라웠다.
<딕셔너리에 클래스 함수 넣기>
클래스 인스턴스의 함수를 딕셔너리로 작성하는건 조금 유의점이 있었다.
팀과제를 하면서 두번정도 활용을 해봤다.
characters = {
"1": Character("냥검사", 1, 160, 40, 30, 25, 20, "냥냥펀치", 30),
"2": Character("냥법사", 1, 140, 50, 20, 30, 25, "하악질", 40),
"3": Character("냥궁수", 1, 120, 40, 25, 20, 30, "털뱉기", 30),
"4": Character("냥힐러", 1, 200, 60, 20, 25, 20, "그루밍", 50)
}
character_skills = {
"냥냥펀치": characters["1"].dealing_Skill,
"하악질": characters["2"].debuff_Skill,
"털뱉기": characters["3"].shooting_Skill,
"그루밍": characters["4"].healing_Skill
}
첫번째는, 캐릭터들 스킬함수 딕셔너리였다.
위에 보이다시피, 우리는 4가지의 주인공 캐릭터들을 만들었다.
그리고 게임을 시작하며 넷중 셋을 고른다. (고르는 순서도 플레이어 맘대로이다.)
Object라는 기본 클래스가 있고,
Character 클래스는 Object를 부모로 삼는 클래스다.
그리고 Character 클래스 아래에 스킬 함수가 위처럼 각각 선언되어있다.
그래서 클래스 함수(메소드)의 이름이 캐릭터마다 다른데
어떻게 하면 스킬을 사용하는 주인공의 스킬함수를 가져다가 쓸수 있을까 고민해봤다.
그때 떠오른게 강의에서 배운 딕셔너리에 함수 넣기였다.
스킬이름으로 어떤 주인공인지 특정할수 있으니,
스킬명:스킬함수로 구성된 딕셔너리를 만들어야 겠다고 생각했다.
위처럼 character_skills라는 딕셔너리를 만들었다.
skill_find = character_skills[players[i].skill_name]
skill_find(target_monster)
실제 전투에서 스킬사용하는 부분이다.
players[i]는 현재 턴을 잡은 주인공인데, .skill_name으로 그의 스킬이름을 가져온다.
가져온 스킬이름으로 스킬 딕셔너리(character_skills)에서 스킬함수를 찾아내고 skill_find에 담는다.
그리고 두번째 줄에서 실행하여 잘 실행된다.
이렇게 해서 스킬 함수를 잘 구현할수 있었다.
equipment1 = Equipment_Item("날카로운 발톱", "공격력을 10만큼 올려줍니다.", 10)
equipment2 = Equipment_Item("방울", "공격력을 10만큼 올려줍니다.", 10)
equipment3 = Equipment_Item("새총", "공격력을 10만큼 올려줍니다.", 10)
equipment4 = Equipment_Item("장난감 막대", "공격력을 10만큼 올려줍니다.", 10)
browse_equipment = {
"냥검사": equipment1.equip,
"냥법사": equipment2.equip,
"냥궁수": equipment3.equip,
"냥힐러": equipment4.equip
}
두번째도, 조금 비슷한 경우인데 캐릭터들 장비 장착 함수이다.
역시나 캐릭터 파티는 4명중 3명이다.
우리는 그 조합을 예측할 수 없기 때문에,
장비 샵에 갔을때 어떤 3명이 장비를 구매할 대상이 되는지,
그리고 그 누구가 character_list[0]이고, [1]이고, [2]인지 하는 순서도 예측할수 없다.
그래서 위처럼 browse_equipment라는 딕셔너리를 만들었다.
조금 다른 부분은, Equipment라는 클래스의 클래스 함수는 equip으로 한가지다.
대신 각 장비를 담은 인스턴스가 equipment1,2,3,4로 다르다.
이 장비들은 사실 캐릭터마다의 전용장비로 대상 주인공이 정해져있다.
그래서 해당 인스턴스의 equip함수를 발동하는 함수 목록을 만든 것이다.
browse_equipment[character_list[0].name](character_list[0])
실제 장비샵에서 장비를 장착하는 부분이다.
character_list[0]의 이름을 참고하여 함수를 가져왔고,
그 함수에는 캐릭터 인스턴스를 인자로 실어보내서,
함수에서 캐릭터한테 장착 처리를 해줄 수 있게 한다.
이렇게 해서 아이템 장착 함수를 잘 구현할수 있었다.
결론, 두가지 부분을 적용해보면서 부딫혔던 시행착오가 있다.
클래스 함수를 딕셔너리에 담으려면,
인스턴스명.함수명 으로 담아야 한다는 것이다.
처음에는 클래스명.함수명으로 작성했었는데 이렇게 하면 에러가 난다.
생성된 인스턴스의 클래스 함수여야지 정상적으로 활용된다.
(지금 생각해보면, 인스턴스를 특정할수 없다는 것도 문제다.)
argument가 없다고 에러가 나오지만 분명 argument는 주고 있다.
없는게 아니라 제대로 인식하지 못하는 문제로 보인다.
인스턴스.함수명으로 바꿔주니 바로 잘 동작했다.
앞으로 클래스 함수를 담는 딕셔너리를 쓸때는 이부분을 주의해야 겠다.