코딩 테스트

[코드트리챌린지] 재귀함수에 대한 고찰 - 파이썬 리뷰

코드트리애호가 2023. 10. 10. 16:18

저번에 팩맨 문제를 풀때

3중포문에서 재귀함수를 사용하다 정신 나갔던 적이있다.

 

코드트리쌤한테 질문을 해서 코드를 수정을했엇는데 

 

왼쪽에서 오른쪽으로 바뀌었다. 코쌤말로는 deepcopy()를 쓰지않기위해 저렇게 처리했다고 하셨다. 

코드를 자세히보면, 처음에 방문한 delete1 을 선언하고 delete1 체크 후, for j 문으로 넘어가고 

temp2 에다가 현재까지온 delete1 2차원배열을 저장. 그다음 for z 문 넘어가서 temp3에 delete1 2차원배열을 저장. 

for문 수행이 다끝나면 다시 아까 저장했던 배열을 delete1[nx3][ny3] =  temp3 으로 해준다.

즉, 선택이 끝나고 다시 불러와주는것. 나는 deepcopy 를통해 delete배열을 새로 만들어 줬다. 

 

그렇다면 코쌤이 말씀하신대로  재귀 함수를 통해 이함수를 만들어 보면 어떨까? 

 

한번 써보기로했다. 

 

 

def pacman_move():  
    global monster_cnt, monster_arr,r1,c1
    #상좌 하우의 우선순위를 가지고
    #3칸을 이동하는데. 몬스터를 가장 많이 먹을 수 있는 경우의 수다.
    #이동칸에 몬스터를 다 먹어치우고 시체를 남긴다.
    #알은안먹음. 움직이기전에 같은 칸에있는 몬스터 안먹고, 이동하는 과정중만 먹는다.
    #팩맨이잇는자리에 알이 태어날경우를 말하는듯.
    dx=[-1,0,1,0]
    dy=[0,-1,0,1]
    x,y=r1,c1 # r1,c1이 팩맨의 위치다.

    moving = []

    for i in range(4):
        for j in range(4) :
            for z in range(4) :  
                (power,moving_arr,real_x,real_y) = lets_search(i,j,z)  # 얘가 최대값을 리턴해줘야한다.
               
                moving.append((power,i,j,z,moving_arr,real_x,real_y))
                       
   
    #print(where_is_64_pac_go)
    moving.sort(key=lambda x:(-x[0],x[1],x[2],x[3]))
    # 몬스터 먹은개수, 처음이동, 2번째 이동, 3번째이동, 각 경로를 담은 배열
    #이게 과연 좌우상하를 가지고 됐을까?
    eat,first,second,third,moving_arr,last_x,last_y = moving[0]

    #팩맨위치 갱신
    r1,c1 = last_x,last_y
    pacman_update()

    #여기서 경로상에 있는 몬스터들 다 지우고, 그녀석들만큼 시체에 넣는다.
    #이거 배열끼리 비교해서 어떻게 안전하게 값 같을때 해당 배열 지우는지 블로그 글쓰기 <<<<<<<<<<<<<<

    #몬스터들 잡아먹히고 난다음 갱신, 시체 갱신

    for item in moving_arr:
        q,p = item
        #안에있는놈 다 날려버리기.
        if len(monster_3d_arr[q][p] ) > 0 :
            monster_3d_arr[q][p] = []
            monster_body_arr[q][p] = 3

    #초기화 하고 다시 넣어준다.
    monster_arr= []
    for i in range(n) :
        for j in range(n) :
            if len(monster_3d_arr[i][j]) > 0 :
                for item in monster_3d_arr[i][j] :
                    monster_arr.append((i,j,item))



    """
    for item in moving_arr:
        q,p = item
        for (q1,p1,dir1) in (monster_arr):
            if q==q1 and p == p1 : #해당하는 위치에 똑같은값들이 있다면,
                monster_body_arr[q1][p1] = 3 #두턴이 3인? ㅋㅋ
                if not (q,p,dir1) in temp_monster_arr : continue
                idx = temp_monster_arr.index((q1,p1,dir1))
                temp_monster_arr.pop(idx) #그 값을 빼버린다.
                #그 장소에 시체를 2턴간 남긴다.
                continue
   
    monster_arr = temp_monster_arr.copy()
    """
    return

위와같이 수정했다. 기존에 내가 했던 방식 ( key=lambda x:(x[0) .. ) 이방식을 유지하고 

재귀함수만 사용해봤다. 근데 이방식은 -1이 들어올때 moving 배열에 넣지않는게 배열 sort할때 시간이 덜 줄어들 것같다. 

 

def lets_search(i,j,k) :
    dx=[-1,0,1,0]
    dy=[0,-1,0,1]
    global r1,c1 # 팩맨의 위치
    x,y = r1,c1
    already_visited = []
    power = 0
    for move_dir in [i,j,k] :
        nx,ny = x+dx[move_dir],y+dy[move_dir]
        if not in_range(nx,ny) :
            return (-1,[],-1,-1)
        if not (nx,ny) in already_visited :
            already_visited.append((nx,ny))
            power += monster_cnt[nx][ny]
        x,y = nx,ny

    real_x = x
    real_y = y

    return (power,already_visited,real_x,real_y)

 

잘써먹은건 저 배열값하나하나 가져온다음에 탐색하고, 이미 방문한 배열이지 않으면 power값 가져오고 

해당한걸 리턴.

 

그리고 리턴한 값을 sort로 정렬 해서 풀었다.

 

만약 내가 현장에서 풀어야한다면, 함수화-함수화-함수화 하는 버릇을 들여서 

최대한 실수가 나지않게 만드는게 중요할꺼같다. 

 

계속 코딩하다보면 뭔가 함수화하면 또 변수선언해야 하고 귀찮으니까 계속 디버깅하면서 구멍나는 부분을 메꾸려고하는데

거기서 시간오래걸리고 잡아먹힐시간에 함수화해서 문제날때 return 해버려서 

그걸 버려버리게 하는게 좋을거같다.