แแก แกแขแแขแแ แแฆแฌแแ แก แแแ แขแแแ แแแฎแกแแแ แแแแก แกแแแแ แฏแแจแ แแแแแจแแก แจแแฅแแแแก แแ แแชแแกแก, แ แแแแแแช แซแแแแแ แแแแฌแแแก. แแแ แแ แแแแกแ, แ แแ แแแแแกแแแแแ แแแ แแแ, แแฅแแแ แแแแแแแ แชแแขแ แแแขแก Swift-แแก แแแแกแแแแกแ แแ แแ แแขแแแแแแแแก แจแแกแแฎแแ. แแแแ แแ แกแแแแ แแแแแฌแงแแแ, แแแแแ แแแแแแแ แแแแแ แแแแแจแ.
แจแแแแฎแกแแแแแ: "Habr"-แแก แงแแแแ แแแแแฎแแแแแกแแแแก - แคแแกแแแแแแแ 10 แ แฃแแแแแแ Skillbox-แแก แแแแแกแแแแ แแฃแ แกแแ แฉแแ แแชแฎแแแกแแก "Habr" แกแแ แแแแแแ แแแแแก แแแแแงแแแแแแ.
Skillbox แแแ แฉแแแ: แกแแแแแแแแแแแแแแ แแแแแแ แแฃแ แกแ
"แแ แแคแแกแแ Java Developer" .
แ แแแแ แแแแแแแจแแ แแแฎแกแแแ แแแแก แแแ แแแ
แแแแแจแ แแฌแงแแแ แแแ แแแแแแก แแแแ แแแแก แแแแแแกแขแ แแ แแแแ. แแกแแแ แแแ แฅแแ แฌแแแแ (แจแแกแแแแแแกแแ, แกแฃแ แแแ แฅแแแแแ). แ แแแแกแแช แ แแแแแแแแแ แแแแฌแแแแฃแแแแ, แกแฃแ แแแ แแฎแกแแแแ แ แแแแแแแแ แฌแแแแ.
แแแแแแแจแแก แแแแชแแแแ แแแแแแ แงแแแแ แแแ แแแ แแ แแ แแ แแแแแ แกแฃแ แแแแแแ. แแฃ แแแ แแแแ แแแ แขแแก แแแฎแกแแแก แจแแแแแ แแแแ แแก แแแแแแขแ แแแแแแ แแ แกแฃแ แแแแแ แแแแฎแแแแ, แแ แแแ แแแ แขแ แฆแแ แ แฉแแแ. แแฃ แแกแแแ แแ แแแแฎแแแแ, แแแ แแแแแ แแแแแ แแฎแฃแ แแแ. แแแแแแ แงแแแแแคแ แแก แแแฎแกแแแ.
แแ แแแฅแขแแก แกแขแ แฃแฅแขแฃแ แ
แแ แแแแแจแแก แแแ แขแแแ แแแ แกแแแก แจแแกแแฅแแแแแแ แแแแญแแ แแแแแ แจแแแแแแ แแแแแแแแแขแแแ:
- แแ แแ แแแแขแ แแแแ แ: 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-แแกแแแแก แฉแแแ แแฅแแแแ แจแแแแฎแแแแแ id-แก NSUUIS().uuidString-แแก แแแแแซแแฎแแแแ.
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 แแแแ. แแแแแแก แแฅแแแแ แแกแแแ แแแแกแแแแแ, แ แแแแ แแชแแ แแแ แแแแแ (แแแ แแแแแแก แแแกแแแ แแแแแแ), แแแ แแแแแ แแแฉแแแแแแแ แแแกแแแ แแแ แขแแแแ แฃแแแ แแแฎแกแแแแ แแ แแแแแแฃแ แ แชแแแแแ แแ แแก Playing แแแแแจแแก แกแขแแขแฃแกแแก แแแแแงแฃแ แแก แแแแแแแแกแแแแก.
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 แแกแ แแแแแแงแฃแ แแแ:
แแแแแแแแ แแแแแ, แแฅแแแ แฃแแแ แแแแงแแแแ แแฎแแแ แแแแแจแ, แ แแแแ แช viewDidLoad แแแแขแ แแแแ แจแ, แฅแกแแแแก แกแฃแ แแแแแแก แฉแแแแแแ. แแแแแจแจแ แแก แงแแแแแคแแ แ แฌแแ แแแแแแแแแ แแฅแแแแ 4*4 collectionView-แแ. แแฃ แฏแแ แแ แแชแแแแ collectionView-แก, แแฅ แแ แแก
แฉแแแ แแแแแแแแคแแแฃแ แแ แแแ GameController-แก, แ แแแแ แช แแ แแแ แแแแก root แแแแขแ แแแแ แก. GameController-แก แแฅแแแแ collectionView, แ แแแแแกแแช แฉแแแ แแแแแแ แแแแ แ แแแแ แช IBOutlet. แแแแแ แแ แแ แแแแแแแแ แแ แแก IBAction onStartGame() แฆแแแแแ, แแก แแ แแก UIButton, แจแแแแซแแแแ แแฎแแแแ แกแชแแแแ แแก แแแคแแแ, แกแแฎแแแแ PLAY.
แชแแขแ แ แแ แแแแขแ แแแแ แแแแก แแแแฎแแ แชแแแแแแแก แจแแกแแฎแแ:
- แแแ แแแ แ แแแจแ, แฉแแแ แแแแแแแแ แแ แซแแ แแแแ แแแแแฅแขแก - แแแแแก: game = MemoryGame() แแ แแแ แแแแแแก แแแแ แแแ: แแแ แแแแแ = [Card]().
- แฉแแแ แแแแแงแแแแ แกแแฌแงแแกแ แชแแแแแแแ, แ แแแแ แช viewDidLoad, แแก แแ แแก แแแ แแแแ แแแแแแ, แ แแแแแแช แแแแแแซแแฎแแแ แแแแแจแแก แแแจแแแแแกแแก.
- collectionView แแแงแแแแแฃแแแ แแแแแแฃแแแ, แ แแแแแ แงแแแแ แแแ แแแ แแแแแแแ แแแแแ, แกแแแแ แแแแฎแแแ แแแแแ แแ แแแแญแแ แก PLAY-แก.
- แ แแแแ แช แแ PLAY-แก แแแแแญแแ แ, แแฌแงแแแ onStartGame IBAction แแแแงแแคแแแแแ แแ แฉแแแ แแแแแงแแแแ collectView 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-แแก แแ แแแ แแแแ แแแแก แกแแคแฃแซแแแแ. แแ แแขแแแแแแแ แแซแแแแ แแแแกแแก, แกแขแ แฃแฅแขแฃแ แแก แแ แฉแแแแแแแแก แฌแแกแแแแก แแแแกแแแฆแแ แแก แจแแกแแซแแแแแแแแก. แแก แแ แแแชแแแ แกแแจแฃแแแแแแก แแแซแแแแ แแแฌแแ แแ แแแแฃแแฃแ แ แแ แแแคแแ แแแแแแแ แแแแ. แกแแแแแแแแแแจแ, แแก แแ แแก แแแแฃแจแ, แ แแแแแกแแช แฉแแแ แฃแแแ แแแฎแแ แชแแแแแแ collectionView-แแกแแแแก GameController-แจแ. แแฎแแ แแแแแ แแแแแแแแแ แฉแแแแ แกแแแฃแแแ แ แแแ แกแแ. แกแแแขแแฅแกแ แแกแ แแแแแแงแฃแ แแแ:
protocol MemoryGameProtocol {
//protocol definition goes here
}
แฉแแแ แแแชแแ, แ แแ แแ แแขแแแแแ แกแแจแฃแแแแแแก แแแแซแแแแก แแแแแกแแแฆแแ แแ แฌแแกแแแ แแ แแแกแขแ แฃแฅแชแแแแ แแแแกแแก แแแแฎแแ แชแแแแแแแกแแแแก, แแกแ แ แแ, แแแแแ แแแคแแฅแ แแ แแแแแ, แแฃ แ แแแแ แ แฃแแแ แแงแแก แแกแแแ. แกแฃแ แแแฎแ แแญแแ แแแแแ.
- แแแแแจแแก แแแฌแงแแแ: memoryGameDidStart.
- แแฅแแแ แฃแแแ แแแแแ แฃแแแ แแแ แแแ แกแแฎแแแ แฅแแแแแ: memoryGameShowCards.
- แแฅแแแ แฃแแแ แแแแแ แฃแแแ แแแ แแแ แกแแฎแแแ แฅแแแแแ: memoryGameHideCards.
- แแแแแจแแก แแแกแแกแ แฃแแ: memoryGameDidEnd.
แแแฎแแแ แแแแแแแก แแแแแ แแแ แจแแกแแซแแแแแแแ แซแแ แแแแแ แแแแกแแกแแแแก, แ แแแแแแช แแ แแก GameController.
memoryGameDidStart
แแ แแแแแแแก แแแจแแแแแกแแก แแแแแจแ แฃแแแ แแแแฌแงแแก (แแแแฎแแแ แแแแแ แแแแญแแ แก PLAY-แก). แแฅ แฉแแแ แฃแแ แแแแ แแแแแแแขแแแ แแแแ แจแแแแแแกแก collectView.reloadData()-แแก แแแแแซแแฎแแแแ, แ แแช แแแ แแแแแก แแแ แแแแก.
func memoryGameDidStart(_ game: MemoryGame) {
collectionView.reloadData()
}
memoryGameShowCards
แฉแแแ แแฃแฌแแแแแ แแ แแแแแแก collectionSDViewSelectItemAt-แแแ. แฏแแ แแฉแแแแแแก แแ แฉแแฃแ แแแ แแแก. แจแแแแแ แแแแฌแแแแก, แแ แแก แแฃ แแ แ แจแแฃแกแแแแแ แแแ แแแ cardsShown แแแกแแแจแ (แแฃ แแแแขแแ แแแฉแแแแแแ แแแ แแแแแแก แ แแแแแแแแ). แแฃ แแ แแก แแ แแ, แจแแ แฉแแฃแแ แแแ แแแ แจแแแแ แแแฃแแแ แแแกแแแ. แแฃ แกแฃแ แแแแแ แแ แแแแแ แแ, แแ แแแ แแแ แขแ แแแแขแแแ แแแ แขแแแก, แ แแแแแแแช แแแฉแแแแแแแ แแ แ แฉแแแ แแแ แแกแแแ . แแฃ แแแแกแฎแแแแแแฃแแแ, แแแ แแแ แขแแแแแก แแแ แขแแแก, แ แแแแแแแช แแแฉแแแแแแแ แแ แแ แแแ แจแแแ แฃแแแแฃแแแ แแแ แแกแแแ .
memoryGameHideCards
แแฃ แแแ แแแแแ แแ แแแแฎแแแแ, แแก แแแแแแ แแแแแแซแแฎแแแ แแ แแแ แแแแก แกแฃแ แแแแแ แแแแแแฃแแแ.
แแแฉแแแแแแ = แงแแแแ.
memoryGameDidEnd
แแ แแแแแแแก แแแแแซแแฎแแแแกแแก, แแก แแแจแแแแก, แ แแ แงแแแแ แแแ แขแ แฃแแแ แแแแแแแแแแแแ แแ แแ แแก cardsShown แกแแแจแ: cardsShown.count = cards.count, แแกแ แ แแ แแแแแจแ แแแกแ แฃแแแ. แแแแแแก แแแแแแซแแฎแแแแ แแแแแ แแขแฃแแแ แแแก แจแแแแแ, แ แแช แฉแแแ แแแแฃแฌแแแแแ endGame() isPlaying var-แแก แแแกแแงแแแแแแแ false-แแ, แ แแก แจแแแแแแแช แแแแแฉแแแแแ แแแแแจแแก แแแกแ แฃแแแแแก แจแแขแงแแแแแแแ. แแกแแแ 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()
}
}
แกแแแแแแแแแแจแ, แแก แงแแแแแคแแ แแ. แแฅแแแ แจแแแแซแแแแ แแแแแแงแแแแ แแก แแ แแแฅแขแ แแแแแจแแก แกแแแฃแแแ แ แแแ แกแแแก แจแแกแแฅแแแแแแ.
แแแแแแแ แ แแแแแ แแแ!
Skillbox แแแ แฉแแแ:
- แแ แแฅแขแแแฃแแ แแฃแ แกแ
"Mobile Developer PRO" .- แแแแแ แแ แแแแแแ แแฃแ แกแก
"แแแแแแแก แแแแแชแแแแ แแแแแแขแแแแกแ" .- แแ แฌแแแแแ แแ แแฅแขแแแฃแแ แแฃแ แกแ
"แแ แแแ PRO แแแ แแแแแแแแแ แ" .
แฌแงแแ แ: www.habr.com