코테 리팩토링) 디펜스 게임

EBAB!·2024년 5월 15일
0
post-custom-banner

목표

  • 기존에 문제를 푸는데만 집중해서 풀었던 문제들을 클린 코드, 객체 지향 방식으로 리팩토링
  • 완벽한 효율보다는 다양한 스타일로 작성

문제

코테 문제) https://school.programmers.co.kr/learn/courses/30/lessons/142085

준호가 처음 가지고 있는 병사의 수 n, 사용 가능한 무적권의 횟수 k, 매 라운드마다 공격해오는 적의 수가 순서대로 담긴 정수 배열 enemy가 매개변수로 주어집니다. 준호가 몇 라운드까지 막을 수 있는지 return 하도록 solution 함수를 완성해주세요.

제한사항

  • 1 ≤ n ≤ 1,000,000,000
  • 1 ≤ k ≤ 500,000
  • 1 ≤ enemy의 길이 ≤ 1,000,000
  • 1 ≤ enemy[i] ≤ 1,000,000
  • enemy[i]에는 i + 1 라운드에서 공격해오는 적의 수가 담겨있습니다.
  • 모든 라운드를 막을 수 있는 경우에는 enemy[i]의 길이를 return 해주세요.




기존 코드

from heapq import heappush,heappop

def solution(n, k, enemy):
    answer = 0
    h = []
    for i,e_n in enumerate(enemy):
        heappush(h,-e_n)
        n-=e_n
        
        if n < 0:
            if k<=0:
                return i
            else:
                n -= heappop(h)
                k -= 1
    return len(enemy)


수정코드

from heapq import heappush, heappop


class Player:
    def __init__(self, soldiers: int, chances: int):
        self.__soldiers: int = soldiers
        self.__chances: int = chances
        self.__enemy_heap: list[int] = []
    
    def fight_enemy(self, enemy: int) -> None:
        self.__soldiers -= enemy
        heappush(self.__enemy_heap, -enemy)
    
    def use_chance(self) -> None:
        if self.__enemy_heap and self.__chances > 0:
            self.__soldiers -= heappop(self.__enemy_heap)
            self.__chances -= 1

    @property
    def is_defeated(self) -> bool:
        return self.__soldiers < 0 and self.__chances <= 0
    
    @property
    def current_soldiers(self) -> int:
        return self.__soldiers
    
    
def solution(n: int, k: int, enemy: list[int]) -> int:
    player = Player(n, k)
    
    for _round, enemy_cnt in enumerate(enemy, start=1):
        player.fight_enemy(enemy_cnt)

        if player.current_soldiers < 0:
            player.use_chance()

        if player.is_defeated:
            return _round - 1
    
    return len(enemy)

개선점

  • PEP8 가이드라인에 따라 작성된 코드
  • 타입 힌트 추가
  • 객체 지향 프로그래밍 (OOP) 사용
    • Player 클래스를 정의해서 객체 지향 프로그래밍을 사용합니다. 코드의 재사용성, 확장성, 유지보수성을 높여줍니다
    • 클래스 내부에 병사 수와 기회 수를 관리하는 방식을 통해 관련된 로직을 메서드로 분리합니다.
      기능을 명확히 하고 코드의 가독성을 향상시킵니다.
  • 명확한 상태 관리
    • Player 클래스의 is_defeatedcurrent_soldiers와 같은 프로퍼티를 통해 코드의 흐름을 더 직관적으로 표현합니다.
    • 병사 수와 기회 수를 클래스 내부에서 관리해서 전역 변수나 매개변수를 일일이 확인하지 않아도 됩니다.
  • 역할 분리
    • Player 클래스가 전투와 관련된 로직을 담당하고 solution 함수는 전투의 흐름을 제어하는 역할을 하면서 역할 분리가 명확해집니다.
  • 메서드 사용을 통한 로직 분리
    • 전투를 진행하는 로직 (fight_enemy)과 기회를 사용하는 로직 (use_chance)을 별도의 메서드로 분리하여 각 메서드가 하나의 책임만 가집니다. (단일 책임 원칙, Single Responsibility Principle)
  • 가독성 향상
    • 명시적 메서드와 프로퍼티를 사용하여 가독성이 향상되었습니다. solution 함수에서 플레이어가 전투를 수행하고, 기회를 사용하는 과정이 더 직관적으로 이해됩니다.

프로그래머스의 컴파일 옵션이 3.8 버전이므로 typing을 사용해야 하지만 (list[int] -> List[int]) 파이썬 3.9 이상부터는 typing없이 타입 힌트가 가능하므로 최근의 버전에 맞춰 작성했습니다.

profile
공부!
post-custom-banner

0개의 댓글