15. C# 문법 종합반 3주차(2)

이규성·2023년 11월 14일
0

TIL

목록 보기
20/106

11/14 튜터님의 강의를 보며 코드를 수정해 보자.

📌코드 수정

수정에 필요한 것들은 아래와 같다. 작성한 코드를 하나하나 수정하여 보자.

  • 클래스 적절한 사용
  • 메서드의 활용
  • 삼항연산자의 활용

아이템 클래스 수정

기존 코드

private static ItemInfo item1;
private static ItemInfo item2;

static void GameDataSetting()
{
    // 캐릭터 정보 세팅
    player = new Character("Chad", "전사", 1, 10, 5, 100, 1500);

    // 아이템 정보 세팅
    item1 = new ItemInfo("무쇠 갑옷", "무쇠로 만들어진 튼튼한 갑옷입니다.", 0, 10, 0);
    item2 = new ItemInfo("낡은 검", "쉽게 볼 수 있는 낡은 검입니다.", 2, 0, 0);
}        

public class ItemInfo
{
    public string ItemName { get; set; }
    public string ItemDescription { get; }
    public int ItemAtk { get; set; }
    public int ItemDef { get; set; }
    public int ItemHp { get; set; }        

    public ItemInfo(string itemname, string itemdes, int itematk, int itemdef, int itemhp)
    {
        ItemName = itemname;
        ItemDescription = itemdes;
        ItemAtk = itematk;
        ItemDef = itemdef;
        ItemHp = itemhp;            
    }
}

기존 코드의 문제점은 아이템을 추가할 때마다 item1, item2 . . . 로 선언을 해줘야 한다는 아주 비생산적이라는 점이다. 배열을 쓰고 싶었으나 개념이해도가 부족해서인지 모조리 실패를 해서 어쩔 수 없이 수동 코드를 작성했었다.
그리고 클래스의 강력한 기능을 반쪽만 이용하고 있었다.

수정 코드

private static ItemInfo[] items; // 클래스를 가지고 와서 배열하는 방법이 있었다. . .
                                 // 가려웠던 부분을 긁어주는 코드다
static void GameDataSetting() // 배열을 사용하여 아이템 정보를 관리
{    
    items = new ItemInfo[10];
    AddItem(new ItemInfo("무쇠 갑옷", "무쇠로 만든 갑옷", 0, 0, 5, 0));
    AddItem(new ItemInfo("낡은 검", "대장간 구석에 있던 검", 1, 2, 0, 0));
    AddItem(new ItemInfo("생명의 돌", "왠지 들고 있으면 튼튼해지는 기분이 드는 돌", 2, 0, 0, 8));
}

static void AddItem(ItemInfo Item) // 배열에 아이템을 추가
{
    if (ItemInfo.ItemCnt == 10)
    {
        return;                
    }
    items[ItemInfo.ItemCnt] = Item;
    ItemInfo.ItemCnt++;
}

public class ItemInfo
{
    public string ItemName { get; set; }
    public string ItemDescription { get; }
    public int Type { get; } // 아이템별로 타입을 지정
    public int ItemAtk { get; set; }
    public int ItemDef { get; set; }
    public int ItemHp { get; set; }

    public static int ItemCnt = 0; // 아이템 정보를 배열화 시키기 위한 숫자 카운트

    public bool IsEquiped {  get; set; } // 아이템의 장착 여부를 판단하기 위한 bool

    public ItemInfo(string itemname, string itemdes, int type, int itematk, int itemdef, 
    int itemhp, bool isEquiped = false)
    {
        ItemName = itemname;
        ItemDescription = itemdes;
        Type = type;
        ItemAtk = itematk;
        ItemDef = itemdef;
        ItemHp = itemhp;
        IsEquiped = isEquiped;
    }

    public void PrintItemDes(bool withNumber = false, int idx = 0)
    {
        Console.Write("- ");

        if (withNumber) // 장비 장착 화면에서 아이템 앞에 번호 붙이기
        {
            Console.Write("{0} ", idx);
        }

        if (IsEquiped) // 아이템이 장착 여부를 판단하여 [E] 붙이고 떼기
        {
            Console.Write("[E]");
            Console.Write(PadRightForMixedText(ItemName, 9)); // 아이템 이름 줄맞춤
        }
        else
        {
            Console.Write(PadRightForMixedText(ItemName, 12));
        }

        Console.Write(" | ");

        if (ItemAtk != 0) // 아이템의 스탯을 출력하기 위해 0이면 출력x
        {
            Console.Write($"Atk {(ItemAtk >= 0 ? "+" : "")}{ItemAtk} ");
        }

        if (ItemDef != 0)
        {
            Console.Write($"Def {(ItemDef >= 0 ? "+" : "")}{ItemDef} ");
        }

        if (ItemHp != 0)
        {
            Console.Write($"Hp  {(ItemHp >= 0 ? "+" : "")}{ItemHp} ");
        }

        Console.Write(" | ");

        Console.WriteLine(ItemDescription);
    }
    
    // 아이템 이름의 줄맞춤을 위한 메서드
    public static int GetPrintableLength(string str)
	{
    	int length = 0;
    	foreach (char c in str)
    	{
        	if (char.GetUnicodeCategory(c) == System.Globalization.UnicodeCategory.OtherLetter)
        	{
            	length += 2; // 한글과 같은 넓은 문자에 대해 길이를 2로 취급
        	}
        	else
        	{
            	length += 1; // 나머지 문자에 대해 길이를 1로 취급
        	}
    	}
    	return length;
	}
    
	public static string PadRightForMixedText(string str, int totalLength)
	{
    	int currentLength = GetPrintableLength(str);
    	int padding = totalLength - currentLength;
    	return str.PadRight(str.Length + padding);
    }    
}

아이템에 의해 변하는 변수들의 정보를 클래스 내부에 넣어놓고 적절하게 호출하여 사용하는 것이 편의성도 생산성도 좋다고 느꼈다.

캐릭터 상태창 수정

기존 코드

static void DisplayMyInfo()
{
    Console.Clear();

    Console.WriteLine("상태보기");
    Console.WriteLine("캐릭터의 정보를 표시합니다.");
    Console.WriteLine();
    Console.WriteLine($"Lv.{player.Level}");
    Console.WriteLine($"{player.Name}({player.Job})");
    Console.WriteLine($"공격력 : {player.Atk}");
    Console.WriteLine($"방어력 : {player.Def}");
    Console.WriteLine($"체력 : {player.Hp}");
    Console.WriteLine($"Gold : {player.Gold} G");
    Console.WriteLine();
    Console.WriteLine("0. 나가기");

    if (item1.ItemName == "[E] 무쇠 갑옷" && item2.ItemName != "[E] 낡은 검")
    {
        Console.Clear();

        Console.WriteLine("상태보기");
        Console.WriteLine("캐릭터의 정보를 표시합니다.");
        Console.WriteLine();
        Console.WriteLine($"Lv.{player.Level}");
        Console.WriteLine($"{player.Name}({player.Job})");
        Console.WriteLine($"공격력 : {player.Atk}");
        Console.WriteLine($"방어력 : {player.Def} +({item1.ItemDef + item2.ItemDef})");
        Console.WriteLine($"체력 : {player.Hp}");
        Console.WriteLine($"Gold : {player.Gold} G");
        Console.WriteLine();
        Console.WriteLine("0. 나가기");
    }
    else if (item2.ItemName == "[E] 낡은 검" && item1.ItemName != "[E] 무쇠 갑옷")
    {
        Console.Clear();

        Console.WriteLine("상태보기");
        Console.WriteLine("캐릭터의 정보를 표시합니다.");
        Console.WriteLine();
        Console.WriteLine($"Lv.{player.Level}");
        Console.WriteLine($"{player.Name}({player.Job})");
        Console.WriteLine($"공격력 : {player.Atk} +({item1.ItemAtk + item2.ItemAtk})");
        Console.WriteLine($"방어력 : {player.Def}");
        Console.WriteLine($"체력 : {player.Hp}");
        Console.WriteLine($"Gold : {player.Gold} G");
        Console.WriteLine();
        Console.WriteLine("0. 나가기");
    }
    else if (item1.ItemName == "[E] 무쇠 갑옷" && item2.ItemName == "[E] 낡은 검")
    {
        Console.Clear();

        Console.WriteLine("상태보기");
        Console.WriteLine("캐릭터의 정보를 표시합니다.");
        Console.WriteLine();
        Console.WriteLine($"Lv.{player.Level}");
        Console.WriteLine($"{player.Name}({player.Job})");
        Console.WriteLine($"공격력 : {player.Atk} +({item1.ItemAtk + item2.ItemAtk})");
        Console.WriteLine($"방어력 : {player.Def} +({item1.ItemDef + item2.ItemDef})");
        Console.WriteLine($"체력 : {player.Hp}");
        Console.WriteLine($"Gold : {player.Gold} G");
        Console.WriteLine();
        Console.WriteLine("0. 나가기");
    }
    int input = CheckValidInput(0, 0);

    switch (input)
    {
        case 0:
            DisplayGameIntro();
            break;
    }
}

지금 봐도 아주 헛웃음이 나오는 if문의 남발이다. . . 당장 고쳐버리자 !

수정 코드

static void DisplayMyInfo()
{
    Console.Clear();

    Console.WriteLine("상태보기");
    Console.WriteLine("캐릭터의 정보를 표시합니다.");
    Console.WriteLine();
    Console.WriteLine("Lv. " + player.Level.ToString("00")); // 레벨을 두 자리수로 표현하기 위해
    Console.WriteLine($"{player.Name}({player.Job})");

	// 캐릭터의 상태에 어떻게 장비의 정보를 전달할 수 있는 삼항연산자 
    int bonusAtk = getSumBonusAtk();
    Console.Write("공격력 : " + (player.Atk + bonusAtk).ToString());
    Console.WriteLine(bonusAtk > 0 ? string.Format(" (+{0})", bonusAtk) : "");

    int bonusDef = getSumBonusDef();
    Console.Write("방어력 : " + (player.Def + bonusDef).ToString());
    Console.WriteLine(bonusDef > 0 ? string.Format(" (+{0})", bonusDef) : "");

    int bonusHp = getSumBonusHp();
    Console.Write("Hp : " + (player.Hp + bonusHp).ToString());
    Console.WriteLine(bonusHp > 0 ? string.Format(" (+{0})", bonusHp) : "");

    Console.WriteLine($"Gold : {player.Gold} G");
    Console.WriteLine();
    Console.WriteLine("0. 나가기");
   
    switch (input)
    {
        case 0:
            DisplayGameIntro();
            break;
    }
}

private static int getSumBonusAtk()
{
    int sum = 0;
    for (int i = 0; i < ItemInfo.ItemCnt; i++)
    {
        if (items[i].IsEquiped)
        {
            sum += items[i].ItemAtk;
        }
    }
    return sum;
}

private static int getSumBonusDef()
{
    int sum = 0;
    for (int i = 0; i < ItemInfo.ItemCnt; i++)
    {
        if (items[i].IsEquiped)
        {
            sum += items[i].ItemDef;
        }                    
    }
    return sum;
}

private static int getSumBonusHp()
{
    int sum = 0;
    for (int i = 0; i < ItemInfo.ItemCnt; i++)
    {
        if (items[i].IsEquiped)
        {
            sum += items[i].ItemHp;
        }
    }
    return sum;
}

크게 달라진 점은 메서드와 삼항연산자를 활용했다는 점이다. 처음에 코드를 작성할 땐 메서드와 bool문을 활용하면 어떻게 될 것 같은데 하면서 다양하게 시도했지만 모조리 실패를 했고, , , 이렇게 메서드와 삼항연산자를 활용하여 해결하니 속이 다 후련하다.

인벤토리 코드 수정

기존 코드

static void DisplayInventory()
{
    Console.Clear();

    Console.WriteLine("인벤토리");
    Console.WriteLine("보유 중인 아이템을 관리할 수 있습니다.");
    Console.WriteLine();
    Console.WriteLine("[아이템 목록]");
    Console.WriteLine($"- {item1.ItemName}    " + $" | 방어력 +{item1.ItemDef} | {item1.ItemDescription}");
    Console.WriteLine($"- {item2.ItemName}    " + $" | 공격력 +{item2.ItemAtk} | {item2.ItemDescription}");
    Console.WriteLine();
    Console.WriteLine("1. 장착 관리");
    Console.WriteLine("0. 나가기");
    Console.WriteLine();
    Console.WriteLine("원하시는 행동을 입력해주세요");

    int input = CheckValidInput(0, 1);
    switch (input)
    {
        case 0:                    
            DisplayGameIntro();
            break;
        case 1:
            EquipItemManagement();
            break;
    }
}

수정 코드

static void DisplayInventory()
{
    Console.Clear();

    Console.WriteLine("인벤토리");
    Console.WriteLine("보유 중인 아이템을 관리할 수 있습니다.");
    Console.WriteLine();
    Console.WriteLine("[아이템 목록]");
    //Console.WriteLine($"- {item1.ItemName}    " + $" | 방어력 +{item1.ItemDef} | {item1.ItemDescription}");
    //Console.WriteLine($"- {item2.ItemName}    " + $" | 공격력 +{item2.ItemAtk} | {item2.ItemDescription}");
    for (int i = 0; i < ItemInfo.ItemCnt; i++) // 아이템 목록을 반복문을 이용해서 자동으로 !
    {
        items[i].PrintItemDes();
    }            
    Console.WriteLine();
    Console.WriteLine("1. 장착 관리");
    Console.WriteLine("0. 나가기");
    Console.WriteLine();
    Console.WriteLine("원하시는 행동을 입력해주세요");

    int input = CheckValidInput(0, 1);
    switch (input)
    {
        case 0:
            DisplayGameIntro();
            break;
        case 1:
            EquipItemManagement();
            break;
    }
}

장비 장착화면 수정

기존 코드

static void EquipItemManagement()
{            
    Console.Clear();

    Console.WriteLine("인벤토리 - 장착 관리");
    Console.WriteLine("아이템을 장착하거나 해제합니다");
    Console.WriteLine();
    Console.WriteLine("[아이템 목록]");
    Console.WriteLine($"- 1 {item1.ItemName}    " + $" | 방어력 +{item1.ItemDef} | {item1.ItemDescription}");
    Console.WriteLine($"- 2 {item2.ItemName}    " + $" | 공격력 +{item2.ItemAtk} | {item2.ItemDescription}");
    Console.WriteLine();
    Console.WriteLine("0. 나가기");
    Console.WriteLine();
    Console.WriteLine("장착할 아이템 번호를 입력해주세요.");
    Console.WriteLine("이미 장착하고 있을 경우 해제합니다.");

    int input = CheckValidInput(0, 2);
    switch (input)
    {                
        case 0:
            DisplayInventory();
            break;
        case 1:
            // 1번 아이템 선택하면 캐릭터 인포에 능력치를 플러스해주고 아이템 이름 앞에 [E]를 붙였다가 떼기                   
            if (item1.ItemName == "무쇠 갑옷")
            {
                item1.ItemName = "[E] 무쇠 갑옷";
                
                player.Atk += item1.ItemAtk;
                player.Def += item1.ItemDef;
                player.Hp += item1.ItemHp;                       
            }
            else
            {
                item1.ItemName = "무쇠 갑옷";

                player.Atk -= item1.ItemAtk;
                player.Def -= item1.ItemDef;
                player.Hp -= item1.ItemHp;
            }                    
            EquipItemManagement();
            break;
        case 2:
            if (item2.ItemName == "낡은 검")
            {
                item2.ItemName = "[E] 낡은 검";

                player.Atk += item2.ItemAtk;
                player.Def += item2.ItemDef;
                player.Hp += item2.ItemHp;
            }
            else
            {
                item2.ItemName = "낡은 검";

                player.Atk -= item2.ItemAtk;
                player.Def -= item2.ItemDef;
                player.Hp -= item2.ItemHp;
            }
            EquipItemManagement();
            break;
    }
}

수정 코드

static void EquipItemManagement()
{
    Console.Clear();

    Console.WriteLine("인벤토리 - 장착 관리");
    Console.WriteLine("아이템을 장착하거나 해제합니다");
    Console.WriteLine();
    Console.WriteLine("[아이템 목록]");
    
    for (int i = 0; i < ItemInfo.ItemCnt; i++)
    {
        items[i].PrintItemDes(true, i + 1);
    }
    Console.WriteLine();
    Console.WriteLine("0. 나가기");
    Console.WriteLine();
    Console.WriteLine("장착할 아이템 번호를 입력해주세요.");
    Console.WriteLine("이미 장착하고 있을 경우 해제합니다.");

    int input = CheckValidInput(0, ItemInfo.ItemCnt);

    switch (input)
    {
        case 0:
            DisplayInventory();
            break;
        default:
            ToggleEquipStatus(input - 1); // items[]가 배열이라 0부터 시작하기 때문
            EquipItemManagement();
            break;
    }
}

// case로 입력값을 받아서 [E]를 탈부착 시켜주는 코드
// 아이템 클래스의 bool 문을 호출하여 사용한다.
static void ToggleEquipStatus(int idx)
{
    items[idx].IsEquiped = !items[idx].IsEquiped;
}

if문을 정말 알차게도 썼다. . . [E]의 탈부착을 bool을 이용하고 싶었는데 실패했었다. 해설 코드를 보면서 직접 사용을 해보니 머리가 트이는 기분이다.

GitHub URL: https://github.com/ssungyeee/Personal-Assignment.git

🤸🏻‍♀️Feedback

우선 계속 혼자 시도했다가 실패했던 기능들을 시원하게 구현할 수 있어서 너무 속이 후련하다. 기본적인 기능들의 개념 이해도가 얼마나 부족한지 깨달을 수 있는 시간이었고, 코드 작성의 흐름을 수박겉핥기 마냥 배울 수 있는 과제였다.

0개의 댓글