만차 판정(is_full(type))도 이 표를 따른다. 승용차는 「소형 + 대형」 현재 수가 최대 수에 닿았는지, 전기차는 「전기 + 소형 + 대형」을 본다.
flowchart TB
a["입구 패널이 get_new_parking_ticket(vehicle) 호출"] --> b{"그 차종 자리가 가득 찼나?"}
b -->|"예"| full["만차 예외, 패널에 메시지"]
b -->|"아니요"| c["락 획득"]
c --> d["주차권 생성, 차에 배정"]
d --> e["DB에 저장"]
e --> f["저장 성공 뒤에 종류별 자리 수 증가"]
f --> g["활성 주차권 목록에 추가"]
g --> h["락 해제, 주차권 반환"]
입구 패널이 여럿이라 동시에 발급해도 서로 간섭하지 않게 발급 구간을 락으로 감싼다. 자리 수는 DB 저장이 성공한 다음에만 늘린다.
싱글턴 초기화 때 DB에서 이름·주소·요금표, 층 지도(층마다 자리 수와 최대 수), 활성 주차권(현재 자리 수 복원), 입구·출구 패널을 읽는다.
차를 자리에 배정했는데 그 자리가 마침 표시판에 떠 있던 빈 자리면, 같은 종류의 다른 빈 자리를 찾아 표시판을 갱신한다.
flowchart TB
a["고객이 출구 패널에 주차권 넣기"] --> b["주차권 스캔, 정보 조회"]
b --> c["총 요금 계산"]
c --> d["요금 표시, 카드 요청"]
d --> e["고객이 카드 삽입"]
e --> f["카드 읽고 결제 처리"]
f --> g{"결제 성공?"}
g -->|"아니요"| err["오류 표시"]
err --> d
g -->|"예"| ok["성공 메시지"]
ok --> r{"영수증 출력?"}
r -->|"예"| prt["영수증 출력"]
r -->|"아니요"| gate["차단기 열기 신호"]
prt --> gate
카드 삽입 → PIN 요청 → PIN 입력 → 맞으면 메뉴(입금, 인출, 이체, 잔액 조회), 틀리면 오류 후 재시도 여부
인출
인출 선택 → 금액 선택지(20달러, 40달러, 100달러, 직접 입력, 취소) → 잔액 확인 → 부족하면 알림 → 거래 수행 → 현금 지급 → 영수증 출력 여부 → 카드 반환
수표 입금
수표 입금 선택 → 계좌 선택(입출금·저축) → 입금구에 수표 넣기 → 스캔 → 금액 표시 → 금액이 틀리면 고객이 바른 금액 입력 → 잔액에 반영 → 성공 메시지 → 영수증 여부 → 카드 반환
이체
금액 입력 → 잔액 부족이면 안내 후 재시도 여부 → 받는 계좌 번호 입력 → 검증, 잘못된 번호면 재시도 여부 → 거래 수행과 계좌 갱신 → 성공 메시지 → 영수증 여부 → 카드 반환
잔액 조회 시퀀스는 다음과 같다.
sequenceDiagram
actor C as Customer
participant A as ATM
participant T as Transaction
participant AC as Account
participant CH as CheckingAccount
participant S as Screen
C->>A: getBalance(Account)
A->>T: balanceInquiryTransaction(Account)
T->>AC: getBalance()
AC->>CH: getBalance()
CH-->>AC: Balance
AC-->>T: Balance
T-->>A: Balance
A->>S: displayMessage(Balance)
S->>S: showMessage()
플레이어와 딜러가 각각 두 장. 플레이어 카드는 모두 앞면, 딜러는 한 장만 보이고(up card) 한 장은 숨긴다(hole card)
목표
21점을 넘지 않으면서 딜러보다 높은 점수
점수
2~10은 숫자대로, J·Q·K는 10점, 에이스는 1점 또는 11점. 에이스 + 10점 카드 두 장으로 21이면 블랙잭
소프트·하드
에이스를 11로 센 합이 소프트 합계, 1로 센 합이 하드 합계다. A + 5는 소프트 16, 하드 6
딜러 규칙
16 이하면 한 장 더(hit), 17 이상이면 멈춘다(stand)
플레이어 선택
히트(한 장 더), 스탠드(멈춤), 더블(판돈을 두 배로 하고 딱 한 장만 더), 스플릿(같은 끗수 두 장을 두 패로 나눔)
버스트
21을 넘으면 그 자리에서 진다
정산
높은 쪽이 이기고 비기면 판돈을 돌려받는다. 블랙잭은 3:2, 나머지 승리는 1:1. 딜러가 버스트하면 플레이어가 이긴다
베팅
조건과 금액
앤티(Ante)
처음 거는 필수 판돈
보험(Insurance)
딜러의 보이는 카드가 에이스일 때만. 앤티의 절반. 딜러가 정확히 21이면 2:1로 받아 원래 판돈 손실을 메운다
스플릿
두 장의 끗수가 같을 때만. 앤티와 같은 금액. 패마다 한 장씩 더 받아 따로 진행하고, 다시 나누지는 않는다
더블
일반 히트 대신. 앤티와 같은 금액
딜러가 에이스를 보이면 보험을 제안한 뒤 숨긴 카드를 확인한다. 10점 카드면 블랙잭이니 카드를 공개하고 보험금을 준다. 아니면 보험은 지고 카드는 공개하지 않은 채 계속한다. 플레이어가 블랙잭(소프트 21)이면 먼저 이븐 머니를 제안한다. 받아들이면 앤티를 1:1로 받고 그 판이 끝나며, 거절하면 보험을 제안한다.
앤티 걸기, 보험 등 추가 베팅 수락·거절, 스플릿, 이븐 머니 수락·거절, 히트·더블·스탠드 선택
클래스
책임과 속성
Card
무늬와 끗수(1~13)
BlackjackCard (Card 상속)
게임 점수: 끗수가 10을 넘으면 10. 에이스는 1 또는 11
Deck
52장, 생성일. 끗수 1~13 × 무늬 4개로 만든다
Shoe
덱 여러 개를 담는 카지노 장비. 덱 수, create_shoe(), shuffle(), deal_card()(다 쓰면 새로 채운다)
Hand
카드 목록. get_scores()는 에이스를 만날 때마다 1과 11 두 갈래로 가능한 합계를 모두 만들고, resolve_score()는 그중 21 이하 최댓값을 고른다
BasePlayer ← Player, Dealer
ID, 비밀번호, 잔액, 상태, Person, 패 목록 / 판돈, 보유 현금
Game
플레이어, 딜러, 슈(덱 최대 3개). 게임 진행, 베팅 제안, 카드 배분, 승패 정산, 스플릿, 히트·더블·스탠드 처리
SUIT enum은 HEART, SPADE, CLUB, DIAMOND다. 셔플은 앞에서부터 각 자리와 남은 범위의 임의 자리를 바꾸는 피셔-예이츠(Fisher-Yates) 방식이다. 스플릿은 원래 패를 지우고, 두 카드에 새 카드를 한 장씩 붙인 패 두 개를 플레이어에게 더한다.
flowchart TB
a["플레이어가 판돈을 건다"] --> b["딜러가 자기와 플레이어에게 두 장씩"]
b --> c{"히트 또는 스탠드"}
c -->|"히트"| d["플레이어에게 한 장 더"]
d --> e{"플레이어 합계가 21 초과?"}
e -->|"예"| lose1["플레이어 패배, 딜러가 판돈 가져감"]
e -->|"아니요"| c
c -->|"스탠드"| bj{"블랙잭인가?"}
bj -->|"예"| win3["플레이어 승리, 3:2 지급"]
bj -->|"아니요"| f["딜러가 규칙대로 자기 카드 추가"]
f --> g{"플레이어 합계가 딜러보다 큰가?"}
g -->|"크다"| win1["플레이어 승리, 1:1 지급"]
g -->|"작다"| lose2["플레이어 패배"]
g -->|"같다"| tie["무승부, 판돈 반환"]
복사본의 어떤 말이든 자기 킹의 위치를 위협하면 불법 수다. 킹 위치는 킹이 움직일 때마다 보드에 등록한다.
통과하면 진짜 보드에 실행하고 차례를 넘긴다.
설계 문서의 활동 다이어그램은 여기에 특수 규칙을 더한다.
flowchart TB
a["b1에서 b2로 말을 옮기려 함"] --> v{"규칙에 맞는 수인가?"}
v -->|"아니요"| no["잘못된 수 안내"]
v -->|"예"| cap{"b2에 말이 있나?"}
cap -->|"예"| take["b2의 말을 잡는다"]
cap -->|"아니요"| cas{"캐슬링인가?"}
take --> cas
cas -->|"예"| rook["룩 위치도 맞춘다"]
cas -->|"아니요"| pro{"폰 승진 조건인가?"}
rook --> pro
pro -->|"예"| promote["퀸, 비숍, 나이트, 룩 중 하나로 승진"]
pro -->|"아니요"| mate{"게임이 끝났나?"}
promote --> mate
mate -->|"예"| over["게임 종료 안내"]
mate -->|"아니요"| move["말을 b2로 옮긴다"]