컴퓨터 & 코딩/Python

[Python] Advent of Code 2022 - Day 9

구로그 2022. 12. 14. 02:45
728x90

head가 인풋에 따라 위치를 이동하는데 이에 따른 tail의 경로를 파악하여 tail이 훑고간 위치가 총 몇 군데 되는지 계산하는게 이번 과제의 문제였다. 

 

문제를 처음 봤을 때는, 리스트로 하나의 필드를 만들어서 움직임을 줘야하나 했지만 인덱스가 늘어날 때마다 요소를 하나씩 추가하는 게 까다로울 것 같아서 head와 tail의 좌표만 리스트로 담아놓았다. pos[0]은 x좌표를, pos[1]은 y좌표를 나타낸다. 

file = open("input/day9.txt", "r")
data = file.read().splitlines()

motions_list = []

# split 
for motion in data:
    motions_list.append(motion.split())

head_pos = [0, 0]
tail_pos = [0, 0]


# function for tail 
def tail_move(direction):
    match direction:
        case "R":
            if head_pos[0] - tail_pos[0] == 2 and head_pos[1] - tail_pos[1] == 0:
                tail_pos[1] += 1
            if head_pos[0] - tail_pos[0] == 2 and head_pos[1] - tail_pos[1] == -1:
                tail_pos[0] += 1
                tail_pos[1] -= 1
            if head_pos[0] - tail_pos[0] == 2 and head_pos[1] - tail_pos[1] == 1:
                tail_pos[0] += 1
                tail_pos[1] += 1
        case "L":
            if head_pos[0] - tail_pos[0] == -2 and head_pos[1] - tail_pos[1] == 0:
                tail_pos[1] -= 1
            if head_pos[0] - tail_pos[0] == -2 and head_pos[1] - tail_pos[1] == 1:
                tail_pos[0] -= 1
                tail_pos[1] += 1
            if head_pos[0] - tail_pos[0] == -2 and head_pos[1] - tail_pos[1] == -1:
                tail_pos[0] -= 1
                tail_pos[1] -= 1
        case "U":
            if head_pos[1] - tail_pos[1] == 2:
                tail_pos[1] += 1
                if head_pos[0] - tail_pos[0] == 1:
                    tail_pos[0] += 1
                elif head_pos[0] - tail_pos[0] == -1:
                    tail_pos[0] -= 1
        case "D":
            if head_pos[1] - tail_pos[1] == -2:
                tail_pos[1] -= 1
                if head_pos[0] - tail_pos[0] == 1:
                    tail_pos[0] += 1
                elif head_pos[0] - tail_pos[0] == -1:
                    tail_pos[0] -= 1
    trace.append(list(tail_pos))

# function for head 
def head_move(direction, number):
    for i in range(1, number+1):
        match direction:
            case "R":
                head_pos[0] += 1
            case "L":
                head_pos[0] -= 1
            case "U":
                head_pos[1] += 1
            case "D":
                head_pos[1] -= 1
        tail_move(direction)


trace = []

# function for execution 
def play(move_list):
    for motion in move_list:
        head_move(motion[0], int(motion[1]))


play(motions_list)

new = []

# get answer 
for each in trace:
    if each not in new:
        new.append(each)

# list(map(list, set(map(tuple, trace))))

print(len(new))

# split: 먼저 인풋의 방향과 숫자를 따로 떼어서 motions_list 리스트에 담는다. 

# function for head: head의 경로에 대한 함수이다. motions_list에 있는 데이터에 따라 head_pos 숫자가 바뀐다. 

# function for tail: head의 경로에 대한 tail 경로 함수이다. head_pos와 tail_pos의 차이에 따라 변하는 값이 달라진다. tail은 head와 상하좌우 그리고 대각선으로 맡닿아 있으면 움직이지 않고 다음과 같은 경우에만 움직인다. 

 tail의 좌표를 기준으로 head와 x축 또는 y축이 2칸 차이가 나면 그때 tail이 움직이는 것이다. 

이에 맞춰서 if 문을 써준다. 처음에는 if 문을 짜고 방향을 안에 넣었는데 먼저 방향으로 match case를 짜고 그 안에 if 문을 넣는 방식으로 구성을 바꾸었다. 그리고 if-elif를 썼을 때는 제대로 안 돌 던게 다수의 if 문으로만 구성했더니 답이 나왔다. 아직 이유를 모르겠다. tail_move 함수의 마지막 동작은 바뀐 모든 tail의 좌표들을 하나의 리스트(trace)에 넣어주는 것이다. 

 

head가 먼저 움직인 후 tail이 움직여야 하기 때문에 head_move 함수 가장 마지막 부분에 tail_move 함수를 놓았다. 그리고 이 head_move 함수가 모든 인풋 데이터를 돌며 처리가 될 수 있도록 for문을 담은 play 함수에 넣고 돌려준다. 

 

# get answer: 마지막으로 tail의 좌표들이 담겨 있는 trace를 돌며 중복된 좌표는 빼준다. 지난번에 리스트에 있는 중복된 요소들을 제거하면서 set()을 썼는데 이번에는 nested list라서 그런지 set() 으로 정리가 되지 않았다. 그래서 새로운 new라는 리스트를 만든 후 trace를 돌면서 중복되지 않은 값만 리스트에 넣어주는 방식으로 정리를 해봤는데 list(map(list, set(map(tuple, <list>))))로 하는 방법도 있었다. 정확하게 어떤 방식으로 되는건지 몰라서 써보진 않았다. 

반응형