프로그래머스 - 빛의 경로 사이클 (Lv. 2)

OQ·2022년 3월 17일
0

프로그래머스

목록 보기
19/33

문제 링크

풀이

import Foundation

func solution(_ grid:[String]) -> [Int] {
    var nodes: [[Node]] = []
    (0..<grid.count).forEach { _ in // nodes 행 채우기
        nodes.append([])
    }

    let args = grid.map { $0.map { String($0) } }
    for (i, arg) in args.enumerated() {
        for (j, str) in arg.enumerated() {
            let node = Node(Node.NType(rawValue: str)!)
            if i != 0 { // 첫 행이 아니라면
                node.uNode = nodes[i - 1][j]
                nodes[i - 1][j].dNode = node
                
                if i == grid.count - 1 {    // 마지막 행
                    node.dNode = nodes[0][j]
                    nodes[0][j].uNode = node
                }
            }
            
            if j != 0 { // 첫 열이 아니라면
                node.lNode = nodes[i][j - 1]
                nodes[i][j - 1].rNode = node
                
                if j == arg.count - 1 { // 마지막 열
                    node.rNode = nodes[i][0]
                    nodes[i][0].lNode = node
                }
            } 
            
            nodes[i].append(node)
        }
    }
    
    var result: [Int] = []
    
    nodes.forEach {
        $0.forEach {
            for direction in Node.Direction.allCases {
                var count = 0
                var nextDirection = direction
                var nextNode =  $0
                while let args = nextNode.next(nextDirection) {
                    count += 1
                    nextDirection = args.0
                    nextNode = args.1
                }

                if count != 0 {
                    result.append(count)   
                }
            }
        }
    }
    
    result = result.sorted(by: <)
    
    return result
}

class Node {
    enum NType: String {
        case S = "S"
        case L = "L"
        case R = "R"
    }
    
    enum Direction: CaseIterable {
        case left
        case right
        case up
        case down
        
        // 다음에 갈 방향
        func next(_ type: NType) -> Direction {
            switch type {
                case .S:
                    return self
                case .L:
                    switch self {
                        case .left:
                            return .down
                        case .right:
                            return .up
                        case .up:
                            return .left
                        case .down:
                            return .right
                    }
                case .R:
                    switch self {
                        case .left:
                            return .up
                        case .right:
                            return .down
                        case .up:
                            return .right
                        case .down:
                            return .left
                    }
            }
        }
    }
    
    let type: NType
        
    // 한번 거친 노드는 nil 대입한다.
    var lNode: Node? // 왼쪽 노드
    var rNode: Node? // 오른쪽 노드
    var uNode: Node? // 위쪽 노드
    var dNode: Node? // 아래쪽 노드
    
    init(_ type: NType) {
        self.type = type
        self.lNode = self
        self.rNode = self
        self.uNode = self
        self.dNode = self
    }
    
    func next(_ direction: Direction) -> (Direction, Node)? {
        let nextDirection = direction.next(type)
        switch nextDirection {
            case .left:
                if let nextNode = lNode {
                    lNode = nil
                    return (nextDirection, nextNode)
                } else {
                    return nil  // 한번 지나간적 있을경우
                }
            case .right:
                if let nextNode = rNode {
                    rNode = nil
                    return (nextDirection, nextNode)
                } else {
                    return nil
                }
            case .up:
                if let nextNode = uNode {
                    uNode = nil
                    return (nextDirection, nextNode)
                } else {
                    return nil
                }
            case .down:
                if let nextNode = dNode {
                    dNode = nil
                    return (nextDirection, nextNode)
                } else {
                    return nil
                }
        }
    }
}

후기

그래프에 대한 이해도가 요구되는 문제.
코드가 상당히 길어졌지만 머리속에 그래프를 그려놓고 이동되는걸 상상하면서 차근차근 풀었다.
아직 따끈따끈한 문제인지 몰라도 프로그래머스 다른사람의 풀이에서 Swift 부분 21번째로 올려졌다!
내가 전체 Swift 개발자 중에서 21번째로 푼 사람인 듯 하다!ㅋㅋ

profile
덕업일치 iOS 개발자

0개의 댓글