[TIL]2024.02.13 알고리즘 + 유니티 팀 프로젝트

문정현·2024년 2월 13일
0

nbcamp5

목록 보기
1/2

알고리즘 첫번째, 프로그래머스 Lv1 푸드 파이트 대회 [링크]

문제 설명
수웅이는 매달 주어진 음식을 빨리 먹는 푸드 파이트 대회를 개최합니다. 이 대회에서 선수들은 1대 1로 대결하며, 매 대결마다 음식의 종류와 양이 바뀝니다. 대결은 준비된 음식들을 일렬로 배치한 뒤, 한 선수는 제일 왼쪽에 있는 음식부터 오른쪽으로, 다른 선수는 제일 오른쪽에 있는 음식부터 왼쪽으로 순서대로 먹는 방식으로 진행됩니다. 중앙에는 물을 배치하고, 물을 먼저 먹는 선수가 승리하게 됩니다.

이때, 대회의 공정성을 위해 두 선수가 먹는 음식의 종류와 양이 같아야 하며, 음식을 먹는 순서도 같아야 합니다. 또한, 이번 대회부터는 칼로리가 낮은 음식을 먼저 먹을 수 있게 배치하여 선수들이 음식을 더 잘 먹을 수 있게 하려고 합니다. 이번 대회를 위해 수웅이는 음식을 주문했는데, 대회의 조건을 고려하지 않고 음식을 주문하여 몇 개의 음식은 대회에 사용하지 못하게 되었습니다.

예를 들어, 3가지의 음식이 준비되어 있으며, 칼로리가 적은 순서대로 1번 음식을 3개, 2번 음식을 4개, 3번 음식을 6개 준비했으며, 물을 편의상 0번 음식이라고 칭한다면, 두 선수는 1번 음식 1개, 2번 음식 2개, 3번 음식 3개씩을 먹게 되므로 음식의 배치는 "1223330333221"이 됩니다. 따라서 1번 음식 1개는 대회에 사용하지 못합니다.

수웅이가 준비한 음식의 양을 칼로리가 적은 순서대로 나타내는 정수 배열 food가 주어졌을 때, 대회를 위한 음식의 배치를 나타내는 문자열을 return 하는 solution 함수를 완성해주세요.

제한사항
2 ≤ food의 길이 ≤ 9
1 ≤ food의 각 원소 ≤ 1,000
food에는 칼로리가 적은 순서대로 음식의 양이 담겨 있습니다.
food[i]는 i번 음식의 수입니다.
food[0]은 수웅이가 준비한 물의 양이며, 항상 1입니다.
정답의 길이가 3 이상인 경우만 입력으로 주어집니다.

풀이코드

using System.Linq;
using System.Text;

public class Solution {
    public string solution(int[] food) {
        var answer = new StringBuilder();

        for(var i = 1; i < food.Length; i++)
        {
            answer.Append(string.Concat(Enumerable.Repeat(i.ToString(), food[i] / 2)));
        }

        var descendingOrder = string.Concat(answer.ToString().OrderByDescending(e => e));
        answer.Append("0").Append(descendingOrder);

        return answer.ToString();
    }
}

StringBuilder를 사용하여 하나씩 Apeend하는 방식으로 풀었다.

food는 짝수여야지만 대회에 사용이 되므로 Enumerable.Repeat로 i를 food[i] / 2 만큼 반복해 answer에 Append해주었다.

정답은 대칭이므로 OrderByDescending을 사용해 역정렬을 시켜주고, answer에 0을 append해준 뒤 역정렬한 값을 또 append하여 풀었다.

두번째 알고리즘, 프로그래머스 Lv1 콜라 문제 [링크]

문제 설명
오래전 유행했던 콜라 문제가 있습니다. 콜라 문제의 지문은 다음과 같습니다.

정답은 아무에게도 말하지 마세요.

콜라 빈 병 2개를 가져다주면 콜라 1병을 주는 마트가 있다. 빈 병 20개를 가져다주면 몇 병을 받을 수 있는가?

단, 보유 중인 빈 병이 2개 미만이면, 콜라를 받을 수 없다.

문제를 풀던 상빈이는 콜라 문제의 완벽한 해답을 찾았습니다. 상빈이가 푼 방법은 아래 그림과 같습니다. 우선 콜라 빈 병 20병을 가져가서 10병을 받습니다. 받은 10병을 모두 마신 뒤, 가져가서 5병을 받습니다. 5병 중 4병을 모두 마신 뒤 가져가서 2병을 받고, 또 2병을 모두 마신 뒤 가져가서 1병을 받습니다. 받은 1병과 5병을 받았을 때 남은 1병을 모두 마신 뒤 가져가면 1병을 또 받을 수 있습니다. 이 경우 상빈이는 총 10 + 5 + 2 + 1 + 1 = 19병의 콜라를 받을 수 있습니다.

문제를 열심히 풀던 상빈이는 일반화된 콜라 문제를 생각했습니다. 이 문제는 빈 병 a개를 가져다주면 콜라 b병을 주는 마트가 있을 때, 빈 병 n개를 가져다주면 몇 병을 받을 수 있는지 계산하는 문제입니다. 기존 콜라 문제와 마찬가지로, 보유 중인 빈 병이 a개 미만이면, 추가적으로 빈 병을 받을 순 없습니다. 상빈이는 열심히 고심했지만, 일반화된 콜라 문제의 답을 찾을 수 없었습니다. 상빈이를 도와, 일반화된 콜라 문제를 해결하는 프로그램을 만들어 주세요.

콜라를 받기 위해 마트에 주어야 하는 병 수 a, 빈 병 a개를 가져다 주면 마트가 주는 콜라 병 수 b, 상빈이가 가지고 있는 빈 병의 개수 n이 매개변수로 주어집니다. 상빈이가 받을 수 있는 콜라의 병 수를 return 하도록 solution 함수를 작성해주세요.

풀이코드

public class Solution {
    public int solution(int a, int b, int n) {
        var answer = 0;
        var extra = 0;
        var remain = n;

        while(remain + extra >= a)
        {
            remain += extra;
            extra = remain % a;
            remain = (remain / a) * b;

            answer += remain;
        }

        return answer;
    }
}

remain : 남은 콜라 병 수.
extra : 남은 콜라 병 수와 교환 해주는 병 수의 나머지

반복문을 사용하여 풀었다.

유니티 팀 프로젝트 주간이다.

우리 팀은 3D 퍼즐 플랫포머 게임을 만들기로 했다.

메인이 되는 기믹은 캐릭터가 분신을 만들고, 분신과 함께 퍼즐에 상호작용 하는 것이다.

분신 조작
모드 1, 2, 3 → 본체하고 분신하고 완전히 똑같은 자격
1 : 본체 조작, 상호작용 가능
2 : 분신 조작, 상호작용 가능
3 : 동시 조작, 상호작용 가능

내가 맡은 역할은 캐릭터 제어와 분신 구현이다.

이전 프로젝트들을 하면서 기본적인 기획에 대한 중요성을 느껴 draw.io에서 기본적인 구조를 그리고 구현을 시작했다.
* 실제 구현된 것과는 구조가 좀 달라졌다.

현재 구현된 구조다. PlayerController에서 이벤트를 제어한다.
분신을 동시 조종이 가능해야되므로 CharacterControl을 받아와

onMoveEvent += characterControl.onMoveEvent;
onLookEvent += characterControl.onLookEvent;
onJumpEvent += characterControl.onJumpEvent;
onInteractEvent += characterControl.onInteractEvent;

다음 처럼 PlayerController의 Action들에 구독시켜 구현했다.

캐릭터 1만 조종할때는 캐릭터 2의 Action들을 구독 해제시켜주는 방식이고,
둘다 조종할때는 둘의 Action을 모두 구독해주는 방식이다.

다음으로 카메라 이동을 구현했다.
게임이 3인칭 시점으로 진행하기로 기획했다.
카메라는 플레이어를 따라오고, 시점은 플레이어에게 고정되어 있지만 상하좌우를 볼 수 있고, 캐릭터가 멈춰있을 땐 카메라가 회전해도 캐릭터가 움직이지 않도록 구현해야했다.

처음엔 Lerp를 이용해서 구현하려했다가, 여러 3rd person view tutorial들을 보고 cinemachine의 Virtual Camera를 사용하여 구현하기로 했다.

Virtual Camera의 Body에는 3rd Person Follow라고 3인칭 시점으로 카메라가 따라오도록 할 수 있어 카메라가 따라오는 건 해결했다.

다음으론 시점인데, Virtual Camera에 Aim에서 Same as Follow Target으로 설정해 주고 Player의 자식에 CameraFocus를 만든 뒤, CameraFocus를 보도록 설정해주었다.

그리고 CameraFocus를 마우스 움직임에 따라 회전시켜 줘 카메라 움직임을 만들어 줬다.

    private void CameraLook()
    {
        _camCurXRot += _mouseDelta.y * lookSensitivity * Time.deltaTime;
        _camCurXRot = Mathf.Clamp(_camCurXRot, minXLook, maxXLook);
        cameraVerticalFocus.localEulerAngles = new Vector3(-_camCurXRot, 0, 0);

        cameraHorizontalFocus.eulerAngles += new Vector3(0, _mouseDelta.x * lookSensitivity * Time.deltaTime);

        if (_isMoving)
            CharacterLook();
    }
    
    private void CharacterLook()
    {
        character.rotation = Quaternion.Slerp(character.rotation, cameraHorizontalFocus.rotation, 30f);
    }

작성한 코드다.

Update문에서 돌기에 deltaTime을 곱해줬고, Clamp를 해 줘 x축 회전에 대한 제한을 걸어줬다.

CharacterLook Method에 Slerp는 캐릭터가 이동할 때, 최대한 자연스럽게 회전하도록 만들어 준 것이다.

다음으로는 카메라와 캐릭터 사이에 오브젝트가 있을 때, 카메라가 캐릭터에게 가까워지도록 설정해주었다.

이건 cinemachine으로 간단하게 설정이 가능한데, CinemachineVirtualCamera의 맨 아래에 Add Extension에서 Cinemachine Collider를 추가해주면 된다.

추가한 것에서 Strategy를 Pull Camera Forward로 설정해주면 쉽게 해결된다.

0개의 댓글