과제/개인과제

[Python] 플레이어와 몬스터를 생성하여 1대 1으로 싸우는 게임 (수정)

마이구미+ 2023. 3. 27. 16:20

<요구사항>

  • 이름을 입력해 플레이어를 생성할 수 있어야 한다.
  • 몬스터는 임의 생성할 수 있어야 한다.
  • while 반복문을 사용해 종료 조건을 충족할 때까지 턴제 플레이어와 몬스터간 전투를 반복 진행해야 한다.
  • 플레이어는 공격 타입을 선택할 수 있어야 한다. ex) 일반공격, 마법공격
  • 몬스터는 일반 공격을 할 수 있어야 한다.
  • 매 전투시 플레이어와 몬스터의 상태 정보를 출력해야 한다.
  • 모든 공격은 캐릭터의 파워 기준으로 랜덤성을 가지고 있어야 한다. ex) 파워가 10인 경우 일반공격은 8~12 사이의 랜덤한 값으로 공격
  • 몬스터나 플레이어의 HP가 0이 되면 전투를 종료하고 승리 또는 패배를 출력해야 한다.

<내가 처음 작성한 코드>

**가로 스크롤은 shift + 마우스스크롤**

import random


class Character:
    # 모든 캐릭터의 모체가 되는 클래스
    def __init__(self, name, hp, power, mp, m_power):
        self.name = name
        self.max_hp = hp
        self.hp = hp
        self.power = power
        self.max_mp = mp
        self.mp = mp
        self.m_power = m_power

    # 일반공격 함수
    def attack(self, other):
        damage = random.randint(self.power - 2, self.power + 2)
        other.hp = max(other.hp - damage, 0)
        print(f"{self.name}의 공격! {other.name}에게 {damage}의 데미지를 입혔습니다.")
        if other.hp == 0:
            print(f"{other.name}님이 쓰러졌습니다. {self.name}님이 전투에서 승리하였습니다!")
            print("전투가 종료되었습니다.")
            quit()

    # 마법공격 함수
    def m_attack(self, other):
        damage = random.randint(self.m_power - 2, self.m_power + 2)
        use_mp = 0
        if self.mp >= damage * 0.8:
            use_mp = damage * 0.8
        else:
            print("마력이 부족합니다. 일반공격을 실시합니다.")
            self.attack(other)
            return
        monster.hp = max(monster.hp - damage, 0)
        self.mp = int(max(self.mp - use_mp, 0))
        if self.mp == 0:
            print("마력을 모두 사용하였습니다. 다음에는 마법공격이 불가능합니다.")
        print(f"{self.name}의 마법공격! {other.name}에게 {damage}의 데미지를 입혔습니다.")
        if other.hp == 0:
            print(f"{other.name}님이 쓰러졌습니다. {self.name}님이 전투에서 승리하였습니다!")
            print("전투가 종료되었습니다.")
            quit()

    # 캐릭터의 상태 표시 함수
    def show_status(self):
        print(
            f"{self.name}의 상태\nHP {self.hp}/{self.max_hp}\nMP {self.mp}/{self.max_mp}")

    # 전투 진행 함수
    def battle(self, other):
        while True:
            if self == player:
                while True:
                    attack_type = str(
                        input("공격 유형을 선택하십시오(숫자 입력). 1: 일반공격, 2: 마법공격 (전투를 끝내고 싶다면 0을 누르세요)\n"))
                    if attack_type == "1":
                        player.attack(monster)
                        monster.attack(player)
                        self.show_status()
                        other.show_status()
                        print("\n")
                    elif attack_type == "2":
                        player.m_attack(monster)
                        monster.attack(player)
                        self.show_status()
                        other.show_status()
                        print("\n")
                    elif attack_type == "0":
                        return print("전투가 종료되었습니다.")
                    else:
                        continue
            elif self == monster:
                monster.attack(player)
                while True:
                    attack_type = str(
                        input("공격 유형을 선택하십시오(숫자 입력). 1: 일반공격, 2: 마법공격 (전투를 끝내고 싶다면 0을 누르세요)\n"))
                    if attack_type == "1":
                        player.attack(monster)
                        self.show_status()
                        other.show_status()
                        print("\n")
                        break
                    elif attack_type == "2":
                        player.m_attack(monster)
                        self.show_status()
                        other.show_status()
                        print("\n")
                        break
                    elif attack_type == "0":
                        return print("전투가 종료되었습니다.")
                    else:
                        continue


# 플레이어 생성
player_name = input("캐릭터의 이름을 지어주세요: ")
player_hp = random.randint(100, 120)
player_mp = random.randint(50, 80)
player_power = random.randint(10, 20)
player_m_power = random.randint(15, 30)
player = Character(player_name, player_hp, player_power,
                   player_mp, player_m_power)
player.show_status()

# 몬스터 생성
monster_name = player_name + "킬러"
monster_hp = random.randint(100, 120)
monster_power = random.randint(10, 20)
monster = Character(monster_name, monster_hp, monster_power, 0, 0)
monster.show_status()


# 선공을 위한 가위바위보 게임 함수
def rps():
    rps = input("\n선공을 잡기 위한 가위바위보 게임을 시작합니다. 가위/바위/보 중 하나를 입력하시오: ")
    monster_rps = random.choice(["가위", "바위", "보"])
    while True:
        if rps == "가위" and monster_rps == "보":
            print(f"{player_name}: {rps}, {monster_name}: {monster_rps}")
            print(f"{player_name}님이 이겼습니다. 공격을 시작하세요\n")
            player.battle(monster)
            break
        elif rps == "가위" and monster_rps == "바위":
            print(f"{player_name}: {rps}, {monster_name}: {monster_rps}")
            print(f"{monster_name}가 이겼습니다. 공격이 시작됩니다\n")
            monster.battle(player)
            break
        elif rps == "바위" and monster_rps == "가위":
            print(f"{player_name}: {rps}, {monster_name}: {monster_rps}")
            print(f"{player_name}님이 이겼습니다. 공격을 시작하세요\n")
            player.battle(monster)
            break
        elif rps == "바위" and monster_rps == "보":
            print(f"{player_name}: {rps}, {monster_name}: {monster_rps}")
            print(f"{monster_name}가 이겼습니다. 공격이 시작됩니다\n")
            monster.battle(player)
            break
        elif rps == "보" and monster_rps == "바위":
            print(f"{player_name}: {rps}, {monster_name}: {monster_rps}")
            print(f"{player_name}님이 이겼습니다. 공격을 시작하세요\n")
            player.battle(monster)
            break
        elif rps == "보" and monster_rps == "가위":
            print(f"{player_name}: {rps}, {monster_name}: {monster_rps}")
            print(f"{monster_name}가 이겼습니다. 공격이 시작됩니다\n")
            monster.battle(player)
            break
        elif rps == monster_rps:
            print(f"{player_name}: {rps}, {monster_name}: {monster_rps}")
            rps = input("\n비겼습니다. 다시 입력해주십시오(가위/바위/보): ")
            monster_rps = random.choice(["가위", "바위", "보"])
            continue
        else:
            rps = input("\n잘못 눌렀습니다. 다시 선택해주세요.(가위/바위/보): ")
            monster_rps = random.choice(["가위", "바위", "보"])
            continue


rps()

<수정한 코드>

  • 오늘 보충 강의를 들어보니 몬스터 클래스도 따로 지정해주어야 하는 것 같아서 몬스터 클래스를 추가했다
  • 원래 그냥 캐릭터 클래스를 이용했던 이유는 마력 말고는 캐릭터와 다른 게 없어서 몬스터 클래스를 추가하는 건 쓸데없이 코드만 길어지는 거 아닌가 싶어서였다 그래서 몬스터 상태에 마력이 없어서 그냥 고정값으로 0으로 출력되게끔 했는데....
  • 내가 몬스터 성질에 무언가를 더 추가했다면 몬스터 클래스가 더 의미있긴 할 것 같다 예시로 불 속성, 물 속성 뭐 이런 걸 추가하던데 그거까지 하면 흥미가 떨어질 것 같아서 하지 않기로 했다 사실 게임에는 흥미가 없다보니....그런 속성 그런 걸 잘 모르기도 하고....
  • 그리고 몬스터 이름을 플레이어가 지은 이름 뒤에 "킬러"(ㅋㅋㅋ)를 붙여서 생성되게끔 했는데 킬러라는 단어가 좀 무섭기도 하고 플레이어로 하여금 기분 나쁠 수도 있을 거 같아서 흔히 몬스터에 붙을 법한 이름 세 가지 중 하나가 랜덤으로 출력되게끔 수정했다
  • 마지막으로 가위바위보 함수 코드를 축약했다 몬스터 클래스를 추가하고 나니 코드가 길어져서 뭔가 맘에 들지 않아서 '뭘 줄일 수 있을까?', '어디가 낭비되고 있을까?'하고 찾아봤다 가위바위보 함수는 처음부터...아 이거 반복이 너무 심한데...라는 생각을 하긴 했지만 코드 완성시키는 것이 목표여서 일단 생각을 접어두고 코드를 완성 했었다가 오늘 다른 곳 수정하는 김에 수정했다
  • 원래는 플레이어가 낸 거랑 몬스터가 낸 걸 하나씩 비교했는데 조건문에 or을 써서 플레이어가 이기는 경우 3가지를 모두 합치고 마찬가지로 몬스터가 이기는 경우를 모두 합쳤다
import random
import time


class Character:
    # 캐릭터의 모체가 되는 클래스
    def __init__(self, name, hp, power, mp, m_power):
        self.name = name
        self.max_hp = hp
        self.hp = hp
        self.power = power
        self.max_mp = mp
        self.mp = mp
        self.m_power = m_power

    # 일반공격 함수
    def attack(self, other):
        damage = random.randint(self.power - 2, self.power + 2)
        other.hp = max(other.hp - damage, 0)
        print(f"{self.name}의 공격! {other.name}에게 {damage}의 데미지를 입혔습니다.")
        if other.hp == 0:
            print(f"{other.name}님이 쓰러졌습니다. {self.name}님이 전투에서 승리하였습니다!")
            print("전투가 종료되었습니다.")
            quit()

    # 마법공격 함수
    def m_attack(self, other):
        damage = random.randint(self.m_power - 2, self.m_power + 2)
        use_mp = 0
        if self.mp >= damage * 0.8:
            use_mp = damage * 0.8
        else:
            print("마력이 부족합니다. 일반공격을 실시합니다.")
            self.attack(other)
            return
        monster.hp = max(monster.hp - damage, 0)
        self.mp = int(max(self.mp - use_mp, 0))
        if self.mp == 0:
            print("마력을 모두 사용하였습니다. 다음에는 마법공격이 불가능합니다.")
        print(f"{self.name}의 마법공격! {other.name}에게 {damage}의 데미지를 입혔습니다.")
        if other.hp == 0:
            print(f"{other.name}님이 쓰러졌습니다. {self.name}님이 전투에서 승리하였습니다!")
            print("전투가 종료되었습니다.")
            quit()

    # 캐릭터의 상태 표시 함수
    def show_status(self):
        print(
            f"{self.name}의 상태\nHP {self.hp}/{self.max_hp}\nMP {self.mp}/{self.max_mp}")


class Monster:
    # 몬스터의 모체가 되는 클래스
    def __init__(self, name, hp, power):
        self.name = name
        self.hp = hp
        self.max_hp = hp
        self.power = power

    # 일반공격 함수
    def attack(self, other):
        damage = random.randint(self.power - 2, self.power + 2)
        other.hp = max(other.hp - damage, 0)
        print(f"{self.name}의 공격! {other.name}에게 {damage}의 데미지를 입혔습니다.")
        if other.hp == 0:
            print(f"{other.name}님이 쓰러졌습니다. {self.name}님이 전투에서 승리하였습니다!")
            print("전투가 종료되었습니다.")
            quit()

    # 몬스터의 상태 표시 함수
    def show_status(self):
        print(
            f"{self.name}의 상태\nHP {self.hp}/{self.max_hp}")

# 전투 진행 함수
def battle(self, other):
    while True:
        if self == player:
            while True:
                attack_type = str(
                    input("공격 유형을 선택하십시오(숫자 입력). 1: 일반공격, 2: 마법공격 (전투를 끝내고 싶다면 0을 누르세요)\n"))
                if attack_type == "1":
                    player.attack(monster)
                    monster.attack(player)
                    self.show_status()
                    other.show_status()
                    time.sleep(1)
                    print("\n")
                elif attack_type == "2":
                    player.m_attack(monster)
                    monster.attack(player)
                    self.show_status()
                    other.show_status()
                    time.sleep(1)
                    print("\n")
                elif attack_type == "0":
                    return print("전투가 종료되었습니다.")
                else:
                    continue
        elif self == monster:
            monster.attack(player)
            while True:
                attack_type = str(
                    input("당신 차례입니다. 공격 유형을 선택하십시오(숫자 입력). 1: 일반공격, 2: 마법공격 (전투를 끝내고 싶다면 0을 누르세요)\n"))
                if attack_type == "1":
                    player.attack(monster)
                    self.show_status()
                    other.show_status()
                    time.sleep(1)
                    print("\n")
                    break
                elif attack_type == "2":
                    player.m_attack(monster)
                    self.show_status()
                    other.show_status()
                    time.sleep(1)
                    print("\n")
                    break
                elif attack_type == "0":
                    return print("전투가 종료되었습니다.")
                else:
                    continue

# 선공을 위한 가위바위보 게임 함수
def rps():
    rps = input("\n선공을 잡기 위한 가위바위보 게임을 시작합니다. 가위/바위/보 중 하나를 입력하시오: ")
    monster_rps = random.choice(["가위", "바위", "보"])
    while True:
        if (rps == "가위" and monster_rps == "보") or (rps == "바위" and monster_rps == "가위") or (rps == "보" and monster_rps == "바위"):
            print(f"{player_name}: {rps}, {monster_name}: {monster_rps}")
            print(f"{player_name}님이 이겼습니다. 공격을 시작하세요\n")
            battle(player, monster)
            break
        elif (rps == "가위" and monster_rps == "바위") or (rps == "바위" and monster_rps == "보") or (rps == "보" and monster_rps == "가위"):
            print(f"{player_name}: {rps}, {monster_name}: {monster_rps}")
            print(f"{monster_name}가 이겼습니다. 공격이 시작됩니다\n")
            time.sleep(1.5)
            battle(monster, player)
            break
        elif rps == monster_rps:
            print(f"{player_name}: {rps}, {monster_name}: {monster_rps}")
            rps = input("\n비겼습니다. 다시 입력해주십시오(가위/바위/보): ")
            monster_rps = random.choice(["가위", "바위", "보"])
            continue
        else:
            rps = input("\n잘못 눌렀습니다. 다시 선택해주세요.(가위/바위/보): ")
            monster_rps = random.choice(["가위", "바위", "보"])
            continue


# 플레이어 생성
player_name = input("캐릭터의 이름을 지어주세요: ")
player_hp = random.randint(100, 120)
player_mp = random.randint(40, 60)
player_power = random.randint(10, 20)
player_m_power = random.randint(15, 30)
player = Character(player_name, player_hp, player_power,
                   player_mp, player_m_power)
player.show_status()

# 몬스터 생성
monster_name = random.choice(["고블린", "메두사", "트롤"])
monster_hp = random.randint(100, 120)
monster_power = random.randint(10, 20)
monster = Monster(monster_name, monster_hp, monster_power)
monster.show_status()

# 가위바위보 게임으로 시작
rps()