본문 바로가기

카테고리 없음

[Python/클래스] 클래스로 자판기 만들기 (예제)

"""
ClassGeneralVM.py

- 참고유튜브 영상: "크리애플creApple"의 "파이썬 프로젝트 1 파이썬으로 자판기 프로그램을 만들어요!클래스 편"
- 영상에 소스코드가 다 나온 것은 아니라서 추측하여 완성하고, 이래저래 수정한 것임
- 수정한 부분:
  영상에 나온 재귀함수 호출 부분을 제거하고 루프를 적절히 활용하는 식으로...
  VM 클래스 하나만 만들고 자판기 개체들은 그 특징을 클래스에 인자로 전달하여 인스턴스를 만드는 식으로...
  리스트 인덱싱을 이용해 함수 갯수를 줄이고 간결하게...
  맛있는 음식이나 음료 자판기를 추가함...ㅎㅎ 칭따오, 기네스는 안 먹어봤네...

클래스 실습 - 자판기 완성하기
"""
import sys


class VM:
    def __init__(self, name, products, prices):
        # 자판기의 기본 틀
        self.name = name
        self.products = products  # 제품명 리스트
        self.prices = prices      # 가격들 리스트
        self.menu_num = len(products)  # 메뉴의 갯수
        self.price_unit = 100  # 가격은 100원 단위
    # 메시지 출력에 사용되는 문자열들
    texts = {"title": "#### 클래스 %s 자판기입니다. ####",
             "product": "%s:%s(%s원)",
             "insert_coin": "동전을 넣어주세요 (취소: 0) ",
             "not_enough_coin": "동전이 부족합니다. 거스름돈은 %s원입니다.",
             "refund": "거스름돈은 %s원입니다.",
             "select_product": "원하는 상품번호를 선택하세요: ",
             "select_fault": "잘못 누르셨습니다.",
             "product_out": "선택하신 %s 입니다. 거스름돈은 %s원입니다.\n 감사합니다.",
             "cancle_select": "취소를 선택하셨습니다.",
             "exit": "종료합니다.",
             }

    def printWelcome(self):
        # 클래스 %s 자판기입니다 출력.
        print(self.texts["title"] % self.name)

    def selectProduct(self, coins):
        global flag
        # 메뉴 선택 문자열 만들기
        discription = ""
        for i in range(self.menu_num):
            price = self.prices[i]
            discription += str(i) + ':' + \
                self.products[i] + '(' + str(price) + '원' + ') '
        discription += ' (취소:' + str(self.menu_num) + ') '
        print(discription)
        # 번호가 선택되면 숫자인지 아닌지, 유효한 숫자인지 확인 후 조처
        selected_num = input(self.texts['select_product'])
        # 선택된 것이 숫자가 아니라면 다시 루프로
        if selected_num.isdecimal() == False:
            print(self.texts['select_fault'])
            return
        # 숫자라면 그 문자열을 정수로 변환. 유효 숫자인지 확인
        else:
            selected_num = int(selected_num)
            # 취소가 선택되었다면 메시지 출력하고 루프 중단 플래그를 설정하고 리턴
            if selected_num == self.menu_num:
                print(self.texts['cancle_select'])
                # 돈 반환 코드
                print(self.texts['refund'] % (coins * self.price_unit))
                flag = False
                return
            # 잘못된 숫자를 입력했다면 메시지 출력하고 다시 루프로
            elif selected_num < 0 or selected_num > self.menu_num:
                print(self.texts['select_fault'])
                return
        # 선택된 숫자를 인덱스 삼아 제품 가격과 제품명을 가져옴
        selected_price = self.prices[selected_num]
        selected_product = self.products[selected_num]
        # 정산 함수에게 코인 개수, 해당 제품명, 제품 가격을 인자로 넘긴다
        self.payment(coins, selected_product, selected_price)

    def payment(self, coins, product, price):
        global flag
        # 10 코인이라면 * price_unit을 곱해 1000원
        coins_value = coins * self.price_unit
        # 코인 수치가 가격보다 높다면
        if coins_value >= price:
            balance = coins_value - price
            print(self.texts['product_out'] % (product, int(balance)))
        else:
            print(self.texts['not_enough_coin'] % int(coins_value))
            flag = False
        return
        # 처리를 마쳤으니 다시 메인 루프로 돌아간다.


# ---------------------------------------------
# 자판기 종류에 따른 메뉴와 가격
vm_names = ["커피", "과자", "아이스크림", "캔맥주", "막걸리"]

vm_types = [["설탕커피", "프림커피", "원두커피"],                      # 커피
            ["오감자", "오징어땅콩", "빼빼로", "칸쵸"],                # 과자
            ["설레임", "죠스바", "투게더", "싸만코", "팥빙수"],         # 아이스크림
            ["카스라이트", "기네스", "아사히", "필라이트", "테라", "칭따오"],  # 캔맥주
            ["홍천막걸리", "서울막걸리", "포천막걸리", "지평막걸리"]]         # 막걸리

vm_prices = [[200, 300, 400],           # 커피
             [400, 500, 600, 500],      # 과자
             [700, 500, 300, 1000, 1500],    # 아이스크림
             [1800, 3000, 3000, 1000, 2700, 2500],  # 캔맥주
             [1800, 1200, 1800, 3200]]      # 막걸리

# 자판기 개수
VM_num = len(vm_names)

# -----------------------------------------
# 자판기 종류를 선택하도록 한다.
# 자판기 종류 목록을 만든다.
description = ""
for i in range(VM_num):
    description += str(i) + ': ' + vm_names[i] + ' '
description += str(i+1) + ': 취소'
print(description)
#print("0: 커피 1: 과자 2: 아이스크림 3: 맥주 4: 막걸리 5: 취소")
selected_vm = input("사용할 자판기를 선택하세요: ")

# 숫자가 아닌 것이 입력되었다면 종료.
if selected_vm.isdecimal() == False:
    print("잘못 누르셨습니다.")
    exit(0)
# 숫자가 입력되었다면 유효한 정수인지 확인한다.
else:
    selected_vm = int(selected_vm)  # 정수로 변환한다.
    # 유효한 숫자가 아니라면 종료
    if selected_vm >= VM_num or selected_vm < 0:
        print("종료합니다.")
        exit(0)

# 선택된 번호를 인덱스 삼아 자판기명, 제품명 목록, 제품 가격 목록을 뽑아 자판기 클래스 인스턴스를 만든다.
CurVM = VM(vm_names[selected_vm], vm_types[selected_vm],
           vm_prices[selected_vm])
# 환영 메시지를 출력한다.
CurVM.printWelcome()

# flag는 전역변수로 사용하여 루프를 탈출하는 데 이용된다.
flag = True

# 선택된 자판기(생성된 VM 인스턴스)를 가동한다.
while flag:
    # 동전 개수를 입력 받는다. 유효하면 제품 선택 메뉴로 넘어간다.
    coins = input(CurVM.texts['insert_coin'])
    if coins.isdecimal() == False:
        print(CurVM.texts['select_fault'])
    else:
        coins = int(coins)
        if coins == 0:  # 0이라면 종료
            print(CurVM.texts['exit'])
            flag = False
        else:
            CurVM.selectProduct(coins)