본문 바로가기

Computer Science/알고리즘

[Swift]세탁 횟수 같게 만들기 2 - 모든 속옷의 세탁 횟수 같게 만들기

지난 시간에 세탁 횟수에 영향을 미치는 요인 중, 2번 "입을 속옷을 선택하는 방법"에 대해 생각해 보았다. 그 결과, 세탁된 속옷을 서랍에 넣기 전에 임시 바구니를 거치도록 하여 모든 속옷이 사용되게 하였다.

 

이를 추가한 세탁 라이프는 다음과 같다.

이번엔 5 단계의 반복으로 표현된다.

  1. 사용자가 그날 속옷을 입기로 하였다면 서랍에서 속옷을 꺼내 입는다.
  2. 서랍이 비었다면 건조대에서 서랍으로 속옷을 옮긴다.
  3. 속옷을 사용하고 난 뒤 세탁 바구니에 넣는다.
  4. 세탁하는 날이 되면 세탁 바구니에 있는 속옷을 세탁한다.
  5. 건조가 다 된 속옷을 건조대에 그대로 둔다.

 

이제 세탁 횟수에 영향을 미치는 요인 중, 1번 "일정하지 않은 세탁물의 양"을 살펴보자. 세탁물의 양이 일정하지 않게 되는 현상은 사용자가 그날 속옷을 입을지 말지 모른다는 불확실성에서 기인한다. 그렇다면 세탁할 속옷이 일정량 찼을 때만 세탁하면 되지 않을까?? 하지만 이미 세탁 주기를 고정해 두었기 때문에, 다시 말해 세탁하는 날을 정해두었기 때문에 속옷이 일정량 차면 추가로 세탁기를 돌려야 하는 문제가 생긴다. 운이 좋아 세탁기를 돌리는 주기와 속옷이 일정량 찬 시기가 동일할 수 있겠지만, 대부분의 경우 세탁기를 여러 번 돌려야 할 것이다. 물론 애초에 일반 세탁물과 속옷을 따로 세탁하는 사용자라면 모르겠지만, 귀찮은 걸 싫어하는 나의 경우, 모든 세탁물을 한꺼번에 돌리기 때문에 이러한 문제가 발생한다.

 

그렇다면 어떻게 세탁기 돌리는 날을 고정한 채로 세탁되는 속옷의 양을 일정하게 맞출 수 있을까?? 이번에도 역시 임시 바구니를 활용할 수 있다. 사용자가 사용한 속옷을 세탁 바구니로 바로 넣는 것이 아니라, 임시 바구니에 넣는 것이다. 그리고 만약 임시 바구니가 세탁 주기만큼 찼을 경우에는 임시 바구니에 있는 속옷을 세탁 바구니로 옮긴다. 이렇게 옮겨진 속옷은 다음 세탁 주기에 세탁될 것이다. 이로써 세탁되는 세탁물의 양을 조절할 수 있게 된다. 

 

이를 시뮬레이션으로 구현해 보자. 이전과 비슷한 방식으로 advancedLaundrySimulator1을 복사/붙여 넣은 다음,  advancedLaundrySimulator2로 이름을 변경한 후, 아래와 같이 임시 바구니 tmpLaundryBasket을 추가하였다. 그다음 사용자가 사용한 속옷을 방금 만든 tmpLaundryBasket에 저장한다. 그리고 앞에서 설명한 바와 같이, 임시 바구니에 속옷이 일정 수량(세탁 주기) 만큼 차면, 해당 속옷을 laundryBasket으로 옮기면 된다. 

func advancedLaundrySimulator2(washTerm: UInt, repeatNumber: UInt, possibility: Double = 1.0, priority: SelectionPriority) -> [Stuff] {
    
    ...
    
    var washedBasket: Basket = []                           // 세탁된 옷을 넣는 바구니1
    var laundryBasket: Basket = []                          // 세탁할 옷을 넣는 바구니2
    var tmpWashedBasket: Basket = []                        // 세탁된 옷을 보관하는 임시 바구니1
    var tmpLaundryBasket: Basket = []                       // 세탁할 옷을 보관하는 임시 바구니2
    
    ...

    var washedNumber: Int = 0
    while washedNumber < repeatNumber {                     // repeatNumber 만큼 세탁 가능
        var day: Int = 0
        while day < washTerm {                              // 세탁을 위한 주기 카운트
            let isPossible: Bool = { Double.random(in: 0.0 ..< 1.0) < possibility }()
            if isPossible {
                
                ...
                
                tmpLaundryBasket.append(washedBasket.remove(at: selectedIndex))     // 선택된 속옷을 사용 후에 임시 바구니2에 넣기
                
                ...
                
                if tmpLaundryBasket.count == washTerm {     // 임시 바구니2에 속옷의 개수가 washTerm이 되면 바구니2로 옮기기
                    tmpLaundryBasket.move(to: &laundryBasket)
                }
            }
            day += 1
        }
        
        ...
        
    }

    ...
    
}

 

그런데 이전 매개변수를 활용하여 해당 함수를 실행해 보면, 에러가 발생한다. 

이는 tmpLaundryBasket에 세탁 주기보다 하나 적은 속옷이 들어가 있어 세탁을 안 하고 다음 세탁이 있기 전까지, 사용할 속옷이 부족할 때 생기는 현상이다. 따라서 tmpLaundryBasket에 최대로 세탁 주기보다 하나 적은 속옷이 들어간 상태에서 속옷이 부족하지 않기 위해, 추가로 세탁 주기보다 하나 많은 속옷(advancedLaundrySimulator1의 guard문 참고)이 필요하다. 즉 세탁 주기에 최소 2배만큼의 속옷이 필요하게 된다.

 

이를 반영하여 guard무을 수정하고,

guard stuffNumber >= washTerm * 2 else {
    fatalError("The number of stuff must be more than or equal to the twice washing term")
}

 

속옷의 양을 14로 변경한 뒤 다시 함수를 실행시켜 보자.

결과는 만족스럽게 나왔다. 속옷을 어떻게 선택하는지에 상관없이 세탁 횟수가 동일하게 나왔다. 간혹 세탁 횟수가 하나 차이나는 경우가 있는데, 이는 laundryBasekt에 있던 속옷들에 대해 세탁기를 돌린 횟수가 홀수일 때 나타나는 현상으로, 다음 세탁 때 같아질 것이다. 

 

이렇게 성공적으로 세탁 횟수 문제를 해결할 수 있었다. 하지만 속옷의 양을 무작정 늘릴 수도 없다. 속옷의 양을 18로 설정하여 다시 함수를 실행해 보자. 그러면 세탁 횟수가 달라지게 된다. 이는 tmpWashedBasket에 속옷이 세탁 주기보다 많이 들어가는 경우가 생기기 때문에 발생한다. 

 

따라서 구현된 방식으로 세탁 횟수를 맞추기 위해서는 속옷의 양이 세탁 주기에 정확히 두배여야 한다는 결론이 나온다. 

 

마지막으로 전 과정을 정리하면 다음과 같다.

6단계의 반복으로 표현이 가능하다.

  1. 사용자가 그날 속옷을 입기로 하였다면 서랍(washedBasket)에서 속옷을 꺼내 입는다.
  2. 서랍이 비었다면 건조대(tmpWashedBasket)에서 서랍(washedBasket)으로 속옷을 옮긴다.
  3. 속옷을 사용하고 난 뒤 임시 세탁 바구니(tmpLaundryBasket)에 넣는다.
  4. 임시 세탁 바구니(tmpLaundryBasket)에 속옷이 세탁 주기만큼 차면 세탁 바구니(laundryBasket)로 옮긴다.
  5. 세탁하는 날이 되면 세탁 바구니(laundryBasket)에 있는 속옷을 세탁한다.
  6. 건조가 다 된 속옷을 건조대(tmpWashedBasket)에 그대로 둔다.

이상으로 세탁 횟수 문제를 해결했다. 해당 문제를 인식하고 해결하기까지 시간이 꽤 걸렸는데, 코드나 글로는 너무 간단히 해결되어 서운(?)한 마음이 든다. 바구니 2개만 추가하면 되니 말이다.

 

포스팅 전반에 걸친 코드는 정리하여 깃 허브(https://github.com/Taeminator1/Various-Algorithms/tree/main/Laundromat)에 올려두었다. 포스팅에서는 각각의 시뮬레이션을 함수로 구성하였는데, 리팩터링 하여 시뮬레이션에 대한 구조체를 만들고, 메서드 하나로 통합하였다. 이제 더 이상 해진 정도를 구분할 필요가 없어졌다. 왜냐하면 모든 속옷의 세탁 횟수는 같을 테니까!