TIL(Today I Learned)

텍스트 RPG 게임 : 기능 구현과 디버깅 - TIL#15

Najdorf 2024. 1. 12. 23:54
728x90

오늘의 알고리즘 오류 상황

 

문제 : 정수 n을 입력받아 n의 약수를 모두 더한 값을 리턴하는 함수, solution을 완성해주세요.

 

 

오늘 문제는 정수를 입력받아 그 수의 모든 약수를 더해서 반환하는 문제인데,

처음에 이 문제를 보자마자 내가 알고리즘 동작 순서로 계획했던 것은

수학에서 약수를 구하는 정석적인 방법으로 구하려고 했었다.

 

즉, 정수 n을 입력 받으면 -> n을 소인수분해 ->

중첩 반복문으로 약수 구해서 배열에 할당하는 방식으로 생각해서 실제로도 그렇게 시도를 했었다.

 

그러나, 당초에 소수라는 수는 규칙이 없거니와

그런 소수를 일일이 3000까지 등록하기엔 귀찮고,

2부터 3000까지의 소수를 구하려면 어떻게 해야하나 고민에 빠지게 되었다.

 

실제 수학에서도 소수를 구하는 방법은 한 가지 방법밖에 없는데,

바로 '에라토스테네스의 체'라는 방법을 사용하는 것이다.

 

https://ko.wikipedia.org/wiki/%EC%97%90%EB%9D%BC%ED%86%A0%EC%8A%A4%ED%85%8C%EB%84%A4%EC%8A%A4%EC%9D%98_%EC%B2%B4

 

에라토스테네스의 체 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 에라토스테네스의 체 수학에서 에라토스테네스의 체는 소수를 찾는 빠르고 쉬운 방법이다. 고대 그리스 수학자 에라토스테네스가 발견하였다. 알고리즘[편집]

ko.wikipedia.org

 

이름만 들어선 어려워 보이지만...

실상은 가장 작은 소수인 2부터 차례로 나눠가며

1과 자기 자신이 약수인 수들을 찾아내는 노가다성 반복 작업이다...

 

이를 구현하려고 고민에 빠지고 있던 찰나....

이렇게 3000번 정수까지 나누고 소수인지 확인하는 반복 작업을 애초에 컴퓨터에 시킬 거라면

처음부터 약수를 반복작업으로 구하는 게 더 쉽지 않느냐는 생각이 들었다.

 

애초에 알고리즘 문제도 이걸 의도 했던 것 같다.

나는 '약수'라는 말을 듣자마자 '수학적'으로 어떻게 풀어야 하나 고민을 했는데,

'컴퓨팅적 사고'는 그런 게 아니었다.

 

컴퓨터는 기본적으로 반복적인 작업에 매우 강하다!!

 

그래서 생각해 낸 방법은,

정수 n이 주어지면, 정수 i가 n부터 시작해서 1씩 작아지는 반복문을 돌리고,

n을 i로 나눴을 때 나머지가 0이면 배열에 할당하는 방식이다.

 

이 방법을 생각하고 나서 위에서 내가 얼마나 쓸데없는 고민을 했는지 알 수 있었다 ㅋㅋㅋㅋ

(그래... 이러니까 레벨 1짜리 문제지...)

using System;
using System.Collections.Generic;

public class Solution
{
    public int solution(int n)
    {
        List<int> aliquots = new List<int>();

        for (int i = n; i > 0; i--)
        {
            if (n % i == 0)
            {
                aliquots.Add(i);
            }
        }

        int answer = 0;

        foreach (int aliquot in aliquots)
        {
            answer += aliquot;
        }
        return answer;
    }
}

 

해결했다!

 

그러나 앞선 생각들이 모두 잡생각은 아니었던 것 같다.

이렇게 고민하는 과정이 있어야 알고리즘을 잘 짤 수 있게 되는 게 아닐까...?


프로젝트 오류 상황

 

어제 예상이 매우 정확했다.

코드를 병합하고 직접 실행까지 시켜보니 수많은 오류(...)가 생기며

앞서 내가 짰던 코드들이 얼마나 빈틈이 많은 형편없는 것이었는 지 깨닫게 되었다...

 

1. 빌드 오류

내 코드를 합치자마자 빌드 오류가 날 반겨줬다...

문제의 원인을 찾기 위해 코드를 이리저리 둘러보다가...

 

메인 함수가 너무 비쩍 말랐다는 것을 깨닫게 되었다.

새로운 Map 클래스 변수를 하나 만들어놓고...

정작 Map 생성자에서 뭘 하라고 던져놓은 것도 아니라서 빌드 오류가 난 것 같다.

 

그래서 팀원 한 분이 구현해주신 Map.cs를 다시 병합하고,

Map.cs 에서 시작하는 메서드인 DrawMap을 호출하니

정상적으로 빌드되는 모습을 확인할 수 있었다.

 

 

2. 주석 처리를 조심하자

병합을 처음 하고 나서 바로 빌드 오류가 생긴 것을 간신히 해결하고,

이제 좀 프로그램이 돌아가겠거니 해서 돌려보는데?

또 예외가 발생했다며... 빨리 해결하라고 콘솔창이 울기 시작했다.

 

저기서 나온대로라면, 문제가 발생한 곳은

내가 짰던 ItemManager.cs의 43번째 줄에서 오류가 발생했다는 데...

바로 이 부분이다.

 

내가 의도했던 기능은 Utilities에 구현된 LoadFile 기능을 이용해서

지정된 경로에 존재하는 Item_Data.json 파일의 데이터를 읽어와,

List에 할당한 다음, 배열로 바꾸는 기능이었는데...

뭔가 오류가 있었던 모양이다.

 

그래서 이걸 해결하기 위해 Utilities의 LoadFile 메서드를 팀원과 함께 유심히 읽어보기로 했다.

그랬더니... 제일 중요한 return 부분이 주석 처리가 되어있었다...

 

그래서 리스트에 당연히 받아야 할 데이터도 불러오지 못했고

그걸 배열로 변환하는 과정에서 문제가 생겼던 것이다...

 

주석 처리를 해제하니 잘 돌아가는 모습을 볼 수 있다.

 

3. 쓰잘데기 없는 변수

 

여기서 잘만 돌아갔으면 좋았을텐데...

이번엔 상점에 정작 중요한 아이템 목록이 뜨지 않는다는 것이다.

인벤토리야 상점에서 물건을 사야 들어오기 때문에

처음에는 아무 아이템도 없는 것이 정상이지만...

 

상점은 처음에 isSale 변수가 true인 모든 아이템을 가져와 나열하게 되어있는데

아무 아이템도 뜨지 않는 것이다.

 

혼자시 심각하게 또 Utilities 클래스를 내가 잘못 이해하고 있나? 생각하다

팀원 분께 아주 좋은 조언을 얻게 되었다.

 

 

바로 Visual Studio 에서는 'F9'을 눌러 중단점을 만들고

'F5'로 '디버깅'을 할 수 있는데,

중단점에서 콘솔창이 꺼지며

 

 

아래와 같이 변수를 자세히 확인할 수 있는 창이 뜨게 된다.

여기서 내가 원하는 변수에 드래그를 하고 마우스를 올려두게 되면...

 

 

이렇게 어떤 값이 들어있는지 상세하게 확인할 수 있다!

 

여기서 디버깅을 해보며 알 수 있던 사실은,

나는 문제의 원인이 items 값이 아까와 같이 기능적인 문제로

아이템 데이터를 제대로 읽지 못해서 null 값이 들어있어

상점도 아무런 데이터가 뜨지 않았을 거라고 생각했는데...

 

의외로 items 변수에는 Item_Data.json의 데이터가 정상적으로 들어가 있었고,

문제는 다른 곳에 있었다는 것이다.

 

바로 아이템 데이터는 items에 할당시켜놓고

'data'라는 아무 값도 들어있지 않은 쓰잘데기 없는 엄한 변수에서 값을 불러와

모든 기능이 동작하게 코드를 개판으로 짜놨던 것이다!!!

 

그래서 상점에도 아무 정보가 없는 배열을 나열하니

아무 것도 보이지 않았던 것이다...

(컴퓨터는 거짓말을 하지 않는다.)

 

문제를 깨닫고 items에서 변수를 불러오는 것으로 수정했더니...

 

 

정상적....으로 작동한다?

 

 

4. 메서드 별 실행속도

 

 

내가 분명 의도했던 건 위 코드 순서대로 콘솔창에 출력하는 것이었다.

그런데 출력된 콘솔창을 살펴보면 itemManager.ShowShop() 으로 호출했던

상점 아이템 전시 메서드가 엄한 곳에서 실행되고 있다.

 

이는 Utilities를 구현한 팀원분께 문제의 원인을 자세히 들을 수 있었는데...

 

위 코드에서 나는 Utilities.AddLine 이라는 메서드를

Console.WriteLine 대신 사용하고 있다.

 

AddLine 메서드는 팀 프로젝트 일부 기능 구현에 있어서

편의상 구현해놓은 콘솔창 출력 기능인데,

이게 아무래도 해당 메서드를 호출하게 되면,

 

'Utilities 클래스 -> AddLine 메서드 -> Console.WriteLine 과 기타 기능 실행'

과 같은 순서로 실행되기 때문에

 

당연히 Console.WriteLine을 단독으로 호출하는 것보다 실행 속도에 있어

더딜 수밖에 없다는 단점이 있다.

 

그런데 중간에 따로 호출한 itemManager.ShowShop 메서드에선

내가 AddLine 기능을 사용하지 않고 Console.WriteLine을 사용했기 때문에

속도 상 뒤죽박죽이 되어버려 위와 같은 결과가 뜨게 된 것이다.

 

이를 반영해 아래와 같이 코드를 수정하면,

 

 

이렇게 의도한대로 정상적으로 출력되는 것을 볼 수 있다!


느낀 점

 

분명 근 일주일 간 밖을 나가지 않았는데

감기에 걸려(...) 열도 나고 컨디션이 매우 좋지 않은 하루였지만,

 

팀원과 함께 발생하는 오류들을 수정하고

이를 해결해 나갈 수 있음을 알게 되어서 인상깊었다.

 

또한, 서로 만든 코드를 병합해 점점 완성되는 프로젝트를 보니

파티에 서로 만든 음식을 하나씩 가져와 즐기는 것 같기도 하였다.

 

 

 

 

 

주말에도... 버그 잡아야겠지...?

728x90