본문 바로가기

Computer Science/알고리즘

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

지난 포스팅에서 세탁 횟수에 영향을 미치는 요인을 두 가지로 정리했다.

  1. 일정하지 않은 세탁물의 양
  2. 입을 속옷을 선택하는 방법

이번 포스팅에서는 해당 요인이 세탁 횟수에 얼마나 영향을 주는지 알아보기 위해 시뮬레이션을 작성하여 살펴볼 것이다.

 

먼저 세탁물에 대한 클래스인 Stuff를 정의하자. 해당 클래스에서 생성된 인스턴스(속옷)가 다른 영역에서도 같은 객체로서 참조하길 원하기 때문에 클래스로 정의하였다. 

// Stuff.swift

class Stuff {
    static var sPreference: Int = 0             // Whenever create a instance, add unique ID.
    private(set) var preference: Int = 0
    private(set) var washedNumber: Int = 0

    init() {
        self.preference = Stuff.sPreference
        Stuff.sPreference += 1
    }

    func wash() {
        washedNumber += 1
    }

    func displayState() {
        print("The washed number of Stuff[\(preference)]: \(washedNumber)")
    }
}

각각의 속성에 대해 살펴보자. 

  • sPreference: 순차적으로 preference 값을 부여하기 위한 정적 변수이다.
  • preference: 각각의 인스턴스(속옷)를 구별하기 위한 ID이다. 속옷을 선호도에 따라 선택하는 경우가 있으므로, 선호도를 통해 각각의 객체를 구별하도록 하였다.
  • washedNumber: 해당 인스턴스가 세탁된 횟수를 저장한다.

 

다음은 simulator를 정의해 볼 것이다. 아래 normalLaundrySimulator의 정의를 살펴보자.

func normalLaundrySimulator(stuffNumber: UInt, washTerm: UInt, repeatNumber: UInt, possibility: Double = 1.0, priority: SelectionPriority) -> [Stuff] {
    guard stuffNumber >= washTerm else {
        fatalError("Wash term has to be more than the number of stuff")
    }

    ...
    
}

매개 변수는 총 다섯 개로 다음과 같다.

  • stuffNumber: 현재 가지고 있는 속옷의 수이다.
  • washTerm: 세탁 주기이다. 1주일 간격으로 세탁하면 7을, 열흘 간격으로 세탁하면 10을 넣으면 된다.
  • repeatNumber: 몇 번의 세탁을 할 것인지에 대한 값이다. washTerm이 7이고, repeatNumber가 10이면, 일주일마다 10번의 세탁을 하기 때문에 70일에 대한 시뮬레이션이 된다.
  • possibility: 그날그날 옷을 입을 확률이다. 사실 가변 되어야 하는 것이 맞지만, 편의상 확률로 설정했다. 1주일마다 5일만 속옷을 갈아입는다면, 0.714( ≈ 5 ÷ 7) 정도를 넣으면 된다.
  • priority: 세탁된 옷들 중, 어떤 방법으로 그날 입을 옷을 선택할지 결정한다. 다시 말해 무엇을 우선적으로 입을지 결정하는 매개변수이다.

priority에 대한 타입은 아래와 같이 enum을 이용하여 정의해 주었다.

 

enum SelectionPriority {
    case lastInFirstOut
    case randomly
    case byPreference
}

각각의 케이스는 다음과 같다.

  • lastInFirstOut: 가장 바깥쪽에 있는 속옷을 꺼내 사용한다.
  • randomly: 무작위로 속옷을 선택해서 사용한다.
  • byPreference: 선호도가 가장 높은 속옷을 먼저 사용한다.

 

그리고 함수의 초입에는 guard문을 이용해 세탁 주기보다 세탁물의 양이 적지 않도록 해주었다. 생각해보면 당연하다 세탁 주기가 7일이면 7일 동안 최대 7개의 속옷을 사용할 수도 있는데(하루에 최대 하나의 속옷을 사용할 수 있다고 할 때), 속옷이 6개밖에 없으면 하루는 맨발로 다녀야 할 것이다. 

 

 

이제 인스턴스를 생성할 텐데, 그전에 다음과 같이 빈 배열 2개를 생성해 줄 것이다. 해당 배열의 원소의 타입은 Stuff인데, 이 배열은 빨래의 분류를 위한 변수이다. 가독성을 위해  Array<Stuff>를 Basket이라는 별칭으로 지어 주었다. laundryBasket은 사용한 속옷을 세탁하기 전에 모아두는 바구니고, washedBasket은 세탁이 완료되어 건조된 속옷을 놓는 바구니 또는 서랍이다.

typealias Basket = Array<Stuff>

func normalLaundrySimulator(stuffNumber: UInt, washTerm: UInt, repeatNumber: UInt, possibility: Double = 1.0, priority: SelectionPriority) -> [Stuff] {
    
    ...

    var laundryBasket: Basket = []                          // 세탁할 옷을 넣는 바구니1
    var washedBasket: Basket = []                           // 세탁된 옷을 넣는 바구니2

    ...
    
}

 

다음은 관리할 속옷을 추가해 주어야 한다. 앞서 언급했지만, 각 객체의 ID는 선호도로 구분된다. 그리고 선호도는 순차적으로 부여된다. 이를 편리하게 하기 위해 Array 구조체를 extension 하여 create라는 메서드를 구현해 주었다.

extension Array where Element == Stuff {
    // 초기에 관리할 항목 추가
    mutating func create(_ number: UInt, to basket: inout Basket) {
        Stuff.sPreference = 0                           // 선호도 초기화
        for _ in 0 ..< number { self.append(Stuff()) }  // 관리할 옷 생성
        basket.append(contentsOf: self)                 // 다른 바구니로 옮기기
    }
}

 

이제 이 create 메서드를 이용해 아래와 같이 인스턴스를 생성해 주면 된다.

func normalLaundrySimulator(stuffNumber: UInt, washTerm: UInt, repeatNumber: UInt, possibility: Double = 1.0, priority: SelectionPriority) -> [Stuff] {
    
    ...
    
    var underwears: Array<Stuff> = []                       // 관리할 옷 추가
    underwears.create(stuffNumber, to: &washedBasket)       // 관리할 옷 바구니2에 넣기

    ...
    
}

 

다음으로 세탁 주기와 반복 횟수에 따른 반복문을 구현해 준다.

func normalLaundrySimulator(stuffNumber: UInt, washTerm: UInt, repeatNumber: UInt, possibility: Double = 1.0, priority: SelectionPriority) -> [Stuff] {

    ...
    
    var washedNumber: Int = 0
    while washedNumber < repeatNumber {                     // repeatNumber 만큼 세탁 가능
        var day: Int = 0
        while day < washTerm {                                  // 세탁을 위한 주기 카운트
        
            ...        // (1)
            
            day += 1
        }
        
        ...            // (2)
        
        washedNumber += 1
    }
    
    ...                // (3)
    
}

 

 

그리고 (1) ~ (3) 부분에 원하는 동작을 구현해 주면 된다. 

 

생각보다 글이 길어져 다음 포스팅에서 계속하겠다..