본문 바로가기
Xcode/Swift - Algorithm

Swift ) 프로그래머스(Lv2) - [1차]프렌즈4블록 (Simulation)

by 후르륵짭짭 2020. 9. 8.
728x90
반응형

programmers.co.kr/learn/courses/30/lessons/17679

 

코딩테스트 연습 - [1차] 프렌즈4블록

프렌즈4블록 블라인드 공채를 통과한 신입 사원 라이언은 신규 게임 개발 업무를 맡게 되었다. 이번에 출시할 게임 제목은 프렌즈4블록. 같은 모양의 카카오프렌즈 블록이 2×2 형태로 4개가 붙��

programmers.co.kr

안녕하세요! 후르륵짭짭 입니다.

이 문제는 백준의 뽀요뽀요 문제랑 비슷합니다.

그냥 빡!! 구현 문제 입니다.

그럼 바로 알아 가보도록 하겠습니다.

 

** 저의 풀이 **

더보기
// 1 : 22
var check : [[Bool]] = []
var breakBlock : Int = 0

func solution(_ m:Int, _ n:Int, _ board:[String]) -> Int {
    
    var map : [[String]] = []
    
    for element in board {
        let temp = element.map { (char) -> String in
            return String(char)
        }
        map.append(temp)
    }
    
    
    var flag = true
    
    while flag == true {
        
    flag = false
        
    check = Array(repeating: Array(repeating: true , count: n), count: m)
    
    for y in 0..<m{
        
        for x in 0..<n {
                
            if checkIs4(map, x, y) {
                flag = true
            }
            
        }
        
    }
    
    moveItme(&map)
    
    for element in map{
        print(element)
    }
        print(flag)
        
        
    }
    
    
    return breakBlock
}

func checkIs4(_ map : [[String]],_ x : Int, _ y: Int) -> Bool{
    
    let start = map[y][x]
    
    let LR = [1,1,0,0]
    let UD = [1,0,1,0]
    
    if start != " " {
    
    if x >= 0 && x < map[0].count - 1 && y >= 0 && y < map.count - 1{
        
        if map[y + 1][x + 1] == start && map[y][x + 1] == start && map[y + 1][x] == start {
            
            for go in 0..<4{
                
                if check[y + UD[go]][x + LR[go]] == true {
                    breakBlock += 1
                }
                check[y + UD[go]][x + LR[go]] = false
            }
            
            return true
        }
        
    }
        
    }
    
    return false
}

func moveItme(_ map : inout [[String]]){
    
    for x in 0..<map[0].count {
        
        var down = map.count - 1
        var cnt = 0
        
        while down >= 0 {
            
            if !check[down][x]{
                cnt += 1
            }
            else if check[down][x] && cnt > 0 {
                
                let item = map[down][x]
                map[down + cnt][x] = item
                check[down + cnt][x] = true

                for start in down..<(down+cnt) {
                    check[start][x] = false
                    map[start][x] = " "
                }
                
            }
            
            down -= 1
            
        }

        for start in 0..<cnt {
//            print(start, x)
            check[start][x] = false
            map[start][x] = " "
        }
        
        
        
    }
    
}

코드가 너무 길어서 줄이도록 하겠습니다.

    var map : [[String]] = []
    
    for element in board {
        let temp = element.map { (char) -> String in
            return String(char)
        }
        map.append(temp)
    }
    

일단 이렇게 문자열로 된 지도를 2차원 배열로 만들어 줍니다.

 

func checkIs4(_ map : [[String]],_ x : Int, _ y: Int) -> Bool{
    
    let start = map[y][x]
    
    let LR = [1,1,0,0]
    let UD = [1,0,1,0]
    
    if start != " " {
    
    if x >= 0 && x < map[0].count - 1 && y >= 0 && y < map.count - 1{
        
        if map[y + 1][x + 1] == start && map[y][x + 1] == start && map[y + 1][x] == start {
            
            for go in 0..<4{
                
                if check[y + UD[go]][x + LR[go]] == true {
                    breakBlock += 1
                }
                check[y + UD[go]][x + LR[go]] = false
            }
            
            return true
        }
        
    }
        
    }
    
    return false
}

그리고 이렇게 4개가 동일한 모양인지 확인을 해줍니다.

그런데 여기서 주의 해야할 것은 

라이언 라이언 라이언

라이언 라이언 라이언 

이렇게 가운데 라이언이 중복 될 경우에는 부수는 벽돌을 계산 해주면 안되기 때문에 

경우를 나눠주고 check를 false로 바꿔 줍니다. check 배열은 파괴 됐는지 안됐는지 확인용 입니다.

 

func moveItme(_ map : inout [[String]]){
    
    for x in 0..<map[0].count {
        
        var down = map.count - 1
        var cnt = 0
        
        while down >= 0 {
            
            if !check[down][x]{
                cnt += 1
            }
            else if check[down][x] && cnt > 0 {
                
                let item = map[down][x]
                map[down + cnt][x] = item
                check[down + cnt][x] = true

                for start in down..<(down+cnt) {
                    check[start][x] = false
                    map[start][x] = " "
                }
                
            }
            
            down -= 1
            
        }

        for start in 0..<cnt {
//            print(start, x)
            check[start][x] = false
            map[start][x] = " "
        }
        
        
        
    }
    
}

이 방법은 위에서 그린 것 처럼

세로줄 맨 마지막 부터 확인 해서 올라가는 방식 입니다. 그래서 check가 false인 곳 파괴된 곳이라면 파괴 안된 것을 몇칸 아래로 내려 줄지

알려주는 cnt 갯수를 증가시켜주고 파괴 안된 것을 만나면 그 파괴 안 된 것을 올라온 갯수 만큼 내려주게 됩니다. 

그리고 당연히 내려줬으니 기존에 있던 장난감을 false로 만들어줘야합니다.

이러한 과정이 끝났는데, 만약에 파괴 되지 않는 것을 만나지 않고 끝나면 과정을 마무리를 마치고 끝나기 때문에 

마지막에도 " " 로 만들어주는 과정을 해줍니다.

예를 들어 

let m = 2
let n = 2
var board = ["AA", "AA"]

이런 경우를 말하는 겁니다.

 

    while flag == true {
        
    flag = false
        
    check = Array(repeating: Array(repeating: true , count: n), count: m)
    
    for y in 0..<m{
        
        for x in 0..<n {
                
            if checkIs4(map, x, y) {
                flag = true
            }
            
        }
        
    }
    
    moveItme(&map)
 
        
    }

이제 마지막으로 파괴가 되지 않을 경우가 나올 때 까지 이 과정을 반복 해줍니다.

 

나름 처리해줘야할게 많은 빡구현 문제 였습니다....

예전에 현대카드에서도 이런 문제가 나왔는데,,,

 

728x90
반응형

댓글