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=' ')