디자인 패턴 - 3 [Feat. 재귀함수, BFS 문제]

이준호·2024년 1월 28일
0

📌 더티 플래그 패턴

더티플래그 패턴은 중복적인 연산을 효율적으로 처리하기 위한 디자인 패턴이다. 이 패턴은 한번에 연산하거나 값을 호출하기 전까지 해당 연산을 수행하지 않는 방식으로 작동한다.

  • 장점

    • 중복적인 연산을 크게 줄일 수 있다.
  • 고려사항

    • 이전 값을 저장해야 한다.
    • 변경이 있는지 계속 체크해야 한다.

Transform.Translate ➔ 이동에 회전을 적용하는 연산을 한다음에 이동
Transform.Rotate ➔ 지금 어떤 회전이 걸려있고 그거에 대해서 행렬연산
Transform.SetPositionAndRotation ➔ Transform의 위치와 회전을 모두 설정할 때, 각각 개별적으로 할당하는 것보다 더 효율적

➔ 예시 : 트랜스폼 업데이트

트랜스폼의 자식들은 부모의 이동에 의해 영향을 받는다.




➔ 유사 예시 : LINQ Lazy Evaluation

static Func<int, bool> func; //int를 인자로 받아 bool을 반환하는 Func

static void Main(string[] args)
{
 	List<int> list = new List<int> { 1, 2, 3, 4, 5, 6, 7 };
  	func = (x) =>
            {
             Console.WriteLine("Func Executed");
             return x % 2 == 0; 
            };

	Console.WriteLine("==Where==");
	IEnumerable<int> whereList = list.Where(func);  //.ToArray();넣으면 최종결과로 인식

	Console.WriteLine("==Foreach==");
	foreach(int i in whereList)
    {
    	Console.WriteLine(i);
    }
}
/////////////////////////
.ToArray() // 결과화해버리면 그냥 끝이다.

==Where==
==Foreach==
Func Executed
Func Executed
2
Func Executed
Func Executed
4

==Where==
Func Executed
~~ X7
==Foreach==
2
4
6











📌 상태 패턴

유한 상태 기계(Finite State Machine, FSM)은 객체의 동작이 내부 상태에 따라 달라지는 상황에서 사용되는 개념이다. 이러한 상황에서 상태 패턴(State Pattern)은 유용하게 활용된다. 상태 패턴은 객체의 상태를 클래스로 추상화하고, 각 상태마다 해당 상태에서의 동작을 정의한다. 객체는 현재 상태에 따라 동작을 수행하며, 상태 전환을 통해 다른 동작을 수행할 수 있다.

예를 들어, 플레이어의 상태를 관리하는 경우를 생각해보면 플레이어는 여러 가지 상태를 가질 수 있으며, 각 상태에서는 특정 동작을 수행한다. 상태 패턴을 사용하면 플레이어의 상태 관리가 간편해지고, 새로운 상태를 추가하거나 기존 상태를 변경하는 것도 쉬워진다. 또한, 각 상태의 동작을 분리하여 유지보수성을 높일 수 있다.

➔ 예시 - 플레이어 상태관리

// 플레이어 상태 인터페이스
public interface IPlayerState
{
    void EnterState(Player player);
    void ExitState(Player player);
    void UpdateState(Player player);
}

// 정지 상태 클래스
public class IdleState : IPlayerState
{
    public void EnterState(Player player)
    {
        player.AnimateIdle();
    }

    public void ExitState(Player player) { }

    public void UpdateState(Player player)
    {
        if (player.IsMoving)
        {
            player.ChangeState(new MoveState());
        }
    }
}

// 이동 상태 클래스
public class MoveState : IPlayerState
{
    public void EnterState(Player player)
    {
        player.AnimateMove();
    }

    public void ExitState(Player player) { }

    public void UpdateState(Player player)
    {
        if (!player.IsMoving)
        {
            player.ChangeState(new IdleState());
        }
    }
}

// 플레이어 클래스
public class Player
{
    private IPlayerState currentState;

    public bool IsMoving { get; set; }

    public Player()
    {
        currentState = new IdleState();
    }

    public void ChangeState(IPlayerState newState)
    {
        currentState.ExitState(this);
        currentState = newState;
        currentState.EnterState(this);
    }

    public void Update()
    {
        currentState.UpdateState(this);
    }

    public void AnimateIdle()
    {
        // 정지 상태 애니메이션 재생
    }

    public void AnimateMove()
    {
        // 이동 상태 애니메이션 재생
    }
}











📌 재귀, BFS 알고리즘 문제

➔ 알고리즘 문제 접근방식

  • 제한사항 꼼꼼히 확인.

  • 입출력 예시 꼭 확인. (뇌피셜 금지)

  • 내가 가지고 있는 무기 확인.
    (자료구조, 알고리즘 지식, 과거 문제 풀이 경험 등등)




➔ 문제 해설

[142] 하노이의 탑

using System;
using System.Collections.Generic;

public class Solution {
    public List<int[]> Move(int where, int to, int pass, int num) {
        List<int[]> result = new List<int[]>();
		
        // n개 짜리 탑이 1개라면 바로 옮긴다.
        if (num == 1) {
            result.Add(new int[] { where, to });
            return result;
        }
        // n개의 탑을 n-1개의 탑으로 보내는 프로세스
        // 1. n-1개 짜리 탑을 2번으로 보내라
        result.AddRange(Move(where, pass, to, num - 1));
        // 2. n번째 탑을 3번으로 보내라
        result.Add(new int[] { where, to });
        // 3. n-1개 짜리 탑을 3번으로 보내라
        result.AddRange(Move(pass, to, where, num - 1));

        return result;
    }

    public int[,] solution(int n) {
        List<int[]> resultList = Move(1, 3, 2, n);
        int rowCount = resultList.Count;
        int[,] array = new int[rowCount, 2];

        for (int i = 0; i < rowCount; i++) {
            array[i, 0] = resultList[i][0];
            array[i, 1] = resultList[i][1];
        }

        return array;
    }
}



[143] 미로 탈출

using System;
using System.Collections.Generic;

public class Solution {
    public int solution(string[] maps) {
        
        return FindShortestPath(maps);
    }

    public char[,] ConvertTo2DArray(string[] input) {
        int rows = input.Length;
        int cols = (rows > 0) ? input[0].Length : 0;
        char[,] result = new char[rows, cols];

        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                result[i, j] = input[i][j];
            }
        }

        return result;
    }

    private int BFS(char[,] grid, Tuple<int, int> start, Tuple<int, int> end, char[] validChars) {
        int rows = grid.GetLength(0);
        int cols = grid.GetLength(1);
        bool[,] visited = new bool[rows, cols];
        // Tuple contains row, col, and distance
        Queue<Tuple<int, int, int>> queue = new Queue<Tuple<int, int, int>>(); 

        queue.Enqueue(new Tuple<int, int, int>(start.Item1, start.Item2, 0));
        visited[start.Item1, start.Item2] = true;

        int[] dr = new int[] { -1, 1, 0, 0 };
        int[] dc = new int[] { 0, 0, -1, 1 };

        while (queue.Count > 0) {
            var current = queue.Dequeue();
            int row = current.Item1, col = current.Item2, distance = current.Item3;

            if (row == end.Item1 && col == end.Item2) {
                return distance;
            }

            for (int i = 0; i < 4; i++) {
                int newRow = row + dr[i];
                int newCol = col + dc[i];

                if (IsValidMove(newRow, newCol, rows, cols, grid, visited, validChars)) {
                    queue.Enqueue(new Tuple<int, int, int>(newRow, newCol, distance + 1));
                    visited[newRow, newCol] = true;
                }
            }
        }

        return -1; // No path found
    }
    
        private bool IsValidMove(int newRow, int newCol, int rows, int cols, char[,] grid, bool[,] visited, char[] validChars) {
        // Check if the new position is within the grid boundaries
        bool isInBounds = newRow >= 0 && newRow < rows && newCol >= 0 && newCol < cols;
        // Check if the position has not been visited and is a valid character
        bool isValidPosition = isInBounds && !visited[newRow, newCol] && Array.IndexOf(validChars, grid[newRow, newCol]) >= 0;

        return isValidPosition;
    }

    public int FindShortestPath(string[] input) {
        var grid = ConvertTo2DArray(input);
        Tuple<int, int> start = null, endL = null, endE = null;

        // Find positions of S, L, and E
        for (int i = 0; i < grid.GetLength(0); i++) {
            for (int j = 0; j < grid.GetLength(1); j++) {
                if (grid[i, j] == 'S') start = Tuple.Create(i, j);
                else if (grid[i, j] == 'L') endL = Tuple.Create(i, j);
                else if (grid[i, j] == 'E') endE = Tuple.Create(i, j);
            }
        }

        // S-> L갈 때 O, L, E만 밟을 수 있고, 
        int distanceSL = BFS(grid, start, endL, new char[] { 'O', 'L', 'E' });
        int distanceLE = BFS(grid, endL, endE, new char[] { 'O', 'S', 'E' });

        if (distanceSL == -1 || distanceLE == -1) return -1; // No path found

        return distanceSL + distanceLE;
    }
}
profile
No Easy Day

0개의 댓글