본문 바로가기
자료구조

[자료구조] Stack 구현 (C++)

by 송파감자 2023. 3. 19.

금요일에 짰던 초밥 스택을 Push랑 Pop하는 걸 복습할 겸 아래와 같이 다시 새로 짜보았다.

감자초밥에서 초밥 한 접시 주문해보세요 :)

 

#include <iostream>
using namespace std;

struct SushiSt {
	string name = "초밥이름";
	int price = 1004;
};

// 내가 구매한 접시 푸쉬하고 팝하려고 만든 클래스임
class Stack {
	enum { MAX_ARRAY_SIZE = 10 };
public:
	Stack()
		: m_top(0) { } // m_top을 0으로 초기화 해줌

	void Push(string name, int price)
	{
		m_sushiAry[m_top].name = name;
		m_sushiAry[m_top++].price = price;
	}

	void Pop()
	{
		if (m_top > 0)
			m_top--;
	}

	void Print()
	{
		// 남은 접시 없을 때 예외처리
		if (m_top <= 0)		
			return;		

		for (int i = m_top-1; i >=0; i--)
		{
			cout << i+1 << ". " << m_sushiAry[i].name << " " << m_sushiAry[i].price << endl;
		}
	}

private:
	// 내가 산 초밥 배열 만들려고
	SushiSt m_sushiAry[MAX_ARRAY_SIZE]; // 초기화 안 해서 맨첨에 쓰레기값 들어가 있음
	int m_top;
};

void Run();

void ShowMenu(SushiSt menuAry[]);
void OrderMenu(SushiSt menuAry[], Stack* plateStack, int& money);
void CheckBill(int& bill, int& money, int& selectCount, int selectIdxAry[]);
void Eat(Stack* plateStack);

void DoAlba(int& money);
void Cook(int& money);
void Serve(int& money);

int Finish();

//---------------------------------------------------------------
int main()
{
	Run();

	return 0;
}
//---------------------------------------------------------------
// desc   : 메인 돌면 총 정리 하는 함수
// param  : void
// return : void
void Run()
{
	enum { MAX_SIZE = 30 };
	enum { SHOW_MENU = 1, EAT_SUSHI, DO_ALBA, CHECK_BALANCE, FINISH };

	int money = 10000;

	SushiSt menuAry[MAX_SIZE];

	// 주문완료한 스시접시를 푸쉬,
	// 먹은 접시는 팝 하기 위한 스택
	Stack plateStack;

	// 메뉴판 초기화
	menuAry[0] = { "none", 1004 };
	menuAry[1] = { "우니", 4000 };
	menuAry[2] = { "오도로", 3600 };
	menuAry[3] = { "주도로", 3500 };
	menuAry[4] = { "연어뱃살", 2500 };
	menuAry[5] = { "계란", 1500 };
	menuAry[6] = { "유부", 1000 };

	while (1)
	{
		cout << "----------------------* 감자초밥 *----------------------" << endl;
		cout << "1. 초밥메뉴 확인 2. 초밥 먹기 3. 초밥집 알바하기 4. 잔고 확인 5. 끝내기 : ";

		int num;
		cin >> num;

		switch (num)
		{
		case SHOW_MENU:
			ShowMenu(menuAry);
			OrderMenu(menuAry, &plateStack, money);
			system("pause");
			system("cls");
			break;

		case EAT_SUSHI:
			Eat(&plateStack);
			system("pause");
			system("cls");
			break;

		case DO_ALBA:
			DoAlba(money);
			system("pause");
			system("cls");
			break;

		case CHECK_BALANCE:
			cout << "현재 잔액 : " << money << "원" << endl;
			system("pause");
			system("cls");
			break;

		case FINISH:
		{
			int answer = Finish();
			if (answer == 1)
			{
				cout << "감자초밥을 이용해주셔서 감사합니다." << endl;
				return;
			} // answer를 케이스 안에서 초기화해서 C2361 오류나서 묶어줌
		}
		break;

		default:
			cout << "다시 입력하세요." << endl;
			system("pause");
			system("cls");
			continue;

		}//스위치문 끝

	}	//반복문 끝
}
//---------------------------------------------------------------
// desc   : 초밥 메뉴 보여주는 함수
// param  : SushiSt menu[]  초밥메뉴 구조체배열
// return : void
void ShowMenu(SushiSt menuAry[])
{
	for (int i = 1; i < 6; i++)
	{
		cout << i  << ". " << menuAry[i].name << ' ' << menuAry[i].price << "원" << endl;
	}
}
//---------------------------------------------------------------
// desc   : 초밥 메뉴 고르는 함수
// param  : SushiSt menu[]  초밥메뉴 구조체배열 , Stack* plateStack 구매한 스시를 담을 스택 포인터, int& money(머니의 주소)
// return :	void
void OrderMenu(SushiSt menuAry[], Stack* plateStack, int& money)
{
	enum Emenu { None = 0, Uni, Odoro, Judoro, Salmon, Egg, Yubu };
	enum { MAX_SELECT_LENGTH = 20 };

	int bill = 0;

	// (계산 전) 셀렉한 스시 인덱스를 저장하는 배열
	int selectIdxAry[MAX_SELECT_LENGTH] = { 0, };
	int selectCount = 0;

	while (true)
	{
		int menu = 0;
		cout << "메뉴를 선택하세요: ";
		cin >> menu;

		switch (menu)
		{
		case Uni:
		case Odoro:
		case Judoro:
		case Salmon:
		case Egg:
		case Yubu:
			bill += menuAry[menu].price;
			selectIdxAry[selectCount++] = menu;
			break;

		default:
			cout << "잘못된 입력입니다. 다시 입력해주세요." << endl;
			continue;
		}

		int answer = 0;
		cout << "더 선택하시나요? (1.네 2.그만 ) : ";
		cin >> answer;

		// 주문 종료
		if (answer == 2)
		{
			// 계산할 돈 부족하다면 
			// bill, selecSushiIndexes배열, selectCount 초기화 후 다시 메뉴 입력 받음
			if (bill > money)
			{
				CheckBill(bill, money, selectCount, selectIdxAry);

				// 머니 불충분해서 주문 선택하는 반복문 다시 감
				continue;
			}

			// 머니가 충분하면 주문 선택하는 반복문 탈출
			break;
		}

		// 그만두지 않을 거면 계속 주문 받는데
		// 그전에 돈 충분한지 확인 한다
		else
		{
			CheckBill(bill, money, selectCount, selectIdxAry);
			continue;
		}

	} // while문끝		

	cout << money << "원 에서 ";

	// 돈 충분하면 빌 계산한다
	money -= bill;
	cout << bill << "원 선결제 하였습니다. "		
		<< "현재 잔액 : " << money << "원" << endl;

	cout <<"----현재 갖고 있는 접시----" << endl;


	// 내가 selectIdxAry에 메뉴판에서 몇번째 초밥 샀는지 인덱스 저장해둠
	// 스택에다가 내가 산 초밥정보를 푸쉬(저장)하기 위해서 인덱스를 갖고 와서 
	// 메뉴판의 초밥 이름과 가격을 저장해주고 있다
	for (int i = 0; i < selectCount; i++)
	{
		int j = selectIdxAry[i];
		plateStack->Push(menuAry[j].name, menuAry[j].price);
	}

	plateStack->Print();
		
	return;
}
//---------------------------------------------------------------
// desc   : 주문하고 돈 충분하지 체크하는 함수
// param  : int& bill 지불할 금액 , int& money 현재 돈, int& selectCount 선택한 횟수, int selectIdxAry[]
// return : void
void CheckBill(int& bill, int& money, int& selectCount, int selectIdxAry[])
{
	// 내 돈이 많으면 그냥 리턴
	if (bill <= money)
		return;

	// 내 돈이 적으면 아래 수행
	cout << "돈이 부족합니다. 처음부터 다시 선택해주세요." << endl;
	cout << "현재 잔액 : " << money << endl;

	// 돈 부족해서 다시 선택위해 아까 저장한 애들 다 초기화
	bill = 0;
	for (int i = 0; i < selectCount; i++)
	{
		selectIdxAry[i] = 0;
	}
	selectCount = 0;
}
//---------------------------------------------------------------
// desc   : 감자초밥 종료하는 함수
// param  : void
// return : int anwer 종료할지 말지 값
int Finish()
{
	int answer;

	cout << "감자초밥을 나가시겠습니까?(1.네 2.아니오): ";
	cin >> answer;

	return answer;
}
//---------------------------------------------------------------
// desc   : 마지막으로 구매한 초밥부터 먹어서 그릇 Pop하는 함수
// param  : Stack* plateStack
// return : void
void Eat(Stack* plateStack)
{
	// 0. 먹기전 접시 출력해준다
	cout << "-----먹기 전 접시-----" << endl;
	plateStack->Print();

	// 1. 플레이트스택에서 팝한다(최근에 구매한 순서대로 초밥을 먹는다)
	plateStack->Pop();	
	
	// 2. 먹고 나면 남은 접시를 출력해준다
	cout << "-----먹고 남은 접시-----" << endl;
	plateStack->Print();
}
//---------------------------------------------------------------
// desc   : 감자초밥에서 알바해서 돈벌게 해주는 함수
// param  : int& money
// return : void
void DoAlba(int& money)
{
	enum EAlba { ECook = 1, EServe, EFin };
	enum ELevel { EJunior = 1, ESenior, EManager };
	int num;

	cout << "----------------------*알바천국*-------------------------" << endl;
	cout << "1.초밥 만들기  2.서빙  3.종료 : ";
	cin >> num;

	switch (num)
	{
	case ECook:
		Cook(money);
		break;

	case EServe:
		Serve(money);
		break;

	case EFin:
		return;
		break;

	default:
		break;
	}

	return;
}
//---------------------------------------------------------------
// desc   : DoAlba함수에서 초밥 만들어서 돈 벌어 돈 리턴해주는 함수
// param  : int& money
// return : void
void Cook(int& money)
{
	int hour;
	int hourMoney = 15000; //  시급

	cout << "업무 : 초밥 만들기" << endl;
	cout << "시급 : " << hourMoney << "원" << endl << endl;

	while (1)
	{
		cout << "몇 시간 근무하시겠습니까? (최대 5시간): ";
		cin >> hour;

		// 예외처리
		if (hour > 5 || hour < 1)
		{
			cout << "시간을 다시 선택하세요." << endl;
			continue;
		}

		money += (hour * hourMoney);
		cout << "알바비 : " << hour * hourMoney << "원" << endl;
		cout << "잔액 : " << money << endl;
		break;
	}

	return;
}
//---------------------------------------------------------------
// desc   : DoAlba함수에서 서빙해서 돈 버는 함수
// param  : int& money
// return : void
void Serve(int& money)
{
	int hour;
	int hourMoney = 9000; //  시급

	cout << "업무 : 서빙하기" << endl;
	cout << "시급 : " << hourMoney << "원" << endl << endl;

	while (1)
	{
		cout << "몇 시간 근무하시겠습니까? (최대 8시간): ";
		cin >> hour;

		// 예외처리
		if (hour > 8 || hour < 1)
		{
			cout << "시간을 다시 선택하세요." << endl;
			continue;
		}

		money += (hour * hourMoney);
		cout << "알바비 : " << hour * hourMoney << "원" << endl;
		cout << "잔액 : " << money << endl;
		break;
	}

	return;
}

'자료구조' 카테고리의 다른 글

[자료구조] DFS와 BFS  (0) 2024.08.02
[자료구조] Double Linked List (C++)  (1) 2023.10.23
[자료구조] Single Linked List (C++)  (0) 2023.10.15
[자료구조] Stack 개념 정리  (2) 2023.03.18