Algorithm/BOJ

백준 14503 로봇 청소기

삼쓰 웅쓰 2021. 3. 19. 14:04
728x90

출처: www.acmicpc.net/problem/14503

분류: 시뮬레이션


접근방식

현재 방향을 생각하면서 청소기를 돌려주면 되는 문제였습니다.

저는 현재 로봇 청소기의 위치현재 방향을 전역변수로 두고 둘을 조작해주면서 계산했습니다.

방향을 enum 타입으로 정의했고
청소기는 계속 왼쪽 방향으로 회전하기 때문에 각 방향에서 왼쪽으로 회전하는 함수를 만들었습니다.

enum Direction: Int {
    case up = 0, right, down , left
    
    mutating func turnLeft() {
        switch self {
            case .up: self = .left
            case .left: self = .down
            case .down: self = .right
            case .right: self = .up
        }
    }
}

 

현재 방향과 위치에서 앞 뒤도 계속 사용되기 때문에 computed property로 만들어줬습니다.

var front: Point {
    switch currentDir {
        case .up: return (currentPoint.r-1, currentPoint.c)
        case .left: return (currentPoint.r, currentPoint.c-1)
        case .down: return (currentPoint.r+1, currentPoint.c)
        case .right: return (currentPoint.r, currentPoint.c+1)
    }
}
var back: Point {
    switch currentDir {
        case .up: return (currentPoint.r+1, currentPoint.c)
        case .left: return (currentPoint.r, currentPoint.c+1)
        case .down: return (currentPoint.r-1, currentPoint.c)
        case .right: return (currentPoint.r, currentPoint.c-1)
    }
}

 

 

그리고 네 방향에 청소할 곳이 있는지 확인하는 함수를 하나 만들었는데요,
가능하다면 해당 위치로 바꿔주고 true를 아니라면 false를 리턴해주도록 했습니다.

func availableNextClean() -> Bool {
    for _ in 0..<4 {
        currentDir.turnLeft()
        if map[front.r][front.c] == 0 {
            currentPoint = front
            return true
        }
    }
    return false
}

 

마지막으로 이를 종합해주면 됩니다.

현재 위치가 벽일 때까지 while문을 돌렸는데요,
현재 위치를 청소해야하면 하고 (청소하고나면 2로 바꿔줬습니다.)
아니라면 다음 위치로 이동이 가능한지 확인하고
못한다면 빽을 해줬습니다. (빽을 한 위치가 벽이라면 다음 턴에서 종료되겠죠 :))

func runCleaner() {
    while map[currentPoint.r][currentPoint.c] != 1 {
        if map[currentPoint.r][currentPoint.c] == 0 {
            map[currentPoint.r][currentPoint.c] = 2
            cleanCount += 1
        }
        
        if !availableNextClean() {
            currentPoint = back
        }
    }
}

 

 

 

해결방법

// 14503 로봇청소기
let nm = readLine()!.split(separator: " ").map { Int(String($0))! }
let rcd = readLine()!.split(separator: " ").map { Int(String($0))! }
var map = [[Int]]()
for _ in 0..<nm[0] {
    map.append(readLine()!.split(separator: " ").map { Int(String($0))! })
}

typealias Point = (r: Int, c: Int)
enum Direction: Int {
    case up = 0, right, down , left
    
    mutating func turnLeft() {
        switch self {
            case .up: self = .left
            case .left: self = .down
            case .down: self = .right
            case .right: self = .up
        }
    }
}

var currentDir = Direction(rawValue: rcd[2])!
var currentPoint = Point(rcd[0], rcd[1])
var front: Point {
    switch currentDir {
        case .up: return (currentPoint.r-1, currentPoint.c)
        case .left: return (currentPoint.r, currentPoint.c-1)
        case .down: return (currentPoint.r+1, currentPoint.c)
        case .right: return (currentPoint.r, currentPoint.c+1)
    }
}
var back: Point {
    switch currentDir {
        case .up: return (currentPoint.r+1, currentPoint.c)
        case .left: return (currentPoint.r, currentPoint.c+1)
        case .down: return (currentPoint.r-1, currentPoint.c)
        case .right: return (currentPoint.r, currentPoint.c-1)
    }
}

var cleanCount = 0

func availableNextClean() -> Bool {
    for _ in 0..<4 {
        currentDir.turnLeft()
        if map[front.r][front.c] == 0 {
            currentPoint = front
            return true
        }
    }
    return false
}

func runCleaner() {
    while map[currentPoint.r][currentPoint.c] != 1 {
        if map[currentPoint.r][currentPoint.c] == 0 {
            map[currentPoint.r][currentPoint.c] = 2
            cleanCount += 1
        }
        
        if !availableNextClean() {
            currentPoint = back
        }
    }
}

runCleaner()
print(cleanCount)

 

배운점

구현이 쬐끔 오래걸렸고 back 구현에서 위랑 아래를 거꾸로 써서 2번 예제를 한 40 몇번까지 디버깅했던 것 같다... 후우....ㅂㄷㅂㄷ

그리고 문제에서 서쪽이 1인데 동쪽을 1로 하고 돌려서 틀려서 또 애를 먹었따..

실수 그만!!!