Memoria-txartelen joko bat idaztea Swift-en

Memoria-txartelen joko bat idaztea Swift-en

Artikulu honek asko gustatzen zaidan memoria entrenatzeko joko sinple bat sortzeko prozesua deskribatzen du. Berez ona izateaz gain, Swift-eko klaseei eta protokoloei buruz pixka bat gehiago ikasiko duzu joan ahala. Baina hasi baino lehen, uler dezagun jokoa bera.

Gogoratzen dugu: "Habr" irakurle guztientzat - 10 errubloko deskontua "Habr" promozio-kodea erabiliz Skillbox-eko edozein ikastarotan izena ematean.

Skillbox-ek gomendatzen du: Hezkuntza online ikastaroa "Lanbideko Java garatzailea".

Memoria txartela nola jokatu

Jokoa karta multzo baten erakustaldi batekin hasten da. Ahoz behera etzanda daude (hurrenez hurren, irudia behera). Edozein batean klik egiten duzunean, irudia segundo batzuetan irekiko da.

Jokalariaren zeregina irudi berdinak dituzten karta guztiak aurkitzea da. Lehenengo txartela ireki ondoren, bigarrenari buelta ematen badiozu eta irudiak bat datoz, bi kartak irekita geratzen dira. Bat ez badatoz, txartelak berriro itxiko dira. Helburua dena irekitzea da.

Proiektuaren egitura

Joko honen bertsio sinple bat sortzeko osagai hauek behar dituzu:

  • One Controller: GameController.swift.
  • Ikuspegi bakarra: CardCell.swift.
  • Bi eredu: MemoryGame.swift eta Card.swift.
  • Main.storyboard osagaien multzo osoa eskuragarri dagoela ziurtatzeko.

Jokoaren osagai errazenetik hasiko gara, kartekin.

Txartela.bizkorra

Txartel-ereduak hiru propietate izango ditu: bakoitza identifikatzeko id, txartelaren egoera zehazteko erakusten den aldagai boolearra (ezkutua edo irekia) eta txarteletako irudien artworkURL.

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

Erabiltzailearen mapekin elkarrekintza kontrolatzeko metodo hauek ere beharko dituzu:

Txartel batean irudi bat bistaratzeko metodoa. Hemen propietate guztiak lehenespenera berrezartzen ditugu. Id-erako, ausazko id bat sortzen dugu NSUUIS().uuidString deituz.

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

NAN-ak konparatzeko metodoa.

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

Txartel bakoitzaren kopia bat sortzeko metodoa - berdin-kopuru handiagoa lortzeko. Metodo honek antzeko balioak dituen txartela itzuliko du.

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

Eta beste metodo bat behar da txartelak hasieran nahasteko. Array klasearen luzapena egingo dugu.

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

Eta hona hemen Txartel ereduaren kodearen ezarpena propietate eta metodo guztiekin.

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() }
        }
    }
}

Aurrera

Bigarren eredua MemoryGame da, hemen 4*4 sare bat ezarri dugu. Ereduak propietateak izango ditu, hala nola, txartelak (sare batean karta-matrize bat), txartelak dagoeneko irekita dituen cardsShown array bat eta aldagai boolearra isPlaying jokoaren egoeraren jarraipena egiteko.

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

Erabiltzaileen sarearekiko interakzioa kontrolatzeko metodoak ere garatu behar ditugu.

Txartelak sare batean nahasten dituen metodoa.

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

Joko berri bat sortzeko metodoa. Hemen hasierako diseinua hasteko eta isPlaying aldagaia egiazko gisa hasieratzeko lehen metodoari deitzen diogu.

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

Jokoa berrabiarazi nahi badugu, ondoren, isPlaying aldagaia false gisa ezarriko dugu eta karten hasierako diseinua kenduko dugu.

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

Klikatutako txartelak egiaztatzeko metodoa. Geroago berari buruz gehiago.

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

Txartel zehatz baten posizioa itzultzen duen metodoa.

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

Hautatutako txartelak estandarrekin betetzen duen egiaztatzea.

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

Metodo honek **cardsShown** array-ko azken elementua irakurtzen du eta bat ez datorren txartela itzultzen du.

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 eta GameController.swift

Main.storyboard-ak honelako itxura du:

Memoria-txartelen joko bat idaztea Swift-en

Hasieran, joko berria kontrolagailuan viewDidLoad gisa ezarri behar duzu, sareko irudiak barne. Jokoan, hori guztia 4*4 bilduma Ikusi-rekin irudikatuko da. CollectionView oraindik ezagutzen ez baduzu, hemen duzu behar duzun informazioa lor dezakezu.

GameController aplikazioaren erro-kontrolatzaile gisa konfiguratuko dugu. GameController-ek IBOutlet gisa erreferentzia egingo dugun collectionView bat izango du. Beste erreferentzia bat IBAction onStartGame() botoia da, hau UIButton bat da, PLAY izeneko storyboardean ikus dezakezu.

Kontrolagailuen ezarpenari buruz apur bat:

  • Lehenik eta behin, bi objektu nagusi hasieratuko ditugu: sareta: jokoa = MemoryGame(), eta karta multzo bat: txartelak = [Txartela]().
  • Hasierako aldagaiak viewDidLoad gisa ezarri ditugu, hau da jokoa martxan dagoen bitartean deitzen den lehenengo metodoa.
  • collectionView ezkutuan ezarri da txartel guztiak ezkutatuta daudelako, erabiltzaileak PLAY sakatu arte.
  • PLAY sakatu bezain laster, onStartGame IBAction atala hasten da, eta collectionView isHidden propietatea false ezarriko dugu, txartelak ikusgai egon daitezen.
  • Erabiltzaileak txartel bat hautatzen duen bakoitzean, didSelectItemAt metodoari deitzen zaio. didSelectCard deitzen dugun metodoan jokoaren logika nagusia ezartzeko.

Hona hemen GameControllerren azken inplementazioa:

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)
    }
}

Orain hitz egin dezagun apur bat protokolo garrantzitsuei buruz.

protokoloak

Protokoloekin lan egitea da Swift programazioaren muina. Protokoloek klase, egitura edo enumerazio baterako arauak definitzeko gaitasuna ematen dute. Printzipio honek kode modularra eta hedagarria idazteko aukera ematen du. Izan ere, hau CollectionView-n GameController-en inplementatzen ari garen eredua da. Orain egin dezagun gure bertsioa. Sintaxia honela izango da:

protocol MemoryGameProtocol {
    //protocol definition goes here
}

Badakigu protokolo batek klase bat ezartzeko arauak edo argibideak definitzeko aukera ematen duela, pentsa dezagun zer izan behar duten. Lau behar dituzu guztira.

  • Jokoaren hasiera: memoryGameDidStart.
  • Txartela beherantz jarri behar duzu: memoryGameShowCards.
  • Txartela beherantz jarri behar duzu: memoryGameHideCards.
  • Jolasaren amaiera: memoryGameDidEnd.

Lau metodoak klase nagusirako inplementa daitezke, hau da, GameController.

memoryGameDidStart

Metodo hau exekutatzen denean, jokoa hasi behar da (erabiltzaileak PLAY sakatzen du). Hemen edukia berriro kargatuko dugu collectionView.reloadData(ri deituz), eta horrek txartelak nahastuko ditu.

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

memoryGameShowCards

Metodo honi collectionSDViewSelectItemAt-etik deitzen diogu. Lehenik eta behin hautatutako txartela erakusten du. Ondoren, cardsShown array-n paregabeko txartel bat dagoen ala ez egiaztatzen du (erakutsitako txartel kopurua bakoitia bada). Bat badago, hautatutako txartela berarekin konparatzen da. Irudiak berdinak badira, bi kartak Erakusten diren txarteletan gehitzen dira eta ahoz gora geratzen dira. Desberdina bada, txartelak erakutsitako txartelak uzten ditu eta biak ahoz behera jartzen dira.

memoryGameHideCards

Txartelak bat ez badatoz, metodo honi deitzen zaio eta txartelaren irudiak ezkutatu egiten dira.

erakutsia = faltsua.

memoryGameDidEnd

Metodo hau deitzen denean, karta guztiak dagoeneko agerian daudela eta cardsShown zerrendan daudela esan nahi du: cardsShown.count = cards.count, beraz, jokoa amaitu da. Metodoari zehazki deitzen zaio endGame() deitu ondoren isPlaying var false gisa ezartzeko, eta ondoren jokoaren amaierako mezua erakusten da. Era berean, alertController kontrolagailuaren adierazle gisa erabiltzen da. viewDidDisappear deitzen da eta jokoa berrezartzen da.

Hona hemen nolakoa den GameController-en:

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()
    }
}

Memoria-txartelen joko bat idaztea Swift-en
Egia esan, hori da dena. Proiektu hau erabil dezakezu zure jokoaren bertsioa sortzeko.

Zoriontsu kodeketa!

Skillbox-ek gomendatzen du:

Iturria: www.habr.com

Gehitu iruzkin berria