본문 바로가기

Computer Science/알고리즘

[Swift]세탁 횟수 문제 구현 2

이전 포스팅에 이어, normalLaundrySimulator의 반복문 내에 들어갈 동작을 구현해 보자.

 

먼저 가장 안쪽 반복문 부분((1)에 해당)을 정의를 할 텐데, 해당 반복문은 이전 세탁과 다음 세탁 사이의 날들에 대한 부분이다. 다시 말해 그날그날 속옷을 입을지 결정하고, 다 입은 속옷을 세탁바구니에 넣는 작업까지 하게 된다. 

 

어떤 날, 속옷을 입을지 말지는 확률에 의해 정해지도록 설계하였다. 그리고 이러한 확률이 매개변수로 전달되도록 지난 포스팅에서 함수의 정의 부분을 설명한 바 있다. 이러한 확률과 Swift가 제공하는 random 함수를 사용하여 그날그날 속옷을 입을지 말지 결정하였다.

let isPossible: Bool = { Double.random(in: 0.0 ..< 1.0) < possibility }()

 

그리고 해당 상수를 기반으로 조건문을 작성해 주어, 속옷을 입는 날에 대한 정의를 해주었다. 속옷을 입으려면 당연히 속옷을 선택해야 한다. 이 선택의 기준은 역시 지난 시간에 매개변수로 전달한 priority에 의해 결정된다. 아래와 같이 priority에 따라 속옷을 어떻게 결정할지 정해주게 된다.

if isPossible {                                 // 속옷 입는 날
    var selectedIndex: Int
    
    switch priority {                           // priority에 따라 어떤 속옷을 꺼낼지 정함
    case .lastInFirstOut:
        selectedIndex = washedBasket.count - 1
    case .randomly:
        selectedIndex = Int.random(in: 0 ..< washedBasket.count)
    case .byPreference:
        selectedIndex = washedBasket.maxPreferredIndex!
    }
    
    laundryBasket.append(washedBasket.remove(at: selectedIndex))    // 선택된 속옷을 사용 후에 바구니1에 넣기
}
day += 1

 

lastInFirstOut과 randomly를 선택하는 경우는 코드만 봐도 쉽게 이해할 수 있을 것이다. 문제는 선호도에 따른 선택인데, 위와 같이 코드를 구현해 주기 다음과 같이 Array 구조체에 maxPreferredIndex라는 연산 속성을 정의해 주었다. 현재 속옷이 들어있는 바구니(Basket)에서 속옷을 스캔하며, 가장 선호도가 높은 속옷의 인덱스를 반환하는 연산 속성이다.

extension Array where Element == Stuff {
    
    // 선호도가 가장 높은 Stuff의 인덱스 반환
    var maxPreferredIndex: Int? {
        if self.isEmpty { return nil }
        
        var tmpMaxPreferredIndex: Int = 0
        var tmpMaxPreference: Int = self[0].preference
        
        for i in 1 ..< self.count {
            let tmpPreference: Int = self[i].preference
            if tmpPreference > tmpMaxPreference {
                tmpMaxPreferredIndex = i
                tmpMaxPreference = tmpPreference
            }
        }
        
        return tmpMaxPreferredIndex
    }
}

 

그다음 선택된 인덱스에 해당하는 속옷을 washedBasket(서랍)에서 빼내고, laundryBasket(세탁 바구니)에 넣으면 된다. 그다음 그날 속옷을 입는지에 상관없이 day값을 하나 증가시켜주면, 하루가 지난다.

 

이제 세탁할 때가 되었으므로, 세탁을 하면 된다. 세탁을 간편하게(?) 하기 위해 Array 구조체에 두 가지 메서드를 추가해 주었다.

extension Array where Element == Stuff {
    // 현재 바구니에 있는 옷을 다른 바구니로 옮기기
    mutating func move(to basket: inout Basket) {
        basket.append(contentsOf: self)     // 다른 바구니로 옮기기
        self.removeAll()                    // 현재 바구니 비우기
    }
    
    // 현재 바구니에 있는 옷을 세탁한 뒤, 다른 바구니로 옮기기
    mutating func doTheWash() {
        self.forEach { $0.wash() }              // 옷 세탁
        self.shuffle()                          // 세탁 시에 옷이 섞임
    }
}

 

먼저 move 메서드는 현재 바구니에 있는 속옷을 다른 바구니로 옮기는 함수이다. 당연하지만 지정된 배열로 원소들을 옮기면 이전 배열에 있던 원소는 없애주어야 한다.

 

다음은 doTheWash 메서드이다. Array 안에 있는 원소들을 순회하면서 Stuff 클래스에서 정의해준 wash() 메서드를 실행시키는 함수다. 중요한 것은 세탁을 한 뒤에 Array 안에 있는 원소들을 섞어준다는 것이다. 세탁기를 돌린 후에는, 모든 세탁물이 섞이기 마련이다.

 

이렇게 두 메서드를 정의한 뒤에 바깥쪽 반복문 부분((2)에 해당)을 다음과 같이 정의해 주면 된다. 사실 laundryBasket에서 세탁기로 이동하고, 세탁기에서 washedBasket으로 이동하는 것이 맞지만, 결과적으로 차이가 없어, 세탁 뒤에 바로 laundryBasket에서 washedBasket으로 속옷들을 옮겼다.

laundryBasket.doTheWash()                           // 세탁하기
laundryBasket.move(to: &washedBasket)               // 바구니2에 넣기
washedNumber += 1

 

이제 마지막으로 while문 바깥 부분((3)에 해당)을 구현해 주면 된다. 사실 이 부분은 동작에 대한 것이 아니라 시뮬레이션 결과에 대한 부분이다. 각각의 속옷의 상태를 띄우고 해당 속옷들을 return하면 된다.

underwears.forEach { $0.displayState() }
return underwears

 

드디어 시뮬레이션 작성이 끝이 났다. 다음 포스팅에서 매개변수에 따라 결과가 어떻게 달라지는지 확인해 보자.