본문 바로가기

iOS 앱 개발자 프로젝트/알고리즘 코드카타

[Algorithm] 공원 산책 (w/ Swift)

공원 산책

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

문자열 배열 park, 로봇 강아지가 수행할 명령이 담긴 문자열 배열 routes가 매개변수로 주어질 때, 로봇 강아지가 모든 명령을 수행 후 놓인 위치를 [세로 방향 좌표, 가로 방향 좌표] 순으로 배열에 담아 최종적으로 로봇 강아지가 명령 수행 후 놓인 위치 좌표 puppy를 return 하는 함수를 구해보자.

 

 

 

 

var map = Array(repeating: Array(repeating: "", count: w), count: h)
var puppy = [0, 0]

for i in 0..<park.count {
    map[i] = park[i].map { String($0) }
    if let startIdx = map[i].firstIndex(of: "S") {
        puppy, startIdx]
    }
}

 

park 배열을 기반으로 2차원 배열(map)을 초기화하고, 시작점 F의 위치를 찾아 puppy의 시작하는 위치를 설정한다.

w와 h변수를 사용하여 가로(w)와 세로(h)의 크기를 가지며, 모든 요소는 빈 문자열("")로 초기화 된다.

 

 

var directions = [[String]]()
for i in 0..<routes.count {
    directions.append(routes[i].split(separator: " ").map {String($0)})
}

 

2차원 배열인 directions에 문자열을 추가하는 코드 스니펫.

 

먼저 routes 배열의 요소 수만큼 반복하면서 routes[i]를 공백으로 분할하고, 각 요소를 문자열로 변환하여 directions배열에 추가한다.  즉, routes 배열의 요소를 공백으로 분할하여 directions에 추가한다.

 

+ [[String]]() 구문은 빈 2차원 문자열 배열을 초기화하는 방법이다. 배열의 크기나 내용이 정해지지 않았을 때 유용하다.

 

 

func isValid(y: Int, x: Int) -> Bool {
    // y가 0 이상 h 미만이고, x가 0 이상 w 미만일 때 true를 반환합니다.
    // 그렇지 않으면 false를 반환합니다.
    return 0 <= y && y < h && 0 <= x && x < w ? true : false
}

 

여기서 isValid 함수는 주어진 좌표 (y, x)가 특정 범위 내에 있는지를 판별하는 데 사용한다. 이 함수는 yx 좌표가 각각 0 이상 h 미만, 그리고 0 이상 w 미만일 때 true를 반환한다. (하나라도 아니면 false)

 

📌  잠깐 복습하고 가기  :  inValid 

사용 목적과 기능은 함수가 정의된 맥락에 따라 다른데 일반적으로는 어떤 값이나 조건이 유효한지 판단하는데 사용된다. 데이터 유효성 검사, 좌표 유효성 검사, 함수 인자 및 상태 검증 등 다양하게 사용할 수 있다.

 

 

위의 코드 스니펫들을 기반으로 ! 

puppy가 지도 위에서 다양한 방향으로 이동하는 시뮬레이션 구현.. 🐕 🐕  

// directions 배열의 모든 요소를 순회하는 for 루프
for i in 0..<directions.count {
    // 강아지가 다음 위치로 이동할 수 있는지 여부를 나타내는 변수. 기본값은 true
    var isNext = true

    // directions 배열의 i번째 요소의 첫 번째 문자를 기준으로 switch 문을 실행
    switch directions[i][0] {
    case "E": // "E"는 동쪽(East)으로 이동하는 경우
        // 강아지가 이동할 다음 위치를 계산 directions[i][1]에서 이동 거리를 가져와 현재 위치에 더해준다.
        next = [puppy[0], puppy[1]+Int(directions[i][1])!]
        // 다음 위치가 유효한지 확인. isValid 함수는 위치가 지도 내에 있고, 이동 가능한 위치인지 검사
        if isValid(y: next[0], x: next[1]) {
            // 현재 위치에서 다음 위치까지의 모든 위치를 순회하며 장애물("X")이 있는지 검사
            for i in puppy[1]...next[1] {
                // 장애물을 발견하면 isNext를 false로 설정하고 for 루프를 중단
                if map[next[0]][i] == "X" {
                    isNext = false
                    break
                }
            }
            // 장애물이 없으면 강아지의 위치를 다음 위치로 업데이트
            if isNext {
                puppy = next
            }
        }
        // 다른 방향에 대한 케이스도 비슷한 방식으로 구현
        ...
    }
}

 

 

 

최종 코드 

func solution(_ park:[String], _ routes:[String]) -> [Int] {
    let w = park[0].count
    let h = park.count
    
    var map = Array(repeating: Array(repeating: "", count: w), count: h)
    var puppy = [0, 0]
    var next = [0, 0]

    func isValid(y: Int, x: Int) -> Bool {
        return 0 <= y && y < h && 0 <= x && x < w ? true : false
    }

    for i in 0..<park.count {
        map[i] = park[i].map { String($0) }
        if let startIdx = map[i].firstIndex(of: "S") {
            puppy = [i, startIdx]
        }
    }
    
    var directions = [[String]]()
    for i in 0..<routes.count {
        directions.append(routes[i].split(separator: " ").map {String($0)})
    }
    
    for i in 0..<directions.count {
        var isNext = true
        
        switch directions[i][0] {
        case "E":
            next = [puppy[0], puppy[1]+Int(directions[i][1])!]
            if isValid(y: next[0], x: next[1]) {
                for i in puppy[1]...next[1] {
                    if map[next[0]][i] == "X" {
                        isNext = false
                        break
                    }
                }
                if isNext {
                    puppy = next
                }
            }

        case "W":
            next = [puppy[0], puppy[1]-Int(directions[i][1])!]
            if isValid(y: next[0], x: next[1]) {
                for i in next[1]...puppy[1] {
                    if map[next[0]][i] == "X" {
                        isNext = false
                        break
                    }
                }
                if isNext {
                    puppy = next
                }
            }
            
        case "S":
            next = [puppy[0]+Int(directions[i][1])!, puppy[1]]
            if isValid(y: next[0], x: next[1]) {
                for i in puppy[0]...next[0] {
                    if map[i][next[1]] == "X" {
                        isNext = false
                        break
                    }
                }
                if isNext {
                    puppy = next
                }
            }
            
        default:
            next = [puppy[0]-Int(directions[i][1])!, puppy[1]]
            if isValid(y: next[0], x: next[1]) {
                for i in next[0]...puppy[0] {
                    if map[i][next[1]] == "X" {
                        isNext = false
                        break
                    }
                }
                if isNext {
                    puppy = next
                }
            }
        }
    }
    return puppy
}