"""
FILE_NAME : team_problem_mini_dalmuti.py
출제팀 : 경주마와 친구들
출제일자 : 2023-04-18
문제 이름 : <미니 달무티 게임 만들기>
조건 :
1 : 왕 1장
2 : 대주교 2장
3 : 시종장 3장
4 : 남작부인 4장
5 : 수녀원장 5장
0 : 조커 1장
전체 16장의 카드 중에서
컴퓨터와 사용자가 각각 8장씩 가져간다.
컴퓨터와 사용자가 랜덤으로 카드를 뽑아서
숫자가 낮은 사람이 먼저 시작한다.
선이 카드를 1장이상 버리면
다른 사람은 먼저 카드를 버린 사람의 숫자보다 작으면서 같은 수량의 카드를 버려야 한다.
버릴 카드가 없으면 패스가 가능하고, 다음 사람은 숫자와 수량에 관계없이 카드를 버릴 수 있다.
모든 카드를 버리는 사람이 승리
조커는 다른 카드와 같이 낼수있지만, 혼자 낼수는 없다.
카드는 딕셔너리, 리스트 모두 사용가능
카드 딕셔너리 예시
card = {"왕":1, "대주교":2, "시종장":3, "남작부인":4, "수녀원장":5, "조커":6}
card = {
0:[{0:'조커'}],
1:[{1:'달무티'}],
2:[{2:'대주교'},{2:'대주교'}],
3:[{3:'시종장'},{3:'시종장'},{3:'시종장'}],
4:[{4:'남작부인'},{4:'남작부인'},{4:'남작부인'},{4:'남작부인'}],
5:[{5:'수녀원장'},{5:'수녀원장'},{5:'수녀원장'},{5:'수녀원장'},{5:'수녀원장'}]
}
여러가지 방법이 있더라구요, 편한 방법으로 사용하시면 되겠습니다!
게임룰 자세히 보기 : https://namu.wiki/w/%EB%8B%AC%EB%AC%B4%ED%8B%B0
혹시 어려운 것을 원하신다면 카드 수량을 늘려도 좋습니다.
[ random 방법 ]
임포트 필요 : import random
순서 섞기 : random.shuffle(리스트 변수명)
랜덤으로 값 가져오기 : random.randint(시작숫자, 종료숫자)
랜덤으로 값을 여러개 가져오기 : random.sample(range(시작숫자, 종료숫자), 수량)
리스트에서 랜덤으로 1개 값 가져오기 : random.choice(리스트 변수명)
"""
!! 아직 완성을 다 못했습니다.
개발일지 작성 위해 중간 보고서로 작성한 것입니다.
나의 코드 해설 및 중간 후기 :
달무티 게임을 구현하는 것이 이번 프로젝트의 목표이다. 실제로 해본적이 없는 게임이라 룰을 숙지하고, 구현하는데 애를 좀 먹은 것 같다. 또한, 처음 리스트[튜플(카드 개수만큼 append)] 형식으로 만들었다가, 중간에 비효율적인 것 같아 다시 자료형을 수정하느라, 시간이 오래 걸렸다. 하지만, 지금은 딕셔너리 타입으로도 카드 셋(현재는 16장)이 바로 만들어지도록 구현했다. 또한, 입력 검증과 카드패 보여지는 화면의 처리를 위해 부득이하게 함수를 써야했다.
대부분의 로직은 구현 했으나, 아직 미완성인 부분은
- 카드 선택, pass, 조커 사용하기
- 낼 수 없는 카드셋일 때, pass 낼 수 있게 하기.
- 조커를 사용한다고 할 때 어떻게 내게 할지.
- 컴퓨터에게 조커가 있을 경우 어떻게 로직처리를 할지.
정도 남은 것 같다.
현재는 코드는 중간중간에 직접적인 print가 남아서 지저분하지만, 나머지 로직을 완성해놓고 디버깅까지 끝낸 후에 정리할 계획이다. 그렇지 않으면 생산성이 너무 떨어지는 것 같다.
import random
card_dict = {
1: 'Dalmuti', # 달무티
2: 'Archbishop', # 대주교
3: 'Earl Marshal', # 시종장
4: 'Baroness', # 남작부인
5: 'Abbess', # 수녀원장
6: 'Jester' # 조커
}
def print_card(card_index):
width = 12
result_line = []
line_start = "┌" + "─" * width + "┐"
line_basic = "│" + " " * width + "│"
if card_index == '?':
line_card_mark_0 = "│" + f"{'?':^{width}}" + "│"
line_card_mark_1 = "│" + f"{'???':^{width}}" + "│"
else:
line_card_mark_0 = "│" + f"{card_index:^{width}}" + "│"
line_card_mark_1 = "│" + f"{globals()['card_dict'][card_index]:^{width}}" + "│"
line_end = "└" + "─" * width + "┘"
result_line.append(line_start)
result_line.append(line_basic)
result_line.append(line_basic)
result_line.append(line_card_mark_0)
result_line.append(line_card_mark_1)
result_line.append(line_basic)
result_line.append(line_basic)
result_line.append(line_end)
return result_line
def print_card_list(cards: list) -> list:
if len(cards) == 0:
print('[System] 카드 없음!')
return
result_line = []
height = len(print_card(cards[0]))
for i in range(height):
result_line.append('')
for i in cards:
lines = print_card(i)
for j in range(height):
result_line[j] = result_line[j] + lines[j]
for l in result_line:
print(l)
def can_make_card(cards, constraints):
can_card_list = []
card_set = set(cards)
if constraints[0] == 0: # 제한 없는 상태
for c in card_set:
can_card_list.append((c, cards.count(c)))
else:
for c in card_set:
if c <= constraints[0]:
can_card_list.append((c, cards.count(c)))
can_card_list.sort()
return can_card_list
def verify_card_select(can_card_list, select_card):
card_number = select_card[0]
card_size = select_card[1]
limit_size = 0
for tuple_ in can_card_list:
if (tuple_[0] == card_number):
limit_size = tuple_[1]
if card_size <= limit_size:
return True
else:
return False
intro_message = {
'start': '[System] 안녕하세요. 미니 달무티 게임입니다.\n게임을 시작하시겠습니까?',
'guide_who_first': '[System] 선잡기를 시행합니다.',
'show_user_card': '[System] 유저가 뽑은 카드는??',
'show_computer_card': '[System] 컴퓨터가 뽑은 카드는??',
'postfix': '입니다.',
'draw_result': '[System] 비겼으므로 다시 시행하겠습니다.',
'user_lose_result': '[System] 컴퓨터가 이겼습니다. 컴퓨터가 먼저 시작하겠습니다.',
'user_win_result': '[System] 유저가 이겼습니다. 유저가 먼저 시작하겠습니다.',
}
ingame_message = [
'[System] 컴퓨터가 ',
'유저가 ',
' 를',
' 장 버렸습니다.',
'컴퓨터는 ',
'유저는 ',
' 번에서',
' 번 사이의 카드를',
' 장씩만 버릴 수 있습니다.',
'어떻게 하시겠습니까?'
]
card_num_set = set(range(1, 7))
ask_message = {
'enter': "Press [Enter]",
'pick_card_first': "[System] 카드를 뽑겠습니까?",
'restart_game': "[System] 게임을 다시 하시겠습니까?",
'card_num_select': "몇 번 카드를 뽑겠습니까? ",
'card_num_size': "몇 장 낼까요? ",
'ask_1': "[ 1. 예 ] [ 2. 아니요 ] ",
'ask_2': "[ 1. 카드 선택하기 ] [ 2. 조커 사용 ] [ 3. 패스 ] ",
'ask_1_verify': ['1', '2'],
'ask_2_verify': ['1', '2', '3'],
'card_num_verify': [str(x) for x in card_num_set],
'wrong_answer': '[Waring] 잘못 입력하셨습니다. 다시 입력해주세요.',
'wrong_card_set': '[Waring] 가능한 조합이 아닙니다.',
}
restart_message = {
'guide_restart': '[System] 게임을 다시 시작하겠습니다.',
'guide_exit': '[System] 게임을 종료하겠습니다..'
}
cards = []
for i in range(1, 7):
if card_dict[i] != 'Jester':
for j in range(i):
cards.append(i)
else:
cards.append(i)
is_program_going = True
is_in_game_going = True
is_selected_who_start_first = True
is_user_turn = False
is_user_win = False
is_constraint_valid = False # 선잡은 사람이 낸 카드가 제한 걸게됨
is_verified_card_selection = False
constraint_applying_count = 0 # 선잡은 사람이 낸 카드가 제한 걸게됨
constraint_tuple = (0, 0) # type : 1x2 tuple
# 선잡은 사람이 낸 카드 번호[0] 보다는 낮게, 카드 수[1]는 똑같이 낼 수 있다.
user_card_list = []
computer_card_list = []
while is_program_going:
is_selected_who_start_first = True
is_user_turn = False
is_in_game_going = True
constraint_tuple = (0, 0)
constraint_applying_count = 0
print(intro_message['start'])
input(ask_message['enter'])
print(intro_message['guide_who_first'])
# Todo : 카드 섞기
random.shuffle(cards)
user_card_list = cards[0:8]
computer_card_list = cards[8:]
user_card_list = sorted(user_card_list)
computer_card_list = sorted(computer_card_list)
# Todo : 선잡기
while is_selected_who_start_first:
is_selected_who_start_first = False
input(f"{ask_message['pick_card_first']} {ask_message['enter']}")
user_select_card = random.choice(cards)
computer_select_card = random.choice(cards)
print(f"{intro_message['show_user_card']} {user_select_card} {intro_message['postfix']}")
print(f"{intro_message['show_computer_card']} {computer_select_card} {intro_message['postfix']}")
if computer_select_card > user_select_card: # 유저가 이김
print(intro_message['user_win_result'])
is_selected_who_start_first = False
is_user_turn = True
input('[System] 확인하셨습니까?')
elif computer_select_card < user_select_card: # 컴퓨터가 이김
print(intro_message['user_lose_result'])
input('[System] 확인하셨습니까?')
print_card_list(user_card_list)
input('[System] 당신의 카드패 입니다. 확인하셨습니까?')
is_selected_who_start_first = False
is_user_turn = False
else: # 무승부
print(intro_message['draw_result'])
is_selected_who_start_first = True
while is_in_game_going:
# TODO : 제한 사항이 유효한지 확인, 없으면 리셋
print('현재 제한 사항 :', constraint_tuple[0], '번', constraint_tuple[1], '장')
if is_user_turn: # 유저 턴
# Todo : 컴퓨터 카드는 잔여 개수만큼 보여주기
print_card_list(['?'] * len(computer_card_list))
# Todo : 유저 카드 보여주기
print_card_list(user_card_list)
# Todo : 낼 수 있는 카드번호 리스트 (카드 번호, 최대 몇장) 추출 & 제한 적용 카운트
can_card_list = can_make_card(user_card_list, constraint_tuple)
constraint_applying_count += 1
print('can_card_list', can_card_list)
# Todo : 유효사항에 대해 확인 후 낼 수 있는 카드 리스트 안내
is_verified_card_selection = False
user_select_card_num = 0
user_select_card_size = 0
while not is_verified_card_selection:
user_select_card_num = input(ask_message['card_num_select'])
if user_select_card_num not in ask_message['card_num_verify']:
print(ask_message['wrong_answer'])
continue
else:
user_select_card_num = int(user_select_card_num)
user_select_card_size = input(ask_message['card_num_size'])
if user_select_card_size not in ask_message['card_num_verify']:
print(ask_message['wrong_answer'])
continue
else:
user_select_card_size = int(user_select_card_size)
is_verified_card_selection = verify_card_select(can_card_list,
(user_select_card_num, user_select_card_size))
if is_verified_card_selection is False:
print(ask_message['wrong_card_set'])
continue
else:
if constraint_applying_count == 1:
constraint_tuple = (user_select_card_num, user_select_card_size)
break
# Todo : 선택한 카드 빼기 로직
for _ in range(user_select_card_size):
temp_index = user_card_list.index(user_select_card_num)
user_card_list.pop(temp_index)
print_card_list(user_card_list)
input("남은 카드패 입니다. 확인하셨습니까?")
# Todo : 상대에게 턴 넘겨주기
is_user_turn = not is_user_turn
# Todo : 여기서 만일 잔여 카드 0되면 승리
if len(user_card_list) == 0:
is_in_game_going = False
is_user_win = True
else: # 컴퓨터 턴
# 디버깅 끝나면 지우기
print_card_list(computer_card_list)
# Todo : 낼 수 있는 카드번호 리스트 (카드 번호, 최대 몇장) 추출
can_card_list = can_make_card(computer_card_list, constraint_tuple)
constraint_applying_count += 1
# Todo : 추출된 리스트에서 랜덤으로 카드 제거
if len(can_card_list) != 0:
rand_tuple = random.choice(can_card_list)
computer_select_num = rand_tuple[0]
computer_select_num_size = rand_tuple[1]
if constraint_applying_count == 1:
constraint_tuple = (computer_select_num, computer_select_num_size)
input(f'컴퓨터는 {computer_select_num}번 {computer_select_num_size}장 냈습니다.\n 확인하셨습니까? ')
# Todo : 선택한 카드 빼기 로직
for _ in range(computer_select_num_size):
temp_index = computer_card_list.index(computer_select_num)
computer_card_list.pop(temp_index)
else:
input('낼 수 있는 카드가 없어 패스함. \n 확인하셨습니까? ')
print_card_list(computer_card_list)
# Todo : 상대에게 턴 넘겨주기
is_user_turn = not is_user_turn
# Todo : 여기서 만일 잔여 카드 0되면 승리
if len(computer_card_list) == 0:
is_in_game_going = False
is_user_win = True
if constraint_applying_count == 2: # 제한사항을 끼고 한바퀴 돌고 온 상태인 것
constraint_applying_count = 0
constraint_tuple = (0, 0)
if is_user_win:
print('유저 승리!') # 유저 이겼음
else:
print('컴퓨터 승리!') # 컴퓨터가 이겼음
while True:
user_input = input(f"{ask_message['restart_game']}\n{ask_message['ask_1']}")
if user_input not in ask_message['ask_1_verify']:
print(ask_message['wrong_answer'])
continue
else:
user_input = int(user_input)
if user_input == 1:
print(restart_message['guide_restart'])
is_program_going = True
else:
print(restart_message['guide_exit'])
is_program_going = False
break

컴퓨터가 들고 있는 패만큼 ?로 표현되게 하고 싶었다.
또한 유저가 들고 있는 패도 보기 깔끔하게 정렬되게 만들었다.
검증을 위해 can_card_list를 만들었고 만약 x 번호를 y장 내고 싶다면? list 내부에 (x, ?) 로 시작하는 것을 찾아
y는 ?보다 작아야 카드를 낼 수 있게 했다.

옳은 카드 조합을 낸다면 ?

그러면 남은 카드패를 보여준다.

그러면 아직은 디버깅용으로 물음표(?) 처리를 안해놓았지만, 카드패가 줄어든 모습을 구현했다. 또한, 유저가 낸 카드를 제한사항으로 저장해둬 컴퓨터는 그 범위 안에서만, 카드패를 낼 수 있게 해놓았다.
컴퓨터가 카드패를 다 냈다면?

다시 유저의 차례로 돌아왔으므로, 제한사항을 리셋하고, 컴퓨터의 남은 패 갯수, 유저의 남은 패 대로 다시금 선택할 수 있게 만들었다.

오늘은 여기까지만 정리하고, 내일까지 마저 완성할 예정이다.
감사합니다.
'광주인력개발원' 카테고리의 다른 글
회원가입, 로그인 화면 구축 개발 실패 보고서 [2023-04-26] (0) | 2023.05.30 |
---|---|
<개복치 키우기> 개발 완료 보고서 [2023-04-25 학습일지] (1) | 2023.05.30 |
for 반복문 사용하여 숫자 스무고개 만들기 [2023-04-21] (1) | 2023.05.30 |
for 반복문 사용하여 가위바위보 게임 만들기 (메시징 처리) [2023-04-21] (0) | 2023.05.30 |
<김주김> 팀이 내주신 문제 풀이 완료 [2023-04-20 학습일지] (0) | 2023.05.30 |