from collections import deque
# 악세서리로 인한 공격력 증가는 미리 써버리자
def RPG_Extreme():
global NAME , NOW_HP,MAX_HP,DEF,ATT,ATT_Accessories,DEF_Accessories,EXP,LV,Player_Accessories,y,x,Answer
if graph[y][x] == "&":
NAME,W, A, H, E = Monster[(y+1, x+1)][0],Monster[(y+1, x+1)][1], Monster[(y+1, x+1)][2], Monster[(y+1, x+1)][3], Monster[(y+1, x+1)][4] # W-공격력 , A-방어력 , H-최대 체력 , E-죽였을때 경험치
Battle_Turn=0
while True:
Battle_Turn+=1
Player_Damage=max(1,(ATT+ATT_Accessories)-A)
Monster_Damage=max(1,W-(DEF+DEF_Accessories))
if "CO" in Player_Accessories and "DX" in Player_Accessories and Battle_Turn==1:
Player_Damage=max(1,3*(ATT+ATT_Accessories)-A)
elif "CO" in Player_Accessories and "DX" not in Player_Accessories and Battle_Turn==1:
Player_Damage = max(1, 2 * (ATT + ATT_Accessories) - A)
H-=Player_Damage
if H<=0:
if "HR" in Player_Accessories:
NOW_HP = min(NOW_HP + 3, MAX_HP)
if "EX" in Player_Accessories:
EXP+=int(1.2 * E)
elif "EX" not in Player_Accessories:
EXP += E
if EXP >= 5 * LV:
LV += 1 ; EXP = 0 ; MAX_HP += 5 ; NOW_HP = MAX_HP ; ATT += 2 ; DEF += 2
graph[y][x] = '.'
break
NOW_HP-=Monster_Damage
if NOW_HP<=0:
if "RE" in Player_Accessories:
NOW_HP = MAX_HP
y, x = start[0][0], start[0][1]
Player_Accessories.remove("RE")
else:
NOW_HP=0
Answer=0
break
elif graph[y][x] == "B":
T, S = Accessories[(y+1, x+1)][0], Accessories[(y+1, x+1)][1]
if T == "W":
ATT_Accessories = int(S)
elif T == "A":
DEF_Accessories = int(S)
elif T == "O":
if len(Player_Accessories) < 4:
if S not in Player_Accessories:
Player_Accessories.append(S)
graph[y][x] = "."
elif graph[y][x] == "^":
if "DX" in Player_Accessories:
NOW_HP -= 1
elif "DX" not in Player_Accessories:
NOW_HP -= 5
if NOW_HP <= 0:
if "RE" in Player_Accessories:
NOW_HP = MAX_HP
y, x = start[0][0], start[0][1]
Player_Accessories.remove("RE")
else:
NOW_HP = 0 # 종료 조건
Answer=2
elif graph[y][x] == "M":
NAME,W, A, H, E = Monster[(y+1, x+1)][0],Monster[(y+1, x+1)][1], Monster[(y+1, x+1)][2], Monster[(y+1, x+1)][3], Monster[(y+1, x+1)][4] # W-공격력 , A-방어력 , H-최대 체력 , E-죽였을때 경험치
Battle_Turn = 0
while True:
Battle_Turn += 1
Player_Damage = max(1, (ATT + ATT_Accessories) - A)
Monster_Damage=max(1,W-(DEF+DEF_Accessories))
if "CO" in Player_Accessories and "DX" in Player_Accessories and Battle_Turn == 1:
Player_Damage = max(1, 3 * (ATT + ATT_Accessories) - A)
elif "CO" in Player_Accessories and "DX" not in Player_Accessories and Battle_Turn == 1:
Player_Damage = max(1, 2 * (ATT + ATT_Accessories) - A)
if "HU" in Player_Accessories and Battle_Turn==1:
NOW_HP=MAX_HP
H-=Player_Damage
Player_Damage = max(1, (ATT + ATT_Accessories) - A)
H -= Player_Damage
if H<=0:
if "HR" in Player_Accessories:
NOW_HP = min(NOW_HP + 3, MAX_HP)
if "EX" in Player_Accessories:
EXP+=int(1.2 * E)
elif "EX" not in Player_Accessories:
EXP += E
if EXP >= 5 * LV:
LV += 1 ; EXP = 0 ; MAX_HP += 5 ; NOW_HP = MAX_HP ; ATT += 2 ; DEF += 2
Answer=1
graph[y][x]='.'
break
NOW_HP -= Monster_Damage
if NOW_HP <= 0:
if "RE" in Player_Accessories:
NOW_HP = MAX_HP
y, x = start[0][0], start[0][1]
Player_Accessories.remove("RE")
else:
NOW_HP = 0
Answer=0
break
elif graph[y][x] == "@": # 주인공이 있던 칸이면 그냥 넘어감
pass
N,M=map(int,input().split())
graph=[ list(input()) for i in range(N)]
Move=deque(list(input()))
Monster={} ; Accessories={} ; Monster_count=0 ; Accessories_count=0 ; start=[]
for i in range(N):
for j in range(M):
if graph[i][j]=="&" or graph[i][j]=="M":
Monster_count+=1
elif graph[i][j]=="B":
Accessories_count+=1
elif graph[i][j]=="@":
start=[[i,j]]
for i in range(Monster_count):
Monster_Y,Monster_X,NAME,W,A,H,E=input().split() #W-공격력 , A-방어력 , H-최대 체력 , E-죽였을때 경험치
Monster_Y=int(Monster_Y) ; Monster_X=int(Monster_X) ; W=int(W) ; A=int(A) ; H=int(H) ; E=int(E)
Monster[(Monster_Y,Monster_X)]=[NAME,W,A,H,E] #몬스터의 체력은 변할수 있으므로 저장은 리스트로한다.
for i in range(Accessories_count):
"""
T='W'일때 공격력이 S 인 무기장착 , T='A' 인 경우 S인 방어구 장착
T='O' 인 경우 장신구 장착
"""
Accessories_Y,Accessories_X,T,S=input().split()
Accessories_Y=int(Accessories_Y) ; Accessories_X=int(Accessories_X)
if T=='W' or T=='A':
S=int(S)
Accessories[(Accessories_Y,Accessories_X)]=(T,S)
y,x=start[0][0],start[0][1]
LV=1 ; NOW_HP=20 ; MAX_HP=20 ; ATT=2 ; DEF=2 ; EXP=0 # 레벨 , 현재체력 , 최대체력 ,공격력 , 방어력 , 경험치
# 경험치 : 처음엔 레벨 1이며, 레벨 N에서 N+1이 되기 위한 필요 경험치는 5×N이다.
ATT_Accessories=0 ; DEF_Accessories=0 #무기 , 방어구
Player_Accessories=[] #플레이어의 악세서리 도구함 , 최대 4개까지 장착 가능
Answer=-1 # 모든 커맨드를 수행후 죽었거나 보스를 이기지 않았을 경우
count=0 # 턴 횟수 저장변수
while Move:
count+=1
Keyboard=Move.popleft()
if Keyboard=="R" and 0<=x+1<M and graph[y][x+1]!="#":
x+=1
RPG_Extreme()
elif Keyboard=="L" and 0<=x-1<M and graph[y][x-1]!="#":
x-=1
RPG_Extreme()
elif Keyboard=="U" and 0<=y-1<N and graph[y-1][x]!="#":
y-=1
RPG_Extreme()
elif Keyboard=="D" and 0<=y+1<N and graph[y+1][x]!="#":
y+=1
RPG_Extreme()
else:
if graph[y][x]=="^":
if "DX" in Player_Accessories:
NOW_HP -= 1
elif "DX" not in Player_Accessories:
NOW_HP -= 5
if NOW_HP <= 0:
if "RE" in Player_Accessories:
NOW_HP = MAX_HP
y, x = start[0][0], start[0][1]
Player_Accessories.remove("RE")
else:
NOW_HP = 0 # 종료 조건
Answer=2
graph[start[0][0]][start[0][1]] = '.'
break
if Answer==0: #몬스터한테 뒤졌을 경우 , 전투의 결과로 사망했을 경우 S는 몬스터의 이름, 가시 함정에 의해 사망했을 경우 S는 “SPIKE TRAP” 이 된다.
graph[start[0][0]][start[0][1]] = '.'
break
elif Answer==1: #보스 이겼을 경우
graph[start[0][0]][start[0][1]] = '.'
graph[y][x] = '@'
break
elif Answer==2: #트랩에 뒤졌을 경우
graph[start[0][0]][start[0][1]] = '.'
break
if Answer==-1:
graph[start[0][0]][start[0][1]] = '.'
graph[y][x] = '@'
for i in graph:
print(''.join(i).rstrip())
print("Passed Turns : %d"%(count))
print("LV : %d"%(LV))
print("HP : %d/%d"%(NOW_HP,MAX_HP))
print("ATT : %d+%d"%(ATT,ATT_Accessories))
print("DEF : %d+%d"%(DEF,DEF_Accessories))
print("EXP : %d/%d"%(EXP ,5*LV))
if Answer==1:
print("YOU WIN!")
elif Answer==0:
print("YOU HAVE BEEN KILLED BY %s.."%(NAME))# 죽인 사람 이름
elif Answer==2:
print("YOU HAVE BEEN KILLED BY SPIKE TRAP..")
elif Answer==-1:
print("Press any key to continue.")
📌 어떻게 접근할 것인가?
그냥 구현문제입니다.

처음엔 코드길이가 20000 B 이상 넘었는데 코드부분을 수정해서 8500 B 로 줄였습니다.
여라가지 고려해야할 사항들과 내가 푼 방법에 대해 이야기 해보도록 하겠습니다.
N,M=map(int,input().split())
세로, 가로를 먼저 입력받습니다.
graph=[ list(input()) for i in range(N)]
그래프를 입력받습니다.
Move=deque(list(input()))
이동 경로를 덱을 통해 입력받습니다.
Monster={} ; Accessories={} ; Monster_count=0 ; Accessories_count=0 ; start=[]
이후 그래프에있는 몬스터의 개수만큼 입력받고 , 악세서리의 개수만큼 입력받기 위해서
for i in range(N):
for j in range(M):
if graph[i][j]=="&" or graph[i][j]=="M":
Monster_count+=1
elif graph[i][j]=="B":
Accessories_count+=1
elif graph[i][j]=="@":
start=[[i,j]]
한번의 탐색을 통해 몬스터의 개수 , 악세서리의 개수 , 시작점을 체크 해줍니다.
for i in range(Monster_count):
Monster_Y,Monster_X,NAME,W,A,H,E=input().split() #W-공격력 , A-방어력 , H-최대 체력 , E-죽였을때 경험치
Monster_Y=int(Monster_Y) ; Monster_X=int(Monster_X) ; W=int(W) ; A=int(A) ; H=int(H) ; E=int(E)
Monster[(Monster_Y,Monster_X)]=[NAME,W,A,H,E] #몬스터의 체력은 변할수 있으므로 저장은 리스트로한다.
for i in range(Accessories_count):
"""
T='W'일때 공격력이 S 인 무기장착 , T='A' 인 경우 S인 방어구 장착
T='O' 인 경우 장신구 장착
"""
Accessories_Y,Accessories_X,T,S=input().split()
Accessories_Y=int(Accessories_Y) ; Accessories_X=int(Accessories_X)
if T=='W' or T=='A':
S=int(S)
Accessories[(Accessories_Y,Accessories_X)]=(T,S)
몬스터와 악세서리를 딕셔너리를 사용합니다.
딕셔너리의 키 값은 정수형태 뿐만 아니라 튜플도 넣을수 있어서 좌표값을 키 값으로 넣고
value 값은 그 몬스터의 이름 , 공격력 , 방어력 , 체력 ,경험치를 입력받습니다.
악세서리 또한 키 값을 좌표형태를 튜플로 넣고 악세서리 종류를 value 값으로 설정합니다.
y,x=start[0][0],start[0][1]
LV=1 ; NOW_HP=20 ; MAX_HP=20 ; ATT=2 ; DEF=2 ; EXP=0 # 레벨 , 현재체력 , 최대체력 ,공격력 , 방어력 , 경험치
# 경험치 : 처음엔 레벨 1이며, 레벨 N에서 N+1이 되기 위한 필요 경험치는 5×N이다.
ATT_Accessories=0 ; DEF_Accessories=0 #무기 , 방어구
Player_Accessories=[] #플레이어의 악세서리 도구함 , 최대 4개까지 장착 가능
Answer=-1 # 모든 커맨드를 수행후 죽었거나 보스를 이기지 않았을 경우
count=0 # 턴 횟수 저장변수
이후 초기 세팅을 해줍니다.
y,x 는 시작점 , 레벨 , 현재 체력 , 최대체력 , 공격력 , 방어력 , 경험치
그리고 악세서리무기 , 악세서리 방어구 , 악세서리 도구함을 설정해줍니다.
Answer는 게임결과를 담고 count 는 턴 횟수를 저장합니다.
함수를 통해 매번 이동할때마다 함수 하나를 만들어놓고
이름만 적어서 매번 바로 바로 호출할수 있도록 만들었습니다.
while Move:
count+=1
Keyboard=Move.popleft()
if Keyboard=="R" and 0<=x+1<M and graph[y][x+1]!="#":
x+=1
RPG_Extreme()
elif Keyboard=="L" and 0<=x-1<M and graph[y][x-1]!="#":
x-=1
RPG_Extreme()
elif Keyboard=="U" and 0<=y-1<N and graph[y-1][x]!="#":
y-=1
RPG_Extreme()
elif Keyboard=="D" and 0<=y+1<N and graph[y+1][x]!="#":
y+=1
RPG_Extreme()
이동경로를 입력받은 Move 변수가 길이가 0이 될때까지 while문을 사용합니다.
그리고 왼쪽부터 오른쪽으로 커맨드를 실행하기 때문에 popleft()를 사용해줍니다.
이후 상하좌우 4가지 경로에 대해 벽이 아니라 탐색가능하다면
함수 RPG_Extreme 를 실행해줍니다.
else:
if graph[y][x]=="^":
if "DX" in Player_Accessories:
NOW_HP -= 1
elif "DX" not in Player_Accessories:
NOW_HP -= 5
if NOW_HP <= 0:
if "RE" in Player_Accessories:
NOW_HP = MAX_HP
y, x = start[0][0], start[0][1]
Player_Accessories.remove("RE")
else:
NOW_HP = 0 # 종료 조건
Answer=2
graph[start[0][0]][start[0][1]] = '.'
break
이때 중요한것은 벽이 있어 움직이지 못할때 바닥이 가시함정이라면
가시함정으로 인해 피해를 한번 더 받게되고 턴이 하나 증가합니다.
따라서 else 문을 사용하여 가시함정이 있을경우와 이때 "DX" 장신구와 "RE" 장신구가 있을경우 예외처리를 해줍니다.
if Answer==0: #몬스터한테 뒤졌을 경우 , 전투의 결과로 사망했을 경우 S는 몬스터의 이름, 가시 함정에 의해 사망했을 경우 S는 “SPIKE TRAP” 이 된다.
graph[start[0][0]][start[0][1]] = '.'
break
elif Answer==1: #보스 이겼을 경우
graph[start[0][0]][start[0][1]] = '.'
graph[y][x] = '@'
break
elif Answer==2: #트랩에 뒤졌을 경우
graph[start[0][0]][start[0][1]] = '.'
break
while 문을 돌다가 만약 몬스터한테 죽거나 , 보스에게 이겼거나 트랩에 죽었을경우
결과를 담은 변수 Answer로 통해 확인합니다.
if Answer==-1:
graph[start[0][0]][start[0][1]] = '.'
graph[y][x] = '@'
while 문이 끝나고 Answer 값이 초기값과 같다면커맨드를 모두 수행했으니
현재 시작점을 변경해줍니다.
for i in graph:
print(''.join(i).rstrip())
print("Passed Turns : %d"%(count))
print("LV : %d"%(LV))
print("HP : %d/%d"%(NOW_HP,MAX_HP))
print("ATT : %d+%d"%(ATT,ATT_Accessories))
print("DEF : %d+%d"%(DEF,DEF_Accessories))
print("EXP : %d/%d"%(EXP ,5*LV))
if Answer==1:
print("YOU WIN!")
elif Answer==0:
print("YOU HAVE BEEN KILLED BY %s.."%(NAME))# 죽인 사람 이름
elif Answer==2:
print("YOU HAVE BEEN KILLED BY SPIKE TRAP..")
elif Answer==-1:
print("Press any key to continue.")
각 지점은 공백이 없이 바로 출력되어야 하므로 ''join(i) 를 사용하였고
턴 수 , 레벨, 체력 , 공격력 , 방어력 , 경험치를 필수적으로 출력해준뒤
Answer 값에 따라 결과값을 출력해줍니다.
def RPG_Extreme():
global NAME , NOW_HP,MAX_HP,DEF,ATT,ATT_Accessories,DEF_Accessories,EXP,LV,Player_Accessories,y,x,Answer
함수를 하나만 사용할것이고 변수들은 매번 값이 변할수 있으므로
그냥 global 을 사용했습니다.
if graph[y][x] == "&":
NAME,W, A, H, E = Monster[(y+1, x+1)][0],Monster[(y+1, x+1)][1], Monster[(y+1, x+1)][2], Monster[(y+1, x+1)][3], Monster[(y+1, x+1)][4] # W-공격력 , A-방어력 , H-최대 체력 , E-죽였을때 경험치
Battle_Turn=0
while True:
Battle_Turn+=1
Player_Damage=max(1,(ATT+ATT_Accessories)-A)
Monster_Damage=max(1,W-(DEF+DEF_Accessories))
if "CO" in Player_Accessories and "DX" in Player_Accessories and Battle_Turn==1:
Player_Damage=max(1,3*(ATT+ATT_Accessories)-A)
elif "CO" in Player_Accessories and "DX" not in Player_Accessories and Battle_Turn==1:
Player_Damage = max(1, 2 * (ATT + ATT_Accessories) - A)
H-=Player_Damage
if H<=0:
if "HR" in Player_Accessories:
NOW_HP = min(NOW_HP + 3, MAX_HP)
if "EX" in Player_Accessories:
EXP+=int(1.2 * E)
elif "EX" not in Player_Accessories:
EXP += E
if EXP >= 5 * LV:
LV += 1 ; EXP = 0 ; MAX_HP += 5 ; NOW_HP = MAX_HP ; ATT += 2 ; DEF += 2
graph[y][x] = '.'
break
NOW_HP-=Monster_Damage
if NOW_HP<=0:
if "RE" in Player_Accessories:
NOW_HP = MAX_HP
y, x = start[0][0], start[0][1]
Player_Accessories.remove("RE")
else:
NOW_HP=0
Answer=0
break
일반 몬스터와 전투 코드입니다.
먼저 딕셔너리를 통해 몬스터의 정보를 받은뒤 while 문을 통해 매번 턴을 주고 받습니다.
문제에서 주어진 몬스터의 체력이나 공격력 방어력등이 매우 작은 수 이기때문에
while 문을 사용해도 시간초과는 나지 않습니다.
처음 플레이어의 데미지와 몬스터의 데미지를 정해주고
만약 장신구가있으면 장신구에 따라 데미지를 2배 혹은 3배로 변경해줍니다.
그리고 플레이어가 선공이기 때문에 먼저 몬스터의 체력 H 를 깎아줍니다.
이후 몬스터의 체력이 0 이하일떄
HR 장신구가있으면 체력+3 회복 , EX 장신구가있으면 경험치 1.3배 흭득 , 레벨업을 했을경우 공격력 방어력 최대 체력 , 현재체력 증가 , 현재 경험치는 0으로 설정한 후
몬스터를 잡은 자리는 '.' 으로 처리해줍니다.
만약 몬스터가 플레이어의 체력을 공격해서 0 이하가 되는경우
부활옵션이 있는 RE 장신구가 있을경우 부활하고
그렇지 않을경우 게임에서 지게됩니다.
elif graph[y][x] == "B":
T, S = Accessories[(y+1, x+1)][0], Accessories[(y+1, x+1)][1]
if T == "W":
ATT_Accessories = int(S)
elif T == "A":
DEF_Accessories = int(S)
elif T == "O":
if len(Player_Accessories) < 4:
if S not in Player_Accessories:
Player_Accessories.append(S)
graph[y][x] = "."
만약 장신구가있다면
딕셔너리를 통해 y,x 좌표값으로 장신구의 정보를 받아온 후
장신구의 크기가 4개 미만이고 중복이 아니라면 담습니다.
이후 그래프는 '.' 처리 해줍니다.
elif graph[y][x] == "^":
if "DX" in Player_Accessories:
NOW_HP -= 1
elif "DX" not in Player_Accessories:
NOW_HP -= 5
if NOW_HP <= 0:
if "RE" in Player_Accessories:
NOW_HP = MAX_HP
y, x = start[0][0], start[0][1]
Player_Accessories.remove("RE")
else:
NOW_HP = 0 # 종료 조건
Answer=2
트랩 조건입니다.
DX 장신구가있으면 체력을 1만 깎고 아니면 5를 깎습니다.
만약 체력이 0 이하면 RE 장신구가있으면 부활을 하고
그렇지 않으면 죽습니다.
매번 죽었을때나 보스를 잡았을때 게임의 결과를 담는 Answer 변수를 꼭 변경해주어야 합니다.
elif graph[y][x] == "M":
NAME,W, A, H, E = Monster[(y+1, x+1)][0],Monster[(y+1, x+1)][1], Monster[(y+1, x+1)][2], Monster[(y+1, x+1)][3], Monster[(y+1, x+1)][4] # W-공격력 , A-방어력 , H-최대 체력 , E-죽였을때 경험치
Battle_Turn = 0
while True:
Battle_Turn += 1
Player_Damage = max(1, (ATT + ATT_Accessories) - A)
Monster_Damage=max(1,W-(DEF+DEF_Accessories))
if "CO" in Player_Accessories and "DX" in Player_Accessories and Battle_Turn == 1:
Player_Damage = max(1, 3 * (ATT + ATT_Accessories) - A)
elif "CO" in Player_Accessories and "DX" not in Player_Accessories and Battle_Turn == 1:
Player_Damage = max(1, 2 * (ATT + ATT_Accessories) - A)
if "HU" in Player_Accessories and Battle_Turn==1:
NOW_HP=MAX_HP
H-=Player_Damage
Player_Damage = max(1, (ATT + ATT_Accessories) - A)
H -= Player_Damage
if H<=0:
if "HR" in Player_Accessories:
NOW_HP = min(NOW_HP + 3, MAX_HP)
if "EX" in Player_Accessories:
EXP+=int(1.2 * E)
elif "EX" not in Player_Accessories:
EXP += E
if EXP >= 5 * LV:
LV += 1 ; EXP = 0 ; MAX_HP += 5 ; NOW_HP = MAX_HP ; ATT += 2 ; DEF += 2
Answer=1
graph[y][x]='.'
break
NOW_HP -= Monster_Damage
if NOW_HP <= 0:
if "RE" in Player_Accessories:
NOW_HP = MAX_HP
y, x = start[0][0], start[0][1]
Player_Accessories.remove("RE")
else:
NOW_HP = 0
Answer=0
break
보스전투는 그저 일반 몬스터전투에다가 HU 장신구 여부만더 판별 해주면됩니다.
그리고 만약 이겼을 경우 게임의 결과를 담는 변수 Answer 를 1로 만들어 줍니다.
처음에는 전투 과정을 공식 하나로 바로 판별할려했으나
공식을 잘못세워서 그냥 편하게 턴을 주고받는식으로 계속 진행하기로 했습니다.
이 문제는 시간제한도 5초일뿐더러 수의 범위가 매우 작으니 어떻게 실행시간을 빠르게 할까 보다는
어떻게 정확하게 코드를 작성할까에 초점을 두는게 좋은것 같습니다.
예를들면
등등 아주 많이 고려해야할 부분이 있지만 문제를 천천히 읽고 코드를 천천히 작성한다면 충분히 풀만한 문제인것 같습니다. 나중에 함수 캡슐화 또는 객체지향적인 코드를 작성할려고 연습할때
이 문제를 풀면 많은 도움이 될거같습니다.