PS
싸움땅 [삼성 기출]
깊게 생각하고 최선을 다하자
2023. 10. 11. 21:10
1. 문제 접근 방법
- 구현 문제이다. 디테일한 요구 사항을 정확하고 제대로 구현하는 것이 중요한 문제이다.
총의 정보는 gunsBoard라는 3차원 배열을 만들어서, 관리했고,
중간 중간에 정보가 바뀔때마다, sort를 해줬다.
- 메소드 하나하나 디테일하게 주석을 달아서 정리해봐야겠다.
- 시간 복잡도를 반드시 꼼꼼하게 계산하도록 하자.
2. 코드
N, M, K = map(int, input().split())
gunsBoard = [[[] for _ in range(N)] for _ in range(N)]
dx = [-1, 0, 1, 0]
dy = [0, 1, 0, -1]
board = []
players = []
## points를 기록하기 위한 배열
points = [0]*M
## 처음에 입력된 총의 정보를 board에 넣어준다
## 그리고 이 정보를 gunsBoard에 옮겨서 넣어준다.
## gunsBoard는 각각의 좌표에서 리스트를 가지는 3차원 리스트이다.
for i in range(N):
row = list(map(int, input().split()))
board.append(row)
for i in range(N):
for j in range(N):
if board[i][j] != 0:
gunsBoard[i][j].append(board[i][j])
## 사람들의 정보를 입력해준다
## 이 때, 중요한 것은 0~N-1의 좌표를 활용했으므로
## x,y를 각각 -1해서 넣어줘야 한다.
for i in range(M):
x, y, d, s = map(int, input().split())
players.append([x-1, y-1, d, s, 0])
## 선택된 인덱스의 player를 이동시킨다.
def move(num, player):
x = player[0]
y = player[1]
d = player[2]
## 현재 방향을 기준으로 다음 좌표를 정한다
nx = x + dx[d]
ny = y + dy[d]
## 만약 다음 좌표가 board의 바깥이라면,
## 방향을 반대로 바꿔서 이동을 시켜준다.
if not (0<=nx and nx<N and 0<=ny and ny<N):
nx -= dx[d]
ny -= dy[d]
if d == 0:
d = 2
elif d == 1:
d = 3
elif d == 2:
d = 0
elif d == 3:
d = 1
nx += dx[d]
ny += dy[d]
## 여기서 player의 정보를 업데이트해주는 것은 매우 중요하다.
## 이런 디테일과 꼼꼼함이 매우 중요하다.
player[2] = d
## player가 이동하고 나면,
## 마찬가지로 player의 좌표도 업데이트해준다.
player[0] = nx
player[1] = ny
opponent = -1
## 만약에 내가 이동한 좌표에, 다른 player가 존재한다면,
## 해당 player의 좌표를 리턴하고, 없으면 -1을 리턴한다.
## 이건 따로 메소드로 빼도 괜찮을 것 같다.
for i in range(M):
if num != i:
player2 = players[i]
x2 = player2[0]
y2 = player2[1]
if player[0] == player2[0] and player[1] == player2[1]:
opponent = i
break
return opponent
## player가 총이 없다면, 총을 장착할지,
## 혹은 총이 있다면, 새로운 총으로 교체할지 판단하기 위한 메소드이다.
def getGun(player):
x = player[0]
y = player[1]
g = player[4]
gunsInfo = gunsBoard[x][y]
## 현재 위치에 들어 있는 총의 개수를 확인
## 이 개수를 확인하는 것은 필수이다.
## 왜냐하면, 개수가 있을 때만, 총에 관한 판단이 가능하기 때문이다.
## 이것 또한 꼭 챙겨야 하는 디테일이다.
infoLen = len(gunsInfo)
if infoLen > 0:
if g == 0:
player[4] = gunsInfo[infoLen-1]
gunsInfo = gunsInfo[0:infoLen-1]
else:
if g < gunsInfo[infoLen-1]:
player[4] = gunsInfo[infoLen-1]
gunsInfo = gunsInfo[0:infoLen-1]
gunsInfo.append(g)
gunsInfo.sort()
## 바뀐 총의 정보를 반드시 업데이트해줘야 한다
## 이것도 꼭 챙겨야하는 것이다.
## 구현은 꼼꼼함과 디테일의 싸움이다.
gunsBoard[x][y] = gunsInfo
def checkPlayer(num, x, y):
for i in range(len(players)):
if i!= num:
if x == players[i][0] and y == players[i][1]:
return True
return False
## 싸움에서 진 player를 이동시키기 위한 메소드
## 총이 있다면, 총을 버려야 한다.
## 그리고, 이동가능한 위치를 판단해서 이동을 해야 한다
def moveLosePlayer(num, player):
x = player[0]
y = player[1]
d = player[2]
g = player[4]
if g != 0:
gunsBoard[x][y].append(g)
gunsBoard[x][y].sort()
player[4] = 0
cnt = 0
## 이동 가능한 위치를 판단하기 위해서
## 4방향으로 돌면서 판단을 해준다.
while cnt != 4:
nx = x + dx[d]
ny = y + dy[d]
## board안에 있는지, 그리고 해당 칸이 비었는지 판단을 해줘야 한다
## 빈 칸으로만 이동할 수 있다
if (0<=nx and nx<N and 0<=ny and ny<N) and checkPlayer(num, nx, ny) == False:
player[0] = nx
player[1] = ny
player[2] = d
gunsInfo = gunsBoard[nx][ny]
infoLen = len(gunsInfo)
if infoLen > 0:
player[4] = gunsInfo[infoLen-1]
gunsInfo = gunsInfo[0:infoLen-1]
gunsBoard[nx][ny] = gunsInfo
## break문을 여기에 걸어줘야 한다
## if문 안에 걸면 안된다
break
else:
d += 1
d %= 4
cnt += 1
## 싸움과 관련한 메소드
def fight(num, player, num2, player2):
attackSum = player[3] + player[4]
attackSum2 = player2[3] + player2[4]
initAttack = player[3]
initAttack2 = player2[3]
## print("attackSum, attackSum2")
## print(attackSum, attackSum2)
if (attackSum > attackSum2) or ((attackSum == attackSum2) and (initAttack > initAttack2)):
points[num] += (attackSum-attackSum2)
moveLosePlayer(num2, player2)
getGun(player)
else:
points[num2] += (attackSum2-attackSum)
moveLosePlayer(num, player)
getGun(player2)
round = 1
while True:
if round == K+1:
break
for i in range(M):
player = players[i]
opponent = move(i, player)
if opponent == -1:
getGun(player)
else:
fight(i, player, opponent, players[opponent])
round += 1
for i in range(M):
print(points[i], end=' ')