TIL

[멋쟁이사자처럼 부트캠프 TIL회고] Unity 게임개발 16일차

Cadi 2024. 12. 5. 00:33

 

 

Stack

기본 개념


Stack 

  • LIFO(Last IN First Out) 형식의 자료 구조
  • 뒤로가기, 트레이서 점멸 등의 예시를 들 수 있음

Stack의 구현

public class StackNode<T>
{
    public T data;
    public StackNode<T> prev;
    //오늘은 생성자를 사용하지 않는 방식, 이렇게도 짜고
    //저렇게도 짜고 그런다를 표현하려고
}

public class StackCustom<T> where T: new()
{
    public StackNode<T> top;

    public void Push(T data)
    {
        var stackNode = new StackNode<T>();

        stackNode.data = data;
        
        stackNode.prev = top;
        top = stackNode;
    }

    public T Pop()
    {
        if (top == null)
        {
            //없으면 비어있는 데이터값을 표현함
            return new T();
        }
        var result = top.data;
        top  = top.prev;

        return result;

    }

    public T Peak()
    {
        if (top == null)
        {
            return new T();
        }

        return top.data;
    }
}

 

우선 표현을 알아보면 Push는 스택 데이터를 추가하는 것, Pop은 맨 마지막(위) 데이터를 삭제하는 것, Peak는 마지막 데이터를 호출하는 것이다. 

 기본이 되는 StackNode 변수를 만들고, top 이라고 이름붙여준다. 

 

Push

stackNode 라는 변수에 새로운 StackNode<T>() 값을 할당한다. 

stackNode<T>()는 데이터와 이전 노드를 향하는 주소가 포함된 값이다. 

데이터를 먼저 할당해준다. 

우리는 데이터의 맨 끝(위)에 새로운 데이터를 push할 것이므로 새로운 노드의prev를 Top으로 할당해준다.

그리고 새로운 노드를 Top 변수에 할당한다. 

 

Pop

하나씩 지우는 Pop 함수를 만들 것이다.

우선 데이터가 없으면 지울수 없으므로, top 값이 null 이면 빈 데이터를 출력한다.

만일 top 값이 nul이 아니라면, top의 이전 값을 top이라고 할당한다. 

*여기서는 garbage collecter에 의해 자동으로 지워지는건가 ?

 

Peak

top 값을 표현하는 함수다.

top 값이 null이라면 빈 데이터를 반환하고,

top 값이 null이 아니라면 top.data를 반환한다.

 

 

* where T : new()  ->  T는 new를 사용할 것이다라는 문법.

 

 

 

Stack의 구현

 

Stack이라는 자료구조를 이동한 곳의 데이터를 저장하고, 되돌리는 기능을 통해 연습해보았다. 

 void Update()
    {
        Vector3 movePos = Vector3.zero;

        if (Input.GetKey(KeyCode.W))
        {
            movePos += transform.forward;
        }
        if (Input.GetKey(KeyCode.S))
        {
            movePos -= transform.forward;
        }
        if (Input.GetKey(KeyCode.D))
        {
            movePos += transform.right;
        }
        if (Input.GetKey(KeyCode.A))
        {
            movePos -= transform.right;
        }
          transform.position += movePos.normalized * Speed2 * Time.deltaTime;

    }

가벼운 이동 함수

 

이제 키를 눌렀을 때의 위치를 저장하고, space키를 누르면 그 위치로 돌아가는 기능을 구현해본다.

우선 변수를 선언하고, 기본값을 할당해준다.

그리고 위치를 stack형으로 저장하기 위한 변수를 생성하고 기본값을 할당한다.

키를 눌렀을 때, 그 위치가 stack형 자료에 입력되게 만든다.(psuh)

그리고 특정 키(space)를 눌렀을 때, 위치를 stack형 자료의 맨 윗값으로 옮기며 동시에 pop 되게 한다. 

(그래야 또 눌렀을 때 이전 값으로 돌아감)

 

 //움직였던 정보를 기록하기 위해 키를 땔때마다 위치를 이동한다.
        if (Input.GetKeyDown(KeyCode.W) ||
            Input.GetKeyDown(KeyCode.A) ||
            Input.GetKeyDown(KeyCode.S)||
            Input.GetKeyDown(KeyCode.D))

        {
            movePos = Vector3.zero;
            position_Stack.Push(transform.position);
            Debug.Log(position_Stack.Peek());
        }
        
        //왔던 포지션으로 되돌아가는 코드
        if (Input.GetKeyDown(KeyCode.Space))
        {
            if (position_Stack.Count > 0)
                positionRedo_Stack.Push(transform.position);
                transform.position = position_Stack.Pop();
        }

 

* 변수 할당은 제외했다. 

 

 

추가적으로 혼자 undo를 redo하는 기능을 해봤다.

 if (Input.GetKeyDown(KeyCode.LeftShift))
        {
            if (positionRedo_Stack.Count > 0)
            {
                transform.position = positionRedo_Stack.Pop();
            }
        }

*마찬가지로 변수 할당은 제외했다.

 

이를 적용해보면 다음과 같은 움직임이 나온다. 

 

Stack의 구현(2)

 이제 괄호가 알맞게 들어갔는지 확인하는 로직을 만들어본다. 

구현하고 싶은 기능

  • 괄호가 열리고 잘 닫혔는지 ( 만약  '()(' 이거나 '())' 라면 false가 출력되는 기능)
  • 괄호의 짝은 잘 맞는지         ( 만약  '({)}' 라면 false가 출력되는 기능)

구현을 기능하기 위해 다음과 같은 과정을 거친다. 

  1. 문자열을 입력값으로 받고, 리턴값은 bool값인 함수 AreBracketBalanced를 만든다.
  2.  stack형이고 문자(char) 데이터를 받는 함수 stack을 선언하고 기본값을 할당한다.
  3. 모든 text의 문자를 char 형 변수 c에 할당하면서 반복한다.
    -1 만약 c가 '(', '{', '[' 라면  push(c) 를 한다. 
    -2 만약 c가 ')','}',']' 라면 stack count를 한다
         -1 stack count가 0이라면 false를 return한다.
         -2 stack count가 0이 아니라면 pop()을 하고 그 결과를 top 에 저장한다.
              -1 pop을 했을 때, c값과 top 값이 짝이 맞지 않으면 false를 return한다.
  4. 마지막으로 모든 과정을 했을 때, stack.count가 0이라면, true를 return한다.

코드 구현

 public bool AreBracketsBalanced(string expression)
    {
      Stack<char> stack = new Stack<char>();

      foreach (char c in expression)
      {
          if (c == '(' || c == '{' || c == '[')
          {
              stack.Push(c);
          }
          else if (c == ')' || c == '}' || c == ']')
          {
              if (stack.Count == 0)
              {
                  return false;
              }
                 char top = stack.Pop();
                 if (c == ')' && top != '(' ||
                     c == '}' && top != '{' ||
                     c == ']' && top != '[')
                 {
                     return false;
                 }
              
                  
          }
      }

      return stack.Count == 0; 
    }

 

 

 

 

*log는 키를 눌렀을때 로그를 기록한 것이다. 

 

더 공부해야 할 것들

코딩에서 in

 

프로퍼티

 

Assert();

 

LayoutComponent() 오늘 수업시간중 배웠으나, 내가 벌써 건들 내용은 아니라고 생각함.

 

overridng

 

serialized, 직렬화 : 어떤 기법을 써서 가져오고 업뎃해준다.

 

where T : new() 라는 것의 정확한 의미

 

깊이 우선 탐색

 

후위 표기법