[C#] Practice Test++(Console)

Lingtea_luv·2025년 3월 23일
0

C#

목록 보기
10/37
post-thumbnail

아이템 상점


다음 조건을 만족하는 아이템 상점을 구현하시오.

1. 상점에서는 다음 작업들이 가능하다.
	A. 아이템 구매
	B. 아이템 판매
	C. 아이템 확인
2. 아이템은 기본적으로 이름, 설명, 가격을 가지고 있으며, 
무기는 공격력, 방어구는 방어력, 장신구는 체력을 상승시키는 수치를 가진다.
3. 아이템 구매 메뉴 선택시 상점이 소유하고 있는 아이템들 목록이 제공되고, 
구매하고자 하는 아이템을 선택시 구매를 진행한다. 
	단, 돈이 부족하다면 구매는 진행되지 않는다. 
구매가 완료되면 소유한 아이템에 구매한 아이템이 추가되며, 
아이템에 의해 플레이어 능력이 상승한다.
4. 아이템 판매 메뉴 선택시 플레이어가 소유하고 있는 아이템들 목록이 제공되고, 
판매하고자 하는 아이템을 선택시 판매를 진행한다. 
	단, 소유한 아이템이 없다면 진행되지 않는다. 
판매가 완료되면 소유한 아이템에 판매한 아이템이 제거되며, 
아이템에 의해 플레이어 능력이 하락한다.
5. 아이템 확인 메뉴 선택시 플레이어가 소유하고 있는 아이템들 목록이 제공되고,
아이템들에 의해 상승한 플레이어 최종 능력치를 보여준다. 
플레이어는 최대 6개의 아이템을 소유할 수 있으며 빈칸은 보여주지 않는다.

1. Pseudo Code

struct{} // 아이템 구조체 선언
Start{}  // 아이템 정보
Main
{
	Render{}  // 상점 메인 출력, 구매, 판매, 인벤 창 출력
	Input{}   // 입력값 1,2,3,0 제한. ConsoleKey 활용? ConsoleReadLine?
	Update{}  // 입력값에 따른 창 변경 및 구매, 판매 기능 구현 -> Input이랑 통일?
}    

상점의 경우 게임 종료가 따로 없기 때문에, 키 입력에 따라 창 변경, 출력을 해야하므로 Input과 Update를 하나로 묶어 표현하고 나중에 분리시키는 것으로 pseudo 코드를 작성했다.

2. struct, enum

struct Item
{
    public string name;
    public string detail;
    public int price;
    public int value;
    public ItemEnforce enfo;
}
enum ItemEnforce
{
    공격력, 방어력, 체력
}

문구를 출력할 때 아이템의 정보를 가지고 출력이 가능하도록 구조체로 설정을 해주었다.

3. Start

static void Start()
{
    longSword.name = "롱소드";
    longSword.detail = "기본적인 검이다.";
    longSword.price = 450;
    longSword.value = 15;
    longSword.enfo = ItemEnforce.공격력;

    clothArmor.name = "천갑옷";
    clothArmor.detail = "얇은 갑옷이다.";
    clothArmor.price = 450;
    clothArmor.value = 10;
    clothArmor.enfo = ItemEnforce.방어력;

    tearOfGoddess.name = "여신의 눈물";
    tearOfGoddess.detail = "희미하게 푸른빛을 품고 있는 보석이다.";
    tearOfGoddess.price = 800;
    tearOfGoddess.value = 300;
    tearOfGoddess.enfo = ItemEnforce.체력;
}

4. Main

static void Main(string[] args)
{
    int gold = 10000;
    int attack = 0;
    int defense = 0;
    int health = 0;
    List<Item> inventory = new List<Item>();

    Item longSword = new Item();
    Item clothArmor = new Item();
    Item tearOfGoddess = new Item();

    Start();

    Render();
}

플레이어의 기본 골드와 스탯을 선언하고 인벤토리를 아이템 List로 선언하여 구매한 아이템을 List에 추가하고 판매한 아이템을 List에서 제거하도록 했다.

5. Render

  • MainMenu( )

static void MainMenu()
{
    Console.Clear();
    Console.SetCursorPosition(0, 0);
    Console.WriteLine("************************************");
    Console.WriteLine("*********** 아이템 상점 ************");
    Console.WriteLine("************************************\n\n");
    Console.WriteLine("========== 상점 메뉴 ==========");
    Console.WriteLine("1. 아이템 구매");
    Console.WriteLine("2. 아이템 판매");
    Console.WriteLine("3. 아이템 확인");
    Console.Write("메뉴를 선택하세요 : ");

    MainInput();
}

상점 메인의 interface를 설정하고 MainMenu에서 작동하는 MainInput이 이어지도록 했다.

  • ItemBuyMenu( )

static void ItemBuyMenu()
{
    Console.Clear();
    Console.SetCursorPosition(0, 0);
    Console.WriteLine("========= 아이템 구매 =========");
    Console.WriteLine($"보유한 골드 : {gold}G\n");
    Console.WriteLine($"1. {longSword.name}\n   가격 : {longSword.price}\n   설명 : {longSword.detail}\n   {longSword.enfo} 상승 : {longSword.value}\n");
    Console.WriteLine($"2. {clothArmor.name}\n   가격 : {clothArmor.price}\n   설명 : {clothArmor.detail}\n   {clothArmor.enfo} 상승 : {clothArmor.value}\n");
    Console.WriteLine($"3. {tearOfGoddess.name}\n   가격 : {tearOfGoddess.price}\n   설명 : {tearOfGoddess.detail}\n   {tearOfGoddess.enfo} 상승 : {tearOfGoddess.value}\n");

    BuyMenuInput();
}

구매 탭의 interface를 설정하고 ItemBuyMenu에서 작동하는 MuyMenuInput이 이어지도록 했다. interface 출력의 경우 아이템의 정보에 따라 출력이 되도록 했는데, for 기능을 사용하여 줄일 수 있지 않을까 하는 생각을 했다.

  • ItemSellMenu( )

static void ItemSellMenu()
{
    Console.SetCursorPosition(0, 0);
    Console.Clear();
    Console.WriteLine("========= 아이템 판매 =========");
    Console.WriteLine("");
    if (inventory == null || inventory.Count == 0)
    {
        Console.Write("보유하신 아이템이 없습니다. (돌아가기 0)");
        ConsoleKey key = Console.ReadKey().Key;
        switch (key)
        {
            case ConsoleKey.D0:
                Render();
                break;
            default:
                ItemSellMenu();
                break;
        }
    }
    else
    {
        for (int i = 0; i < inventory.Count; i++)
        {
            Console.WriteLine($"{i + 1}. {inventory[i].name}\n   가격 : {inventory[i].price}\n   설명 : {inventory[i].detail}\n   {inventory[i].enfo} 상승 : {inventory[i].value}\n");
        }
    }
    SellMenuInput();
}

아이템 구매 내역에 따라 출력이 되도록 설정하고, 아이템을 구매하지 않은 경우나, 모두 판매한 경우 아이템이 없다는 문구를 출력하도록 했다.

  • ItemConfigMenu( )

static void ItemConfigMenu()
{
    Console.Clear();
    Console.SetCursorPosition(0, 0);
    Console.WriteLine("========= 아이템 확인 =========");
    Console.WriteLine($"플레이어 골드\t보유량 : {gold}G");
    Console.WriteLine($"플레이어 공격력\t상승량 : {attack}");
    Console.WriteLine($"플레이어 방어력\t상승량 : {defense}");
    Console.WriteLine($"플레이어 체력\t상승량 : {health}");
    Console.WriteLine("===============================\n");

    if (inventory != null)
    {
        for (int i = 0; i < 6; i++)
        {

            if (i < inventory.Count)
            {
                Console.WriteLine($"{i + 1}. {inventory[i].name}\n   가격 : {inventory[i].price}\n   설명 : {inventory[i].detail}\n   {inventory[i].enfo} 상승 : {inventory[i].value}\n");
            }
            else
            {
                break;
            }
        }
        Console.Write("계속하려면 아무키나 입력하세요 : ");
    }
    else
    {
        Console.Write("보유하신 아이템이 없습니다.\n\n계속하려면 아무키나 입력하세요 : ");
    }
    
    ConfigMenuInput();
}

인벤토리와 보유하고 있는 아이템에 따라 증가한 스탯이 출력이 되도록 구현했다. 마찬가지로 보유한 아이템이 없을 경우 따로 안내 문구를 출력이 되도록 했다.

5. Input + Update

  • MainInput

static void MainInput()
{
    string key = Console.ReadLine();

    switch (key)
    {
        case "1":
            ItemBuyMenu();
            break;
        case "2":
            ItemSellMenu(;
            break;
        case "3":
            ItemConfigMenu();
            break;
        case "0":
            Render();
            break;
        default:
            MainMenu();
            break;
    }
}

메인 메뉴에서는 1을 누르면 구매 탭, 2를 누르면 판매 탭, 3을 누르면 플레이어 탭으로 가도록 설정하였다.

  • BuyMenuInput

static void BuyMenuInput()
{
    Console.Write("구매할 아이템을 선택하세요 (취소 0) : ");
    ConsoleKey key = Console.ReadKey().Key;
    Console.WriteLine("\n");

    switch (key)
    {
        case ConsoleKey.D1:
            if (inventory.Count < 5)
            {
                Console.WriteLine($"{longSword.name}를 구매합니다.");
                Console.WriteLine($"플레이어의 {longSword.enfo}이 {longSword.value} 상승하여 {attack += longSword.value}이(가) 됩니다.");
                Console.WriteLine($"보유한 골드가 {longSword.price} 감소하여 {gold -= longSword.price}G가 됩니다.\n");
                inventory.Add(longSword);
                Console.Write("계속하려면 아무키나 입력하세요 (돌아가기 0) : ");
                ConsoleKey key1 = Console.ReadKey().Key;
                switch (key1)
                {
                    case ConsoleKey.D0:
                        Render(;
                        break;
                    default:
                        ItemBuyMenu();
                        break;
                }
                break;
            }
            else
            {
                Console.WriteLine("인벤토리가 가득 차 더 이상 구매할 수 없습니다.");
                Console.Write("계속하려면 아무키나 입력하세요 (돌아가기 0) : ");
                ConsoleKey key2 = Console.ReadKey().Key;
                switch (key2)
                {
                    case ConsoleKey.D0:
                        Render();
                        break;
                    default:
                        ItemBuyMenu();
                        break;
                }
            }
            break;

아이템 구매 탭에서는 최대 소지 제한인 5개를 넘어갈 경우 구매를 하지 못하도록 만들었고, 구매한 아이템을 List에 추가하여 판매 탭과 플레이어 탭에서 확인이 가능하도록 했다.

  • SellMenuInput

static void SellMenuInput()
{
    Console.Write("판매할 아이템을 선택하세요 (취소 0) : ");
    string key = Console.ReadLine();
    Console.WriteLine("");

    if (int.Parse(key) > 0 && int.Parse(key) <= inventory.Count)
    {
        for (int i = 1; i <= inventory.Count; i++)
        {
            if (int.Parse(key) == i)
            {
                if (inventory[i - 1].Equals(longSword))
                {
                    Console.WriteLine($"{inventory[i - 1].name}를 판매합니다.");
                    Console.WriteLine($"플레이어의 {inventory[i - 1].enfo}이 {inventory[i - 1].value} 감소하여 {attack -= inventory[i - 1].value}이(가) 됩니다.");
                    Console.WriteLine($"보유한 골드가 {inventory[i - 1].price} 증가하여 {gold += inventory[i - 1].price}G가 됩니다.\n");
                    inventory.Remove(inventory[i - 1]);
                    Console.Write("계속하려면 아무키나 입력하세요 (돌아가기 0) : ");
                    ConsoleKey key1 = Console.ReadKey().Key;
                    switch (key1)
                    {
                        case ConsoleKey.D0:
                            Render();
                            break;
                        default:
                            ItemSellMenu();
                            break;
                    }
                

아이템 판매 탭에서는 구매한 아이템 순서대로 출력이 되어, 번호를 눌렀을 때 해당 번호의 아이템을 판매할 수 있도록 하였다. 다만 아이템의 Type에 따라 변화되는 플레이어의 스탯이 달라지기 때문에 이를 if문으로 설정하여 구분이 되도록 했다. 이 경우 코드 길이가 너무 길어져 이를 함수로 빼는 것이 더 효율적일 것 같다.

  • ConfigMenuInput

static void ConfigMenuInput()
{
    ConsoleKey key = Console.ReadKey().Key;

    switch (key)
    {
        case ConsoleKey D0:
            Render();
            break;
        default:
            Render();
            break;
    }
}

플레이어 탭에서는 확인 이후, 아무 키나 누르면 다시 메인으로 돌아가게 설정했다. switch 구문은 다시 수정하여 줄일 수 있을 것 같다.

6. 추가 보완, 수정할 내용

  1. InputUpdate 분리
  2. 플레이어 구조체 선언
  3. SellMenuInput 에서 반복되는 구문 함수로 설정
  4. Console.ReadKey와 Console.ReadLine 통합
  5. 아이템 소지 제한 확장( Console.Clear` 기능 파악)

프로젝트 GitHub 링크

profile
뚠뚠뚠뚠

0개의 댓글