co-cherry
[SWEA] 1873. 배틀 필드 본문
SW Expert Academy
SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!
swexpertacademy.com
문제를 이해하는 것부터가 굉장히 오래 걸렸다...
혼자 푸는 방식이 어려워서 claude와 같이 푼 문제다. 나중에 꼭 한번 혼자 풀어봐야겠다.
풀이 방식
일단 문제 정의부터 이해하자.
- ^
- <
- >
- v
은 탱크가 보는 방향을 뜻한다.
탱크의 이동은 U(상)/D(하)/L(좌)/R(우) 로 이루어진다.
- . (평지) 플레이어가 유일하게 이동 가능
- * (벽돌 벽) 포탄을 통해 부수면 평지로 바뀌는 땅
- # (강철 벽) 포탄을 통해 부술 수 없는 땅
- - (물) 지나갈 수 없는 땅
결론적으로 탱크가 이동할 수 있는 칸은 . 외에는 없다.
또한, 포탄으로 부술 수 있는 땅 또한 * 밖에 없으며, 하나의 포탄은 하나의 벽만 부술 수 있다.
우리는 맵의 크기(h, w)와 지형의 형태를 먼저 받고, 또 사용자의 이동 횟수와 포탄의 움직임에 관한 문자열을 추가로 받는다.
우리는 주어진 지형의 형태에서 포탄이 어떻게 움직이냐에 따른 결과를 다시 n x n 배열의 형태로 보여주면 되는 것이다.
그럼 문제를 해결해보자.
1. 사용자(탱크)의 위치 계산하기
탱크는 위에서 제시한 ^/>/</v 의 형태를 뜻한다.
탱크의 초기 위치를 계산하기 위해 h x w 형태의 반복문을 돌린다.
만약 해당 좌표의 값이 ^/>/v 의 형태라면 탱크의 위치라는 것을 의미한다.
# 초기 위치 찾기
for i in range(h):
for j in range(w):
if arr[i][j] in ['^', 'v', '<', '>']:
x, y = i, j
cur_direction = tank_to_cmd[arr[i][j]]
break
앞서 부가적인 코드들은 제외하고 일단 좌표를 찾은 것에 집중하자.
2. 명령 처리하기
이제 현재 위치에서 문자열로 주어진 명령을 처리해야 한다.
명령은 크게 이동(UDLR)과 슈팅(S) 두 가지의 경우로 나뉜다.
여기에서 생각해야 할 점은 이동은 탱크의 위치가 이동되는 것이지만, 슈팅은 포탄의 위치가 이동되는 것이다.
for move in moves:
if move == 'S':
dx, dy = directions[cur_direction][0], directions[cur_direction][1]
nx, ny = x + dx, y + dy
while 0 <= nx < h and 0 <= ny < w:
if arr[nx][ny] == '*':
arr[nx][ny] = '.'
break
elif arr[nx][ny] == '#':
break
nx += dx
ny += dy
else:
dx, dy, tank_shape = directions[move]
cur_direction = move
arr[x][y] = tank_shape
nx, ny = x + dx, y + dy
if 0 <= nx < h and 0 <= ny < w and arr[nx][ny] == '.':
arr[x][y] = '.'
x, y = nx, ny
arr[x][y] = tank_shape
먼저 앞서 다룬 달팽이 숫자처럼 UDLR 값에 따른 좌표 이동을 어떻게 할 것인가? 라는 문제에 봉착했다.
달팽이 숫자 문자와 다르게 문자열 값에 따라 특정 패턴 없이 자유로이 이동하므로 Dictionary를 사용하는 방법을 택했다.
directions = {
'U': (-1, 0, '^'),
'D': (1, 0, 'v'),
'L': (0, -1, '<'),
'R': (0, 1, '>')
}
첫번째 값과 두번째 값을 dx, dy로 설정해 이동하는 방법을 택한 것이다.
또한 해당 방향으로 이동한다면 탱크의 방향이 바뀌므로 이를 저장하기 위해 마지막으로 탱크가 바라보는 방향까지 적어줬다.
else:
dx, dy, tank_shape = directions[move]
cur_direction = move
arr[x][y] = tank_shape
nx, ny = x + dx, y + dy
if 0 <= nx < h and 0 <= ny < w and arr[nx][ny] == '.':
arr[x][y] = '.'
x, y = nx, ny
arr[x][y] = tank_shape
다시 해당 부분을 보면, directions[move] 를 통해 dx, dy, tank_shape를 받는 것을 볼 수 있다.
그리고 nx, ny가 x, y에서 dx, dy를 적용해 이동할 좌표 값인데
이미 이동한 좌표가 0 이하 h x w 이상일 수 없으며, 평지가 아닌 땅은 이동할 수 없으므로 이를 고려해야 한다.
조건에 부합한다면 기존에 탱크가 있던 자리는 다시 평지로, 탱크가 이동할 위치에는 이전에 저장해둔 tank_shape를 통해 값을 갱신한다.
이번에는 슈팅 부분을 다뤄보자.
if move == 'S':
dx, dy = directions[cur_direction][0], directions[cur_direction][1]
nx, ny = x + dx, y + dy
while 0 <= nx < h and 0 <= ny < w:
if arr[nx][ny] == '*':
arr[nx][ny] = '.'
break
elif arr[nx][ny] == '#':
break
nx += dx
ny += dy
슈팅 또한 포탄의 이동을 위해 dx, dy를 받아온다.
여기서 cur_direction라는 변수를 다루는데 이 변수는 초기 탱크 위치를 계산할 때도, 좌표 이동을 계산할 때도 사용하던 변수이다.
이 변수는 포탄을 쏠 때 포탄이 어떤 방향으로 나아가야 하는가? 를 위해 사용하는 변수이다.
처음 사용자가 바로 S 을 통해 슈팅할 수도 있고, 이동 후, 슈팅할 수도 있으므로 초기 값 계산 시와 위치 갱신 시마다 값을 업데이트 한다.
이번에 다루는 nx, ny는 앞에서 언급했듯, 포탄의 위치 이동 값이다.
포탄 또한 지형을 벗어나면 아무 일도 일어나지 않으므로 h x w 지형 이내에서만 계산한다.
포탄은 벽에 부딪히기 전까지 계속 이동하므로 while 문을 이용해 dx, dy 만큼 계속 더해 이동한다.
만약 부딪힌 벽이 벽돌 벽이라면 해당 벽을 평지로 바꾸고 강철 벽이라면 아무 일도 일어나지 않는다.
마지막으로 추가적으로, 초기 위치를 찾을 때, tank_to_cmd 라는 게 등장하는데 이는 초기 탱크 값이 ^ > < v 로 지정되어 있어
초기 탱크의 방향을 cur_direction에 U/D/L/R 의 형태로 저장하기 위해 사용한 것이다.
tank_to_cmd = {
'^': 'U',
'v': 'D',
'<': 'L',
'>': 'R'
}
for i in range(h):
for j in range(w):
if arr[i][j] in ['^', 'v', '<', '>']:
x, y = i, j
cur_direction = tank_to_cmd[arr[i][j]]
break
최종적으로 코드를 보면 다음과 같다.
T = int(input())
for test_case in range(1, T + 1):
directions = {
'U': (-1, 0, '^'),
'D': (1, 0, 'v'),
'L': (0, -1, '<'),
'R': (0, 1, '>')
}
tank_to_cmd = {
'^': 'U',
'v': 'D',
'<': 'L',
'>': 'R'
}
h, w = map(int, input().split())
arr = []
for i in range(h):
arr.append(list(input()))
m = int(input())
moves = list(input())
# 초기 위치 찾기
for i in range(h):
for j in range(w):
if arr[i][j] in ['^', 'v', '<', '>']:
x, y = i, j
cur_direction = tank_to_cmd[arr[i][j]]
break
# 명령 처리
for move in moves:
if move == 'S':
dx, dy = directions[cur_direction][0], directions[cur_direction][1]
nx, ny = x + dx, y + dy
while 0 <= nx < h and 0 <= ny < w:
if arr[nx][ny] == '*':
arr[nx][ny] = '.'
break
elif arr[nx][ny] == '#':
break
nx += dx
ny += dy
else:
dx, dy, tank_shape = directions[move]
cur_direction = move
arr[x][y] = tank_shape
nx, ny = x + dx, y + dy
if 0 <= nx < h and 0 <= ny < w and arr[nx][ny] == '.':
arr[x][y] = '.'
x, y = nx, ny
arr[x][y] = tank_shape
print(f'#{test_case}')
for i in range(h):
print(''.join(arr[i]))
비효율적으로 보일 수 있겠으나, 직관적으로 이해하기에 더 좋은 방법을 모르겠다. 의견이 있다면 제시해주시면 좋겠습니다!
'Python' 카테고리의 다른 글
| [SWEA] 2805. 농작물 수확하기 (0) | 2026.05.21 |
|---|---|
| [SWEA] 1974. 스도쿠 검증 (0) | 2026.05.20 |
| [SWEA] 1954. 달팽이 숫자 (0) | 2026.05.20 |
| [SWEA] 26502. 쉬운 삼각형 (0) | 2026.05.19 |
| [SWEA] 26504. MST 만들기 (0) | 2026.05.06 |
