Swift๋กœ ๋ฉ”๋ชจ๋ฆฌ ์นด๋“œ ๊ฒŒ์ž„ ์ž‘์„ฑํ•˜๊ธฐ

Swift๋กœ ๋ฉ”๋ชจ๋ฆฌ ์นด๋“œ ๊ฒŒ์ž„ ์ž‘์„ฑํ•˜๊ธฐ

์ด ๊ธ€์€ ์ œ๊ฐ€ ์ •๋ง ์ข‹์•„ํ•˜๋Š” ๊ฐ„๋‹จํ•œ ๊ธฐ์–ต๋ ฅ ํ›ˆ๋ จ ๊ฒŒ์ž„์„ ๋งŒ๋“œ๋Š” ๊ณผ์ •์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ์ž์ฒด๋กœ ์ข‹์€ ๊ฒƒ ์™ธ์—๋„ Swift ํด๋ž˜์Šค์™€ ํ”„๋กœํ† ์ฝœ์— ๋Œ€ํ•ด ์กฐ๊ธˆ ๋” ๋ฐฐ์šฐ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์‹œ์ž‘ํ•˜๊ธฐ ์ „์— ๊ฒŒ์ž„ ์ž์ฒด๋ฅผ ์ดํ•ดํ•ด ๋ด…์‹œ๋‹ค.

์•Œ๋ฆผ: "Habr"์˜ ๋ชจ๋“  ๋…์ž๋ฅผ ์œ„ํ•œ - "Habr" ํ”„๋กœ๋ชจ์…˜ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Skillbox ๊ณผ์ •์— ๋“ฑ๋กํ•  ๋•Œ 10 ๋ฃจ๋ธ” ํ• ์ธ.

Skillbox๋Š” ๋‹ค์Œ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ๊ต์œก์šฉ ์˜จ๋ผ์ธ ๊ณผ์ • "์ง์—… ์ž๋ฐ” ๊ฐœ๋ฐœ์ž".

๋ฉ”๋ชจ๋ฆฌ ์นด๋“œ ํ”Œ๋ ˆ์ด ๋ฐฉ๋ฒ•

๊ฒŒ์ž„์€ ์นด๋“œ ์„ธํŠธ๋ฅผ ์‹œ์—ฐํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋“ค์€ ์—Ž๋“œ๋ ค ๋ˆ„์›Œ ์žˆ์Šต๋‹ˆ๋‹ค (๊ฐ๊ฐ ์ด๋ฏธ์ง€๊ฐ€ ์•„๋ž˜๋กœ ํ–ฅํ•จ). ํ•˜๋‚˜๋ฅผ ํด๋ฆญํ•˜๋ฉด ์ด๋ฏธ์ง€๊ฐ€ ๋ช‡ ์ดˆ ๋™์•ˆ ์—ด๋ฆฝ๋‹ˆ๋‹ค.

ํ”Œ๋ ˆ์ด์–ด์˜ ์ž„๋ฌด๋Š” ๋™์ผํ•œ ๊ทธ๋ฆผ์ด ์žˆ๋Š” ๋ชจ๋“  ์นด๋“œ๋ฅผ ์ฐพ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ์นด๋“œ๋ฅผ ์—ฐ ํ›„ ๋‘ ๋ฒˆ์งธ ์นด๋“œ๋ฅผ ๋’ค์ง‘์–ด์„œ ๊ทธ๋ฆผ์ด ์ผ์น˜ํ•˜๋ฉด ๋‘ ์นด๋“œ ๋ชจ๋‘ ์—ด๋ฆฐ ์ƒํƒœ๋กœ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. ์ผ์น˜ํ•˜์ง€ ์•Š์œผ๋ฉด ์นด๋“œ๊ฐ€ ๋‹ค์‹œ ๋‹ซํž™๋‹ˆ๋‹ค. ๋ชฉํ‘œ๋Š” ๋ชจ๋“  ๊ฒƒ์„ ์—ฌ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

์ด ๊ฒŒ์ž„์˜ ๊ฐ„๋‹จํ•œ ๋ฒ„์ „์„ ๋งŒ๋“ค๋ ค๋ฉด ๋‹ค์Œ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

  • ํ•˜๋‚˜์˜ ์ปจํŠธ๋กค๋Ÿฌ: GameController.swift.
  • ํ•˜๋‚˜์˜ ๋ทฐ: CardCell.swift.
  • ๋‘ ๊ฐ€์ง€ ๋ชจ๋ธ: MemoryGame.swift ๋ฐ Card.swift.
  • Main.storyboard๋Š” ์ „์ฒด ๊ตฌ์„ฑ ์š”์†Œ ์ง‘ํ•ฉ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ๊ฒŒ์ž„์˜ ๊ฐ€์žฅ ๊ฐ„๋‹จํ•œ ๊ตฌ์„ฑ ์š”์†Œ์ธ ์นด๋“œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

์นด๋“œ์Šค์œ„ํ”„ํŠธ

์นด๋“œ ๋ชจ๋ธ์—๋Š” ์„ธ ๊ฐ€์ง€ ์†์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ ์นด๋“œ๋ฅผ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•œ id, ์นด๋“œ ์ƒํƒœ(์ˆจ๊น€ ๋˜๋Š” ์—ด๊ธฐ)๋ฅผ ์ง€์ •ํ•˜๊ธฐ ์œ„ํ•ด ํ‘œ์‹œ๋˜๋Š” ๋ถ€์šธ ๋ณ€์ˆ˜, ์นด๋“œ ์ด๋ฏธ์ง€์— ๋Œ€ํ•œ ArtworkURL์ž…๋‹ˆ๋‹ค.

class Card {        
    var id: String    
    var shown: Bool = false    
    var artworkURL: UIImage!
}

์ง€๋„์™€์˜ ์‚ฌ์šฉ์ž ์ƒํ˜ธ์ž‘์šฉ์„ ์ œ์–ดํ•˜๋ ค๋ฉด ๋‹ค์Œ ๋ฉ”์„œ๋“œ๋„ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์นด๋“œ์— ์ด๋ฏธ์ง€๋ฅผ ํ‘œ์‹œํ•˜๋Š” ๋ฐฉ๋ฒ•. ์—ฌ๊ธฐ์„œ๋Š” ๋ชจ๋“  ์†์„ฑ์„ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์žฌ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. id์˜ ๊ฒฝ์šฐ NSUUIS().uuidString์„ ํ˜ธ์ถœํ•˜์—ฌ ์ž„์˜์˜ ID๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

init(image: UIImage) {        
    self.id = NSUUID().uuidString        
    self.shown = false        
    self.artworkURL = image    
}

์‹ ๋ถ„์ฆ ๋น„๊ต ๋ฐฉ๋ฒ•.

func equals(_ card: Card) -> Bool {
    return (card.id == id)    
}

๊ฐ ์นด๋“œ์˜ ๋ณต์‚ฌ๋ณธ์„ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ• - ๋” ๋งŽ์€ ์ˆ˜์˜ ๋™์ผํ•œ ๊ฒƒ์„ ์–ป์œผ๋ ค๋ฉด. ์ด ๋ฉ”์†Œ๋“œ๋Š” ๋น„์Šทํ•œ ๊ฐ’์„ ๊ฐ€์ง„ ์นด๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

func copy() -> Card {        
    return Card(card: self)    
}
 
init(card: Card) {        
    self.id = card.id        
    self.shown = card.shown        
    self.artworkURL = card.artworkURL    
}

๊ทธ๋ฆฌ๊ณ  ์ฒ˜์Œ์— ์นด๋“œ๋ฅผ ์„ž๋Š” ๋ฐฉ๋ฒ•์ด ํ•˜๋‚˜ ๋” ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ Array ํด๋ž˜์Šค์˜ ํ™•์žฅ์œผ๋กœ ๋งŒ๋“ค๊ฒ ์Šต๋‹ˆ๋‹ค.

extension Array {    
    mutating func shuffle() {        
        for _ in 0...self.count {            
            sort { (_,_) in arc4random() < arc4random() }        
        }   
    }
}

๋‹ค์Œ์€ ๋ชจ๋“  ์†์„ฑ๊ณผ ๋ฉ”์„œ๋“œ๋ฅผ ํฌํ•จํ•˜๋Š” ์นด๋“œ ๋ชจ๋ธ์šฉ ์ฝ”๋“œ์˜ ๊ตฌํ˜„์ž…๋‹ˆ๋‹ค.

class Card {
    
    var id: String
    var shown: Bool = false
    var artworkURL: UIImage!
    
    static var allCards = [Card]()
 
    init(card: Card) {
        self.id = card.id
        self.shown = card.shown
        self.artworkURL = card.artworkURL
    }
    
    init(image: UIImage) {
        self.id = NSUUID().uuidString
        self.shown = false
        self.artworkURL = image
    }
    
    func equals(_ card: Card) -> Bool {
        return (card.id == id)
    }
    
    func copy() -> Card {
        return Card(card: self)
    }
}
 
extension Array {
    mutating func shuffle() {
        for _ in 0...self.count {
            sort { (_,_) in arc4random() < arc4random() }
        }
    }
}

์•ž์œผ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

๋‘ ๋ฒˆ์งธ ๋ชจ๋ธ์€ MemoryGame์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” 4*4 ๊ทธ๋ฆฌ๋“œ๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋ธ์—๋Š” ์นด๋“œ(๊ทธ๋ฆฌ๋“œ ์œ„์˜ ์นด๋“œ ๋ฐฐ์—ด), ์นด๋“œ๊ฐ€ ์ด๋ฏธ ์—ด๋ ค ์žˆ๋Š” ์นด๋“œ ํ‘œ์‹œ ๋ฐฐ์—ด, ๊ฒŒ์ž„ ์ƒํƒœ๋ฅผ ์ถ”์ ํ•˜๋Š” ๋ถ€์šธ ๋ณ€์ˆ˜ isPlaying ๋“ฑ์˜ ์†์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

class MemoryGame {        
    var cards:[Card] = [Card]()    
    var cardsShown:[Card] = [Card]()    
    var isPlaying: Bool = false
}

๋˜ํ•œ ๊ทธ๋ฆฌ๋“œ์™€์˜ ์‚ฌ์šฉ์ž ์ƒํ˜ธ ์ž‘์šฉ์„ ์ œ์–ดํ•˜๋Š” โ€‹โ€‹๋ฐฉ๋ฒ•๋„ ๊ฐœ๋ฐœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๋“œ์—์„œ ์นด๋“œ๋ฅผ ์„ž๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

func shuffleCards(cards:[Card]) -> [Card] {       
    var randomCards = cards        
    randomCards.shuffle()                
 
    return randomCards    
}

์ƒˆ๋กœ์šด ๊ฒŒ์ž„์„ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•. ์—ฌ๊ธฐ์„œ๋Š” ์ฒซ ๋ฒˆ์งธ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ดˆ๊ธฐ ๋ ˆ์ด์•„์›ƒ์„ ์‹œ์ž‘ํ•˜๊ณ  isPlaying ๋ณ€์ˆ˜๋ฅผ true๋กœ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.

func newGame(cardsArray:[Card]) -> [Card] {       
    cards = shuffleCards(cards: cardsArray)        
    isPlaying = true            
 
    return cards    
}

๊ฒŒ์ž„์„ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, ๊ทธ๋Ÿฐ ๋‹ค์Œ isPlaying ๋ณ€์ˆ˜๋ฅผ false๋กœ ์„ค์ •ํ•˜๊ณ  ์นด๋“œ์˜ ์ดˆ๊ธฐ ๋ ˆ์ด์•„์›ƒ์„ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.

func restartGame() {        
    isPlaying = false                
    cards.removeAll()        
    cardsShown.removeAll()    
}

ํด๋ฆญ๋œ ์นด๋“œ๋ฅผ ํ™•์ธํ•˜๋Š” ๋ฐฉ๋ฒ•. ๊ทธ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋‚˜์ค‘์— ์•Œ์•„๋ณด์„ธ์š”.

func cardAtIndex(_ index: Int) -> Card? {        
    if cards.count > index {            
        return cards[index]        
    } else {            
        return nil        
    }    
}

ํŠน์ • ์นด๋“œ์˜ ์œ„์น˜๋ฅผ โ€‹โ€‹๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์†Œ๋“œ์ž…๋‹ˆ๋‹ค.

func indexForCard(_ card: Card) -> Int? {        
    for index in 0...cards.count-1 {            
        if card === cards[index] {                
            return index            
        }      
    }
        
    return nil    
}

์„ ํƒํ•œ ์นด๋“œ๊ฐ€ ํ‘œ์ค€์„ ์ค€์ˆ˜ํ•˜๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

func unmatchedCardShown() -> Bool {
    return cardsShown.count % 2 != 0
}

์ด ๋ฉ”์†Œ๋“œ๋Š” **cardsShown** ๋ฐฐ์—ด์˜ ๋งˆ์ง€๋ง‰ ์š”์†Œ๋ฅผ ์ฝ๊ณ  ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ์นด๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

func didSelectCard(_ card: Card?) {        
    guard let card = card else { return }                
    
    if unmatchedCardShown() {            
        let unmatched = unmatchedCard()!                        
        
        if card.equals(unmatched) {          
            cardsShown.append(card)            
        } else {                
            let secondCard = cardsShown.removeLast()      
        }                    
    } else {            
        cardsShown.append(card)        
    }                
    
    if cardsShown.count == cards.count {            
        endGame()        
    }    
}

Main.storyboard ๋ฐ GameController.swift

Main.storyboard๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Swift๋กœ ๋ฉ”๋ชจ๋ฆฌ ์นด๋“œ ๊ฒŒ์ž„ ์ž‘์„ฑํ•˜๊ธฐ

์ฒ˜์Œ์—๋Š” ๊ทธ๋ฆฌ๋“œ ์ด๋ฏธ์ง€๋ฅผ ํฌํ•จํ•˜์—ฌ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์ƒˆ ๊ฒŒ์ž„์„ viewDidLoad๋กœ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ฒŒ์ž„์—์„œ๋Š” ์ด ๋ชจ๋“  ๊ฒƒ์ด 4*4 collectionView๋กœ ํ‘œํ˜„๋ฉ๋‹ˆ๋‹ค. collectionView์— ์•„์ง ์ต์ˆ™ํ•˜์ง€ ์•Š๋‹ค๋ฉด ์—ฌ๊ธฐ์— ์žˆ์Šต๋‹ˆ๋‹ค. ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

GameController๋ฅผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฃจํŠธ ์ปจํŠธ๋กค๋Ÿฌ๋กœ ๊ตฌ์„ฑํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. GameController์—๋Š” IBOutlet์œผ๋กœ ์ฐธ์กฐํ•  collectionView๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ ๋‹ค๋ฅธ ์ฐธ์กฐ๋Š” IBAction onStartGame() ๋ฒ„ํŠผ์— ๋Œ€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋Š” UIButton์ด๋ฉฐ PLAY๋ผ๋Š” ์Šคํ† ๋ฆฌ๋ณด๋“œ์—์„œ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ปจํŠธ๋กค๋Ÿฌ ๊ตฌํ˜„์— ๋Œ€ํ•ด ์กฐ๊ธˆ:

  • ๋จผ์ € ๋‘ ๊ฐ€์ง€ ์ฃผ์š” ๊ฐœ์ฒด์ธ ๊ทธ๋ฆฌ๋“œ: game = MemoryGame() ๋ฐ ์นด๋“œ ์„ธํŠธ: ์นด๋“œ = [Card]()๋ฅผ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.
  • ์ดˆ๊ธฐ ๋ณ€์ˆ˜๋ฅผ viewDidLoad๋กœ ์„ค์ •ํ–ˆ๋Š”๋ฐ, ์ด๋Š” ๊ฒŒ์ž„์ด ์‹คํ–‰๋˜๋Š” ๋™์•ˆ ํ˜ธ์ถœ๋˜๋Š” ์ฒซ ๋ฒˆ์งธ ๋ฉ”์„œ๋“œ์ž…๋‹ˆ๋‹ค.
  • ์‚ฌ์šฉ์ž๊ฐ€ PLAY๋ฅผ ๋ˆ„๋ฅผ ๋•Œ๊นŒ์ง€ ๋ชจ๋“  ์นด๋“œ๊ฐ€ ์ˆจ๊ฒจ์ง€๋ฏ€๋กœ collectionView๋Š” ์ˆจ๊น€์œผ๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.
  • PLAY๋ฅผ ๋ˆ„๋ฅด์ž๋งˆ์ž onStartGame IBAction ์„น์…˜์ด ์‹œ์ž‘๋˜๊ณ  collectionView isHidden ์†์„ฑ์„ false๋กœ ์„ค์ •ํ•˜์—ฌ ์นด๋“œ๊ฐ€ ํ‘œ์‹œ๋˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  • ์‚ฌ์šฉ์ž๊ฐ€ ์นด๋“œ๋ฅผ ์„ ํƒํ•  ๋•Œ๋งˆ๋‹ค didSelectItemAt ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ๋ฉ”์†Œ๋“œ์—์„œ didSelectCard๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ฉ”์ธ ๊ฒŒ์ž„ ๋กœ์ง์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

์ตœ์ข… GameController ๊ตฌํ˜„์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

class GameController: UIViewController {
 
    @IBOutlet weak var collectionView: UICollectionView!
    
    let game = MemoryGame()
    var cards = [Card]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        game.delegate = self
        
        collectionView.dataSource = self
        collectionView.delegate = self
        collectionView.isHidden = true
        
        APIClient.shared.getCardImages { (cardsArray, error) in
            if let _ = error {
                // show alert
            }
            
            self.cards = cardsArray!
            self.setupNewGame()
        }
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        
        if game.isPlaying {
            resetGame()
        }
    }
    
    func setupNewGame() {
        cards = game.newGame(cardsArray: self.cards)
        collectionView.reloadData()
    }
    
    func resetGame() {
        game.restartGame()
        setupNewGame()
    }
    
    @IBAction func onStartGame(_ sender: Any) {
        collectionView.isHidden = false
    }
}
 
// MARK: - CollectionView Delegate Methods
extension GameController: UICollectionViewDelegate, UICollectionViewDataSource {
    
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return cards.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CardCell", for: indexPath) as! CardCell
        cell.showCard(false, animted: false)
        
        guard let card = game.cardAtIndex(indexPath.item) else { return cell }
        cell.card = card
        
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        let cell = collectionView.cellForItem(at: indexPath) as! CardCell
        
        if cell.shown { return }
        game.didSelectCard(cell.card)
        
        collectionView.deselectItem(at: indexPath, animated:true)
    }
}

์ด์ œ ์ค‘์š”ํ•œ ํ”„๋กœํ† ์ฝœ์— ๋Œ€ํ•ด ์กฐ๊ธˆ ์ด์•ผ๊ธฐํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

ํ”„๋กœํ† ์ฝœ

ํ”„๋กœํ† ์ฝœ ์ž‘์—…์€ Swift ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค. ํ”„๋กœํ† ์ฝœ์€ ํด๋ž˜์Šค, ๊ตฌ์กฐ ๋˜๋Š” ์—ด๊ฑฐํ˜•์— ๋Œ€ํ•œ ๊ทœ์น™์„ ์ •์˜ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด ์›์น™์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ชจ๋“ˆ์‹ ๋ฐ ํ™•์žฅ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ์ด๊ฒƒ์€ GameController์—์„œ collectionView์— ๋Œ€ํ•ด ์ด๋ฏธ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ๋Š” ํŒจํ„ด์ž…๋‹ˆ๋‹ค. ์ด์ œ ์šฐ๋ฆฌ๋งŒ์˜ ๋ฒ„์ „์„ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ตฌ๋ฌธ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

protocol MemoryGameProtocol {
    //protocol definition goes here
}

์šฐ๋ฆฌ๋Š” ํ”„๋กœํ† ์ฝœ์„ ํ†ตํ•ด ํด๋ž˜์Šค ๊ตฌํ˜„์„ ์œ„ํ•œ ๊ทœ์น™์ด๋‚˜ ์ง€์นจ์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์œผ๋ฏ€๋กœ ํ”„๋กœํ† ์ฝœ์ด ๋ฌด์—‡์ด์–ด์•ผ ํ•˜๋Š”์ง€ ์ƒ๊ฐํ•ด ๋ด…์‹œ๋‹ค. ์ด XNUMX๊ฐœ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

  • ๊ฒŒ์ž„ ์‹œ์ž‘: memoryGameDidStart.
  • ๋ฉ”๋ชจ๋ฆฌ๊ฒŒ์ž„์‡ผ์นด๋“œ(memoryGameShowCards) ์นด๋“œ๋ฅผ ๋’ค์ง‘์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ์นด๋“œ๋ฅผ ๋’ค์ง‘์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค: memoryGameHideCards.
  • ๊ฒŒ์ž„ ์ข…๋ฃŒ: memoryGameDidEnd.

๋„ค ๊ฐ€์ง€ ๋ฉ”์„œ๋“œ ๋ชจ๋‘ GameController์ธ ๊ธฐ๋ณธ ํด๋ž˜์Šค์— ๋Œ€ํ•ด ๊ตฌํ˜„๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฉ”๋ชจ๋ฆฌ๊ฒŒ์ž„DidStart

์ด ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋˜๋ฉด ๊ฒŒ์ž„์ด ์‹œ์ž‘๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(์‚ฌ์šฉ์ž๊ฐ€ PLAY๋ฅผ ๋ˆ„๋ฆ„). ์—ฌ๊ธฐ์—์„œ๋Š” ์นด๋“œ๋ฅผ ์„ž๋Š” collectionView.reloadData()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ฝ˜ํ…์ธ ๋ฅผ ๋‹ค์‹œ ๋กœ๋“œํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

func memoryGameDidStart(_ game: MemoryGame) {
    collectionView.reloadData()
}

๋ฉ”๋ชจ๋ฆฌ๊ฒŒ์ž„์‡ผ์นด๋“œ

collectionSDViewSelectItemAt์—์„œ ์ด ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ๋จผ์ € ์„ ํƒํ•œ ์นด๋“œ๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ CardShown ๋ฐฐ์—ด์— ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ์นด๋“œ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค(cardShown ์ˆ˜๊ฐ€ ํ™€์ˆ˜์ธ ๊ฒฝ์šฐ). ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ ์„ ํƒํ•œ ์นด๋“œ์™€ ๋น„๊ต๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆผ์ด ๋™์ผํ•˜๋ฉด ๋‘ ์นด๋“œ ๋ชจ๋‘ ํ‘œ์‹œ๋œ ์นด๋“œ์— ์ถ”๊ฐ€๋˜๊ณ  ์•ž๋ฉด์ด ์œ„๋กœ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๊ฒฝ์šฐ ์นด๋“œ๋Š” ์นด๋“œ ํ‘œ์‹œ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๊ณ  ๋‘˜ ๋‹ค ๋’ค์ง‘์–ด ๋†“์Šต๋‹ˆ๋‹ค.

๋ฉ”๋ชจ๋ฆฌ๊ฒŒ์ž„์ˆจ๊ธฐ๊ธฐ์นด๋“œ

์นด๋“œ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์œผ๋ฉด ์ด ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ  ์นด๋“œ ์ด๋ฏธ์ง€๊ฐ€ ์ˆจ๊ฒจ์ง‘๋‹ˆ๋‹ค.

ํ‘œ์‹œ = ๊ฑฐ์ง“

๋ฉ”๋ชจ๋ฆฌ๊ฒŒ์ž„์ด ์ข…๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ด ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด ๋ชจ๋“  ์นด๋“œ๊ฐ€ ์ด๋ฏธ ๊ณต๊ฐœ๋˜์–ด ์žˆ๊ณ  CardShown ๋ชฉ๋ก์— ์žˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค(cardShown.count =cards.count). ๋”ฐ๋ผ์„œ ๊ฒŒ์ž„์ด ์ข…๋ฃŒ๋ฉ๋‹ˆ๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋Š” isPlaying ๋ณ€์ˆ˜๋ฅผ false๋กœ ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•ด endGame()์„ ํ˜ธ์ถœํ•œ ํ›„์— ํ˜ธ์ถœ๋˜๋ฉฐ, ๊ทธ ํ›„ ๊ฒŒ์ž„ ์ข…๋ฃŒ ๋ฉ”์‹œ์ง€๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ AlertController๋Š” ์ปจํŠธ๋กค๋Ÿฌ์— ๋Œ€ํ•œ ํ‘œ์‹œ๊ธฐ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. viewDidDisappear๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ  ๊ฒŒ์ž„์ด ์žฌ์„ค์ •๋ฉ๋‹ˆ๋‹ค.

GameController์˜ ๋ชจ๋“  ๋‚ด์šฉ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

extension GameController: MemoryGameProtocol {
    func memoryGameDidStart(_ game: MemoryGame) {
        collectionView.reloadData()
    }
 
 
    func memoryGame(_ game: MemoryGame, showCards cards: [Card]) {
        for card in cards {
            guard let index = game.indexForCard(card)
                else { continue
            }        
            
            let cell = collectionView.cellForItem(
                at: IndexPath(item: index, section:0)
            ) as! CardCell
 
            cell.showCard(true, animted: true)
        }
    }
 
    func memoryGame(_ game: MemoryGame, hideCards cards: [Card]) {
        for card in cards {
            guard let index = game.indexForCard(card)
                else { continue
            }
            
            let cell = collectionView.cellForItem(
                at: IndexPath(item: index, section:0)
            ) as! CardCell
    
            cell.showCard(false, animted: true)
        }
    }
 
    func memoryGameDidEnd(_ game: MemoryGame) {
        let alertController = UIAlertController(
            title: defaultAlertTitle,
            message: defaultAlertMessage,
            preferredStyle: .alert
        )
 
        let cancelAction = UIAlertAction(
            title: "Nah", style: .cancel) {
            [weak self] (action) in
            self?.collectionView.isHidden = true
        }
 
        let playAgainAction = UIAlertAction(
            title: "Dale!", style: .default) {
            [weak self] (action) in
            self?.collectionView.isHidden = true
 
            self?.resetGame()
        }
 
        alertController.addAction(cancelAction)
        alertController.addAction(playAgainAction)
        
        self.present(alertController, animated: true) { }
    
        resetGame()
    }
}

Swift๋กœ ๋ฉ”๋ชจ๋ฆฌ ์นด๋“œ ๊ฒŒ์ž„ ์ž‘์„ฑํ•˜๊ธฐ
์‚ฌ์‹ค ๊ทธ๊ฒŒ ์ „๋ถ€์ž…๋‹ˆ๋‹ค. ์ด ํ”„๋กœ์ ํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž์‹ ๋งŒ์˜ ๊ฒŒ์ž„ ๋ฒ„์ „์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฆ๊ฑฐ์šด ์ฝ”๋”ฉํ•˜์„ธ์š”!

Skillbox๋Š” ๋‹ค์Œ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

์ถœ์ฒ˜ : habr.com

์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ถ”๊ฐ€