과제 진행 상황

구현하고 싶었던 기능은 전부 구현했고, 이쯤에서 이번 과제를 마무리 하기로 했다.

 

https://github.com/P-lani/sparta_RogLike

 

깃 허브에 최종merge 가 완료된 상태이다. 원한다면 플레이가 가능하다 !

아래는 readme 에 쓴 내용이다.

 

## **개발 프로세스**

**도전 기능 부분**
0. 찾기 쉽도록 위쪽에 쓰겠습니다

1. 확률 로직
 1) 플레이어의 공격력과 최대배율에 따른 난수 데미지 / 몬스터의 공격력 또한 1.4배의 난수를 가짐
 2) 축지법 ! 스킬은 일종의 카운터 스킬로, 성공확률이 존재
 3) 필살! 암벽등반! 스킬은 연속공격 스킬로, 5~10회 랜덤횟수를 공격
 4) 지름길 개척 스킬은 도망 스킬로, 10%의 확률(고정)로 성공함
 4) 스테이지 클리어 보상 5가지중 3개를 랜덤 획득하며 (중복 가능)
    각각의 보상은  0.8배~2.0배의 난수를 가짐
 5) 몬스터의 name은, 따로 설정한 배열에서 랜덤으로 선택함
 6) 몬스터의 패턴(체력 소모)는 확률에 따라 상이하게 발생 (빗나감, 약화된 공격, 평범한 공격, 강력한 공격, 아주 강력한 공격)

2. 복잡한 행동 패턴
 1) 필살! 암벽등반 ! 기술은 확률로직 외에도, 충전을 3개를 소모해야 사용할 수 있으며,
    충전은 stage clear 랜덤 보상으로만 획득할 수 있습니다. (원활한 Test를 위해 3충전을 가지고 시작합니다.)
    추가로, 확률 로직과 delay 텍스트 출력 등등 약간의 연출이 추가되어 있습니다.

 2) 지름길 개척 기술은, 성공시 연출효과...를 출력합니다.

 3) 위의 연출 효과를 응용하여 함수로 만들었고, 시작 시(오프닝), 엔딩, 패배 화면에 적용했습니다.

###  게임 기획 분석**


**컨셉 잡기**

1. 등산을 컨셉으로 제작한 게임입니다.
플레이어 : 등산가
플레이어의 체력 : 체력
플레이어의 공격력 : 등산력(...)

몬스터 : 등산로
몬스터의 체력 : 남은 거리
몬스터의 공격력 : 체력 소모량

2. 컨셉만 약간 특이할 뿐, 구현내용은 크게 다르지 않습니다.

다만 !
체력이 0이 된 몬스터는 공격을 못하겠지만,
남은거리가 0이되는 등반은 체력을 소모합니다.
때문에, 마지막 일격에도 반격을 받는 느낌이 되었고 의도된 구현입니다. (더블 KO 는 패배 처리)



**전투 기획**

1. 플레이어= 등산가 의 행동 선택지

    1. 등반하기 : 100% 확률로 등산력에 해당하는 거리를 등반. 이후 체력 소모(상대 턴) 발생합니다.

    2. 축지법 ! : 기본35% 확률로 등산력에 해당하는 거리를 등반. 성공시 체력을 소모하지 않습니다. 실패시 체력소모만 발생합니다.
        35% 확률로 굉장히 저조한 성능이지만, 이후 랜덤 보상을 통해 확률이 증가할 수 있습니다.

    3. 필살! 암벽등반! : 최대 충전3, 초기 충전3, 사용시 충전 3 소모.
        등산력에 해당하는 거리를 5~10회 랜덤횟수 등반합니다.  충전은 랜덤 보상에서 획득 가능합니다.

    4. 지름길 개척 : 도망에 해당하는 기술로, 낮은 확률(10%) 로 성공하여 스테이지 클리어로 판정하고 보상 또한 정상적으로 획득합니다.
        => 이는 사실상 즉사기에 해당하기 때문에, 성공시 등산로의 남은 거리를 0으로 만들고 체력 소모 턴이 발생하지 않습니다.
        실패시 체력 소모만 발생.


2. 플레이어의 능력치
    1. 체력 : 0이 되면 게임오버가 되며, 스테이지 클리어시 확정적으로 일정량을 회복합니다.
        추가적으로 랜덤 보상에서도 획득할 수 있습니다.

    2. 등산력 : 공격력에 해당하며, 등산력 ~ 등산력 x (1+최대배율/100) 의 난수를 가집니다.
        확정 증가는 없으며, 랜덤 보상을 통해 상승할 수 있습니다.

    3. 최대배율 : 최대 공격력 배율에 해당하며, 계산은 위와 같습니다. 기본 20의 최대배율로 시작합니다. (1.2배)
        확정 증가는 없으며, 랜덤 보상을 통해 상승할 수 있습니다.

    4. 축지법 확률 : 축지법 ! 스킬의 성공확률이며, 35%로 시작합니다.
        확정 증가는 없으며, 랜덤 보상을 통해 상승할 수 있습니다.
        최대 75% 의 상한을 가지고 있습니다.

2. 몬스터 = 등산로의 패턴

    1. 엄밀히 따지면, 몬스터가 완전한 턴을 받는 형식의 구현은 아니고,
        플레이어의 행동에 따라 몬스터의 공격 이벤트가 발생하는 방식입니다.

    2. 체력을 소모할 때, 등산로(monster) 의 공격력을 참조하며, 등산로의 공격력은 1 배 ~ 1.4배 난수를 갖습니다.

    3. 추가적으로 확률에 따라 체력 소모가 0.6배 , 1배, 1.3배, 1.6배, 2배, 체력소모 0 이 되는 이벤트가 발생합니다.
        확률은 각각 상이합니다. (낮은 확률로 컨셉이 파괴되는 텍스트가 출력됩니다. )
       
    4. 5층에서는 중간 BOSS 를, 10층에서는 최종BOSS 를 조우합니다.
        BOSS 는 전용 name 을 가지고, 별도의 체력과 공격력을 가집니다.

    5. BOSS 이외의 몬스터는 지정된 값(배열) 중 랜덤한 name을 갖습니다.
        (name중 일부는 컨셉이 파괴되는것도 있습니다. )

    6. 등산로(monster)는 stage 마다 증가한 체력과 공격력을 갖습니다.

    7. 등산로(monster)의 남은거리(hp)가 0 이 될 경우, stage가 클리어 되며,
        랜덤 보상 3가지를 획득하고 다음 stage 로 넘어갑니다.

    8. 중간 BOSS 클리어시엔 랜덤 5가지 보상을 획득하며,
        최종 BOSS 클리어시엔 엔딩이 출력됩니다.


3. 랜덤 보상

    1. stage 를 클리어하여 랜덤한 보상 3개를 획득합니다. (중간BOSS 클리어 시 5개)

    2. 체력 회복 / 등산력 / 최대 배율 / 필살 충전 / 축지법 확률
         종류는 총 5가지 이며 각각 동일한 확률을 가집니다.

    3. 체력 회복, 등산력, 최대배율은 stage 에 따라 기본 보상량이 증가합니다.  
        또한 0.8배~ 2.0배의 난수가 적용됩니다.

    4. 축지법 확률은 stage 에 상관없이 고정된 보상량을 갖지만,
        마찬가지로 0.8배~ 2.0배 난수가 적용됩니다.

    5. 모든 보상은 현재 수치 -> 증가된 수치 , 증가량을 표기합니다.





**추가적인 요소**

1. 전투로그가 14줄을 넘어갈 경우 먼저 출력되었던 로그가 제거되어 14줄이 유지됩니다.

2. 지름길 개척  스킬 성공 시, 연출 효과를 추가했습니다.
    반복문을 통해, 콘솔 클리어와 문자열 출력을 반복합니다.

3. 위의 연출을 함수화 시켜서 GAME-OVER, GAME-CLAER 에도 적용 했습니다.
   
4. setTimeout 을 사용하는 delay 함수를 사용하여, 로그 출력간에 delay를 적용했습니다.


 

readme 에는 기획과 구현기능에 관한 내용을 담아보았다.

 

 

과제 마무리에 관한 내용은 과제 제출날짜인 내일 TIL로 작성할 계획이다.

 

오늘은?

오랜만에 알고리즘 풀이 시간을 가져 보았다. 

물론, 과제 진행중에도 알고리즘 풀이시간을 갖긴 했지만,

TIL로 작성하기엔 시간도 양도 부족했었다.

 

그럼 시작해볼까?

 

 

뭐지 언어 영역인가...

 

시작부터 문제 설명만 10줄이 넘어가는 알고리즘 문제를 만났다.

 

쉽게 설명하면....

[1,3,4,6] 에서

index 0 = 1 개

index 1 = 3 개

index 2 = 4 개

index 3 = 6 개 

의 숫자가 존재하며 이를 풀어서 나열하면 0 111 2222 333333 이 되고, 

이 목록을 0을 기준으로  반으로 쪼개서 1223330333221 을 출력해야하는 상황이다.

이 때, 1은 3개 이기 때문에, 반으로 쪼개고 남은 1개는 버려지게 된다.

 

가장 쉽고 직관적인 방법으로 접근해보자.

1.

index 1~끝까지, 해당 index의 value의 절반만큼(소수점 버림) index를 빈 문자열 answer에 추가

 answer = "122333" 

2.

index 0 을 value 만큼 추가. ( 문제에서 0은 1개로 고정이라고 했기 때문에 arr += 0 을 해도 같다)

3.

answer = "1223330"

그 후, 1에 사용한 방법을 역순으로 적용

index의 끝에서~1 까지, 해당 index의 value의 절반만큼 어쩌구 저쩌구

answer = "1223330333221" 

 

벌써부터 O(n^2 *2 )  급의 코드가 만들어질것 같은 예감이 든다.

당장 해보자 !

 

function solution(food) {
    var answer = '';
    for(let i = 1; i < food.length; i++) {
        for(let j = 0; j < food[i]/2; j++ ){
            answer += i
        }
    }
    return answer;
}

console.log(solution([1,3,4,6]))  // "1122333"  실패 !
// 홀수value 를 가진 경우 +1회가 더 출력되는 모습

계획중  1에 해당하는 부분 이다.

위 처럼 코드를 짰더니, food[i] /2 에 홀수가 들어갈 경우 절반 +1 회 출력이 되어버린다.

 

function solution(food) {
    var answer = '';
    for(let i = 1; i < food.length; i++) {
        for(let j = 1; j <= food[i]/2; j++ ){
            answer += i
        }
    }
    return answer;
}

console.log(solution([1,3,4,6]))  // "122333"

소수점을 고려하지 않도록 위처럼 수정해 주었다.

 

그 후, 0을 추가하고 다시 뒤에서 부터 반복 !

 

function solution(food) {
    var answer = '';
    for(let i = 1; i < food.length; i++) {
        for(let j = 1; j <= food[i]/2; j++ ){
            answer += i
        }
    }
    answer += 0
    for(let i = food.length; i > 0 ; i--) {
       for( j = 1; j <= food[i]/2; j++) {
           answer +=i
       }
    }
    return answer;
}

계획한 그대로 코드가 되었다...

잘 작동하는 모습...

 

여기서 끝낸다면 취업의 길은 O=(food.length-1 ^2 *2) 만큼 멀어졌다고 볼 수 있다.

취업과 가까워 지기 위해 검색을 해본 결과, repeat() 함수를 사용하는것이 좋아보였다.

str.repeat(n) 메서드는, str 을 n번 만큼 반복 출력하는 메서드로, 

이 알고리즘 문제에 특화된 메서드라고 볼 수 있다.

심지어 소수점을 과감하게 버리는 대담함 까지 가지고있다.

 

이를 이용해서 2중 반복문을 1중 반복문으로 간소화 할 수 있다.

 

function solution(food) {
    var answer = '';
    for(let i = 1; i < food.length; i++) {
        answer += i.repeat(food[i]/2);
    }
    answer += 0
    for(let i = food.length; i > 0 ; i--) {
        answer += i.repeat(food[i]/2);
    }
    return answer;
}

 

에러 발생 

i.repeat() is not function 

 

앗... i는 문자열이 아니었다. 어차피 참고용 i이기 때문에 문자열로 전환해주자.

 

function solution(food) {
    var answer = '';
    for(let i = 1; i < food.length; i++) {
        answer += i.toString().repeat(food[i]/2);
    }
    answer += 0
    for(let i = food.length; i > 0 ; i--) {
        answer += i.toString().repeat(food[i]/2);
    }
    return answer;
}

보다 깔끔하고, 2중 for문을 사용하지 않게되어 효율적이게 되었다.

작동도 잘 된다.

 

function solution(food) {
    var answer = [];
    for(let i = 1; i < food.length; i++) {
        answer.push(i.toString().repeat(food[i]/2));
    }
    return answer.join("")+"0"+answer.reverse().join("")
}

 

억지로 줄인다면 위처럼 배열로 제작한 뒤 조립하여 return 할 수도 있다.

코드가 줄어든 것 같지만 메서드도 많이 쓰고 배열이 문자열 보다 많은 메모리를 쓰기 때문에

효율적인 코드는 아니라고 할 수 있다.

 

 

다른 사람이 작성한 코드

 

헉... 위에 작성한 나의 코드와 굉장히 유사한 형태의 코드가 눈에 띄었다.

다만, 문자열 방식을 그대로 사용하고

리턴 과정에서  [...res].reverse().join('') 이라는 엄청난 기술로 

즉각적으로 문자열을 뒤집어서 출력하는 방법을 사용했다.

 

주목할 점은

[...res] 인데, 아주 간단한 방법으로 문자열 쪼개서 배열로 만드는 최신 기술(?) 이 존재했다.

난 왜 이걸 모르고 있었던 걸까???

 

let arr = [1,2,3]

...arr = 1 2 3

... 을 통해서 배열을 분해하여 나열할 수 있는것은 알고 있었지만

거기에  [...arr] 을 한다고 다시 배열이 될 거란 생각은 못했다.

당연히 arr = [1 2 3] 이라는 이상한 녀석이 될 거라고 생각했었기 때문이다.

 

이상하다.. 구조 분해 할당 강의를 분명히 들었는데

머리속에서 undefined를 출력하고있다. (버그발생)

 

남는 시간을 활용해서 해당 부분을 다시 복습해야겠다.

 

 

 

'내일배움캠프' 카테고리의 다른 글

[내일배움캠프] 24.08.29 TIL  (0) 2024.08.29
[내일배움캠프] 24.08.28 TIL  (1) 2024.08.28
[내일배움캠프] 24.08.23 TIL  (0) 2024.08.23
[내일배움캠프] 24.08.22 TIL  (0) 2024.08.22
[내일배움캠프] 24.08.21 TIL  (0) 2024.08.21

+ Recent posts