01/11 본캠프 #13

guno park·2024년 1월 11일
0

본캠프

목록 보기
14/77

알고리즘 풀어보기

오늘부터 알고리즘 풀어보기, 하면서 막혔던 문제에 대해서만 다룰 예정

자릿수 더하기

처음 생각했던 풀이

  1. N을 10으로 나누어서 float A를 만든다.
  2. A를 int로 형변환한 B를 만든다.
  3. A-B를 하면 소숫점만 남는다.
  4. 이 남은 소숫점에 다시 10을 곱해서 return할 값으로 더해준다.

트러블 슈팅

  • 문제
    형변환을 하면 우리 머리로 생각하는 숫자와 실제로 컴퓨터에 저장된 숫자가 다르다.
    ex) 우리 생각 : 98.7 / 실제 : 98.70000006
    예시는 98.7까지 똑같지만 소숫점 숫자가 달라질 수도 있다.
  • 해결
    뒤에서부터 접근하는게 아니라 반대로 앞에서부터 접근해서 해결했다.
  1. MathF.Log10()을 사용해 몇자리 수인지부터 파악한 후,
    N을 나누어 한자리 수로 만든다 (float)
  2. float를 int로 형변환 해 소숫점을 다 떼어버린 후, return할 값에 더한다.
  3. N을 int로 형변환 값에다 곱하기를 해서 원래 크기로 만든 후 빼준 값으로 만든다.
  4. 반복

추가 정보

이 문제에 대해 튜터님께
"float형으로 만들었을 때도 내가 생각한 값대로 나오게 할 수 있는가"라고 여쭤봤더니

출력할 때 string.Format을 사용하는 것이나, 계산 처리를 거치는 방법이 있다고 얘기해주셨다.
말인 즉슨 float을 그냥 사용해서는 내가 원하는 결과를 얻을 수 없다는 의미인 듯 하다.

계산처리하는 예시를 작성하고 넘어간다.
ex)
987 10f = 98.7 우리가 생각하는 수
98.70000006 > 987.00000006 >다시 나누기10 98.7 로 만들어주는 계산처리를 거칠 수 있음

  • 소숫점 많을때는 float 보다 Double이 좋다.

x만큼 간격이 있는 n개의 숫자

문제 풀이

문제 자체는 엄청 간단하다.

  1. 입력받은 크기의 배열 생성
  2. x가 시작값이고 간격이니까 따로 저장해줄 변수도 만듬
  3. for 반복으로 배열 길이만큼 x+temp*i 해서 넣어주면 된다.
public class Solution {
    public long[] solution(int x, int n) {
        long[] answer = new long[n];
        long input=x;
        long temp=x;
        for (int i =0;i<answer.Length;i++){
            answer[i] = input;
            input+=temp;
        }
        return answer;
    }
}

발생한 오류 & 해결


갑자기 숫자가 -값으로 되버렸다.
왜 오류가 나는지 의아하다가, 한번 직접 예외처리 해서 찍어보니 정답이 나왔다.
정수 자료형은 범위가 있다. 그 범위를 벗어나는 값이 되면 표현하지 못하고 다른 값이 되어버리는 것이다.
그래서 문제 풀이에는 answer에 들어가는 값들을 long으로 바꿔주었다.

약수의 합

문제 풀이

간단하게 for문을 두개 작성해서, n보다 작게 범위를 설정했다.
그 후 두 수를 곱해서 n이 나오는 값들만 List에 추가하고 중복되는 값들을 제거한 후,
foreach를 통해 모든 값들을 더해주었다.
여기에 작성하는 이유는 중복값 제거를 위해 사용한 것을 기억하기 위해서다.
츠라구 Coding Note
여기서 list.Distinct().Tolist();를 사용했다.

오늘 느낀 점

풀이를 생각하는 데 오래 걸린 문제들도 있긴 했는데, 엄청 재밌었다. 오늘 늦잠자서 한 문제는 풀 수 있을까 싶었는데, 난이도도 아직까지는 그렇게 어렵지도 않아서 많이 풀었다.

팀 프로젝트 - TextRpg 만들기.

오늘은 팀원들과 코드 한번 통합 하고나서 진행했다.
따로 큰 틀에서 작업한 건 아니고, 자잘자잘하게 작업했다.

레벨업 기능

통합되서 Program.cs를 만질 수 있어서 간단하게 추가했다.
Player 클래스에 EXP 변수를 만들어 주고, 같이 LevelUp, LevelCal 이라는 함수를 만들어 줬다.
메서드가 하나였는데, 반복되는게 불편해서 두개로 분할했다.

 public void Levelup(int value)
 {
     Console.WriteLine("레벨 업!");
     Console.WriteLine($"Lv. {level} -> {level + 1} {name}");
     level++;
     ATK += 0.5f;
     DEF += 1;
 }

 public void LevelCal()
 {
     switch (level)
     {
         case 1:
             if (EXP >= 10)
                 Levelup(level);
             break;
         case 2:
             if (EXP >= 35)
                 Levelup(level);
             break;
         case 3:
             if (EXP >= 65)
                 Levelup(level);
             break;
         case 4:
             if (EXP >= 100)
                 Levelup(level);
             break;
     }
 }

그리고 발제자료에 나온 것처럼, 몬스터들 레벨의 합으로 경험치를 설정했다.

위는 2마리만 잡은 모습이다.

던전 밸런스 조절 (레벨 스케일링)

크게 주안점으로 잡은 것은 세 가지
1. 몬스터 스폰로직 변경
2. 몬스터 스탯 조절
3. 던전 내 이벤트 배치

몬스터 스폰로직 변경

  • 기존 조건
    몬스터는 1~4마리 생성
    생성 가능 몬스터 종류에 제한 없음

  • 변경 조건
    레벨에 따라 생성량 변경, 생성 가능 몬스터 종류 제한

int spawnCut = (Game.game.player.level < 3 ? 3 : 5);

삼항연산자로 생성 가능 종류와 수에 차이를 두었다.

몬스터 스탯 조절

어제 나온 얘긴데, 몬스터가 너무 잘 피한다는 얘기가 나와서 회피율을 조절하기로 했다.

  • 기준
    몬스터의 회피 성공률이 기본 10%정도, 많아도 30%

몬스터 회피율을 설정하기 위해선, 일단 어떤 조건에서 어떤 확률이 발생하는 지 체크해야한다.
그래서 잠깐 실험을 해보았다.

회피율 실험

몬스터의 명중, 회피의 기준점을 5/5로 잡고 실험을 진행하고 점차 바꿔보았다

이런 느낌으로 진행해서 생성된 모든 몬스터 클래스의 스탯을 조절해주었다.

약간의 오류 해결

실험을 하는 도중에 이상한 점이 발견되었다.

내가 작성한 조건식은 비교연산자로, true나 false만 나와야 한다. 3번째 조건이 나오면 안되는데 예외처리를 해봤더니 제 3의 결과가 나왔다.
분명 제시된 조건은 1번 결과가 나와야되는데 혼자 생각하기엔 모르겠어서 튜터님께 질문드렸다

Random은 변수로선언하고 넣어주는게 훨씬 낫다.
우리가 생각하는 조건이랑 실제 동작 순서가 뒤바뀔 수 있다.
랜덤이라는게 우리가 간단하게 랜덤 이렇게 생각할 수 있지만, 명령어 자체는 뒤에서 돌아가는게 많다. 그래서 랜덤같은경우는 이프문에 잘 안넣음.

이라고 하셨다. 기존에 사용되던 전투의 회피 명중도 변수를 선언하는 방법으로 바꿔주었다.

던전 내 이벤트 배치

 public static void dungeonsetting()
 {    
     int[] EventList = new int[7] {0,0,0,0,1,1,2}; //이벤트 갯수 정하기
     EventList = EventList.OrderBy(item => new Random().Next()).ToArray() ;
     
     dungeon = new int[3, 3] { 
     { 5, 0, 0 },
     { 0, 0, 0 },
     { 0, 0, 3 } };
     
     int k = 0;
     for (int i= 0; i< dungeon.GetLength(0); i++) //고정위치 빼고 남은 방에 이벤트 분배
     {
         for (int j =0; j<dungeon.GetLength(1); j++)
         {
             if (dungeon[i, j] == 0)
             {
                 dungeon[i, j] = EventList[k];
                 k++;
             }
         }
     }
     k = 0;

int[] 배열에 이벤트를 비율대로 입력해주고, 이 리스트를 orderby로 섞어서 고정된 방들을 제외하고 배치해주면 완성!
OrderBy할 때 맨 끝에 배열이라면 ToArray(), 리스트라면 ToList()를 붙이는 걸 기억하자!

포션(아이템) 사용하기

기본적으로 존재하는 포션 이외에 상점에서 구매 가능한 소비형 아이템이다.

기본 구상

  1. 인벤토리에서 소비형 아이템만 출력하도록 해준다.
  2. 거기서 선택해서 사용한다.

되게 간단해보인다.
이제 소항목으로 나눠보자

  1. 인벤토리에서 소비형 아이템만 출력하도록 해보자.
    1-1 : 인벤토리 전체를 순환하며 소비형 아이템만 검색한다.
    1-2 : 해당하는 아이템을 출력해준다.
    1-3 : 사용 처리를 위해서 그 위치의 인덱스를 어딘가에 저장한다.
  2. 선택해서 사용한다 //이름으로 구별했음
    2-1 : 선택한 아이템의 종류에 따라 다른 동작을 하도록 분리한다.
    2-2 : 선택한 아이템이 동작한 후, 인벤토리에서 삭제한다. 인덱스를 이 때 사용한다.
    inventory.removeat(index)
    (출처 : Tech_Delight)

되게 오랜만에 구상대로 작성했는데 에러는 안 났는데, 변수가 있었다.

문제 발생

아이템 타입으로 비교를 하려했는데, 참조를 하니 아이템 타입이 None(디폴트)이였다.
브레이크 포인트 걸어서 막 디버깅 해봤는데 shop()에서는 제대로 들어갔었다. 그래서 뭔가 싶어서 팀원들이랑 얘기하니까 바로 답이 나왔다.

문제 해결

애초에 shop에 있는 물건이랑 비교하면 안됬다. 물건을 구매할 때 사용하는 함수에는 아이템 생성자에 아이템 타입을 작성하는 부분이 없었기 때문에 디폴트로 나오는 게 정상 동작이였다.
그래서 생성자를 조금 수정해주었다.

진짜 짜잘이들

보상 추가하기

아이템을 드랍하는 건 게임 컨셉에 부합하지 않는 것 같아 아직 고민 중이다. 골드만 추가해놨는데 내일 포션도 추가할까 싶다.

공격력, 방어력 관련 수정

공격력

공격력이 데미지를 산출할 때 매개변수로 들어가는 값인데, 통합 전까지는 캐릭터의 기본 공격력만
사용하다가, 통합 후에 사용하기 좋은 변수가 있어 데미지 산출에 같이 적용되도록 변경하였다.

방어력

몬스터가 공격할 때 방어력만큼 깎인 후 데미지가 들어오도록 수정하였다.

정리

오늘은 짜잘짜잘하게 많이 했는데, 도전하는 방식이 다양해서 좋았다. 그리고 알고리즘 풀어보는 것도 재밌어서 기대가 된다.
정리하면서 생각 났는데,
도전 과제 12번을 스테이지 추가를 던전으로 대체하긴 했는데, 아마 저 내용이 오늘 한 던전 밸런스 변경이지 싶다.
오늘로 개인과제 피드백도 받았는데, 봐야되는데
주말에 피드백 관련 공부를 할까 싶다.

그래서 내일 할 일

  1. 포션도 보상에서 확률적으로 나오게 추가해보자.
  2. 자잘한 거 수정, 주석 달기, 콘솔 꾸미기 등등
  3. 알고리즘 코드카타도 있다.
  4. 만약 진짜 할 거 없으면 주말 공부 좀 미리 땡겨서 시작하기

0개의 댓글