문제
플레이어 이동
- 각 플레이어는 자신이 향하고 있는 방향으로 한 칸씩 이동합니다.
- 만약 격자를 벗어나면 반대 방향으로 방향을 바꾸고 한 칸 이동합니다.
이동 후 처리
- 다른 플레이어가 없을 경우: 해당 칸에 총이 있는지 확인하여, 총을 획득합니다.
- 이미 총을 가지고 있다면, 더 공격력이 높은 총을 획득하고 기존 총은 내려둡니다.
- 다른 플레이어가 있을 경우: 두 플레이어가 싸움을 벌입니다.
- 싸움 순서: 총을 줍기 전에 먼저 싸움을 진행합니다.
전투 규칙
- 플레이어의 초기 능력치와 총의 공격력 합산이 더 높은 플레이어가 승리합니다.
- 승리한 플레이어는 두 능력치의 차이만큼 포인트를 획득합니다.
- 패배한 플레이어는 총을 해당 위치에 내려놓고, 본인이 향한 방향으로 한 칸 이동합니다.
- 이동하려는 칸에 다른 플레이어가 있거나 격자를 벗어나면, 오른쪽으로 90도씩 회전하여 빈 칸이 보이면 그쪽으로 이동합니다.
전투 종료 후
- 패배한 플레이어는 이동한 칸에 총이 있다면 가장 공격력이 높은 총을 획득합니다.
- 이긴 플레이어는 그 칸에 떨어진 총 중 가장 공격력이 높은 총을 선택하고, 나머지 총은 내려둡니다.
- 패배한 플레이어의 총이 더 공격력이 높을 경우, 승리한 플레이어가 그 총을 가져갈 수 있습니다.
풀이
우선 플레이어와 총을 구분해서 관리하였다.
플레이어는 딕셔너리를 사용하여 관리하였고,
player = {idx: [y - 1, x - 1, d, s, 0] for idx, (x, y, d, s) in enumerate(temp_player)}
총은 한 좌표에 여러개의 총이 있을 수 있기 때문에 3차원 리스트를 이용하여 관리하였다.
arr = [[[num] for num in row] for row in temp_arr]
그리고 해당 문제에서 설명하는 (x,y) 좌표는 우리가 이해하는 (x,y)와 반대라고 생각하면 된다. (덕분에 헷갈림)
문제에서 설명하는대로 구현하면 되는데, 관리해야 할 변수가 너무 많다보니까 디버깅 하는데 오래걸렸다.
구현 문제를 풀때는 정신을 똑바로 차리고, ctrl +c ctrl + v 는 사용하지 않아야겠다는 걸 또 한 번 느꼈다.
1. 플레이어 이동
move_player() 함수에서 구현됩니다. 각 플레이어를 순서대로 이동시키고, 이동 후 다른 플레이어와의 충돌 여부를 확인합니다.
def move_player():
# 중략...
for idx, (x, y, d, s, g) in player.items():
# 이동 로직
# 충돌 확인
user_idx = check_user(player, nx, ny, idx)
if user_idx != -1:
player, arr, results = fight_player(player, idx, user_idx, arr, results)
else:
player[idx], arr = get_gun(player[idx], arr)
2. 총 휙득
get_gun() 함수에서 처리됩니다. 플레이어가 이동한 위치에 총이 있으면 가장 강력한 총을 획득합니다.
def get_gun():
# 중략...
if arr[y][x] and g < arr[y][x][0]:
temp_ = arr[y][x]
if g != 0:
temp_.append(g)
g = arr[y][x][0]
arr[y][x] = sorted(temp_[1:], reverse=True)
3. 플레이어간 전투
fight_player() 함수에서 구현됩니다. 두 플레이어의 전투력을 비교하여 승자를 결정하고, 점수를 갱신합니다.
def fight_player():
# 중략...
user_1_power = user_1[3] + user_1[4]
user_2_power = user_2[3] + user_2[4]
if user_1_power > user_2_power:
results[idx_1] += (user_1_power - user_2_power)
player, arr = end_game(idx_1, idx_2, arr, player)
4. 전투 후 처리
end_game() 함수에서 승자와 패자를 처리합니다. 패자는 총을 내려놓고 이동하며, 승자는 가장 강력한 총을 획득합니다.
def end_game():
# 중략..
# 패배자 총 내려놓기
loser_gun = loser[4]
loser[4] = 0
guns = arr[y][x]
if loser_gun:
guns.append(loser_gun)
# 패배자 이동
while True:
nx, ny = x + DX[d], y + DY[d]
if 0 <= nx < n and 0 <= ny < n:
if check_user(nx, ny):
# 이동 및 총 획득
break
d = (d + 1) % 4
# 승리자 총 줍기
winner, arr = get_gun(winner, arr)
코드
from collections import deque
from typing import List, Tuple, Dict
# 방향 상수 (상, 우, 하, 좌)
DX = [0, 1, 0, -1]
DY = [-1, 0, 1, 0]
def read_input() -> Tuple[int, int, int, List[List[int]], List[List[int]]]:
"""입력을 받아 배열의 크기, 플레이어 정보를 반환하는 함수"""
n, m, k = map(int, input().split()) # n: 격자 크기, m: 플레이어 수, k: 턴 수
arr = [list(map(int, input().split())) for _ in range(n)] # 격자 상태
player = [list(map(int, input().split())) for _ in range(m)] # 플레이어 상태
return n, m, k, arr, player
def check_user(player: Dict[int, List[int]], x: int, y: int, u_idx: int) -> int:
"""같은 위치에 있는 다른 플레이어가 있는지 확인하는 함수"""
for idx, (xx, yy, d, s, g) in player.items():
if idx == u_idx:
continue
if (xx, yy) == (x, y):
return idx
return -1
def move_player(arr: List[List[List[int]]], player: Dict[int, List[int]], results: List[int]) -> Tuple[List[List[List[int]]], Dict[int, List[int]], List[int]]:
"""플레이어를 이동시키는 함수"""
n = len(arr)
for idx, (x, y, d, s, g) in player.items():
# 한 칸 이동
nx, ny = x + DX[d], y + DY[d]
# 이동 가능한 경우
if 0 <= nx < n and 0 <= ny < n:
player[idx] = [nx, ny, d, s, g]
# 이동 불가능한 경우 반대 방향으로 이동
else:
d = (d + 2) % 4
nx, ny = x + DX[d], y + DY[d]
player[idx] = [nx, ny, d, s, g]
# 다른 플레이어 확인 및 싸움 처리
user_idx = check_user(player, nx, ny, idx)
if user_idx != -1:
player, arr, results = fight_player(player, idx, user_idx, arr, results)
else:
# 총을 줍는 처리
player[idx], arr = get_gun(player[idx], arr)
return arr, player, results
def end_game(idx_1: int, idx_2: int, arr: List[List[List[int]]], player: Dict[int, List[int]]) -> Tuple[Dict[int, List[int]], List[List[List[int]]]]:
"""게임에서 승자와 패자를 처리하는 함수"""
winner = player[idx_1]
loser = player[idx_2]
x, y = winner[0], winner[1]
n = len(arr)
# 패배자는 총을 내려둠
loser_gun = loser[4]
loser[4] = 0
guns = arr[y][x]
if loser_gun:
guns.append(loser_gun)
arr[y][x] = sorted(guns, reverse=True)
def check_user(nx: int, ny: int) -> bool:
"""해당 좌표에 다른 플레이어가 있는지 확인"""
for idx, (xx, yy, _, _, _) in player.items():
if idx == idx_2:
continue
if (xx, yy) == (nx, ny):
return False
return True
# 패배자 이동 처리
x, y, d, s, g = loser
while True:
nx, ny = x + DX[d], y + DY[d]
if 0 <= nx < n and 0 <= ny < n:
if check_user(nx, ny):
loser = [nx, ny, d, s, arr[ny][nx][0]] if arr[ny][nx] else [nx, ny, d, s, 0]
arr[ny][nx] = arr[ny][nx][1:] if arr[ny][nx] else []
break
d = (d + 1) % 4
# 승리자 총 줍기
winner, arr = get_gun(winner, arr)
player[idx_1], player[idx_2] = winner, loser
return player, arr
def fight_player(player: Dict[int, List[int]], idx_1: int, idx_2: int, arr: List[List[List[int]]], results: List[int]) -> Tuple[Dict[int, List[int]], List[List[List[int]]], List[int]]:
"""플레이어 간 싸움 처리"""
user_1 = player[idx_1]
user_2 = player[idx_2]
user_1_power = user_1[3] + user_1[4] # 사용자 1의 총합 전투력
user_2_power = user_2[3] + user_2[4] # 사용자 2의 총합 전투력
if user_1_power > user_2_power:
results[idx_1] += (user_1_power - user_2_power)
player, arr = end_game(idx_1, idx_2, arr, player)
elif user_1_power < user_2_power:
results[idx_2] += (user_2_power - user_1_power)
player, arr = end_game(idx_2, idx_1, arr, player)
else:
if user_1[3] > user_2[3]:
player, arr = end_game(idx_1, idx_2, arr, player)
else:
player, arr = end_game(idx_2, idx_1, arr, player)
return player, arr, results
def get_gun(user: List[int], arr: List[List[List[int]]]) -> Tuple[List[int], List[List[List[int]]]]:
"""플레이어가 해당 위치에서 총을 줍는 함수"""
x, y, d, s, g = user
if arr[y][x] and g < arr[y][x][0]:
temp_ = arr[y][x]
if g != 0:
temp_.append(g)
g = arr[y][x][0]
arr[y][x] = sorted(temp_[1:], reverse=True)
user = [x, y, d, s, g]
return user, arr
def main() -> None:
"""메인 함수: 시뮬레이션 실행 및 결과 출력"""
n, m, k, temp_arr, temp_player = read_input()
results = [0] * m
# 총이 여러 개 있을 수 있으므로 arr 배열을 다차원 리스트로 변환
arr = [[[num] for num in row] for row in temp_arr]
# 플레이어를 dict로 관리
player = {idx: [y - 1, x - 1, d, s, 0] for idx, (x, y, d, s) in enumerate(temp_player)}
# k번의 턴 동안 플레이어 이동 및 처리
for _ in range(k):
arr, player, results = move_player(arr, player, results)
print(" ".join(map(str, results)))
if __name__ == "__main__":
main()
'파이썬 > 코드트리' 카테고리의 다른 글
코드트리 - 포탑 부수기 (6) | 2024.10.07 |
---|---|
[python] 코드트리 - 코드트리 빵 (9) | 2024.10.01 |
[python] 코드트리 - 나무박멸 (0) | 2024.09.28 |
[python] 코드트리 - 꼬리잡기놀이 (2) | 2024.09.26 |
[python] 코드 트리 - 예술성 (0) | 2024.09.24 |