首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >iOS记忆游戏-斯威夫特4

iOS记忆游戏-斯威夫特4
EN

Code Review用户
提问于 2018-05-24 20:00:44
回答 1查看 1.9K关注 0票数 2

我正在通过斯坦福大学的iOS课程学习CS193P。我刚刚完成了第一次作业,并希望能进行代码评审,因为由于课程已经完成,我实际上无法提交作业以获得反馈。

需求可以在这里找到。但是任何关于最佳实践和我植入的建议都是有帮助的。该应用程序工作,并处于一个状态,我会提交,如果我可以。我只是在找另一双眼睛。

GitHub

代码语言:javascript
复制
    import Foundation
    /**
     a game card that contains the following var:
     - isFaceUp
     - isMatched
     - identifier
     */
    struct Card: Hashable
    {
        var hashValue: Int {
            return identifier
        }

        static func == (lhs: Card, rhs: Card) -> Bool {
            return lhs.identifier == rhs.identifier
        }

        var isFaceUp = false
        var isMatched = false
        private var identifier: Int

        private static var identifierFactory = 0

        private static func getUniqueIdentifer() -> Int {
            identifierFactory += 1
            return identifierFactory
        }

        init(){
            self.identifier = Card.getUniqueIdentifer()
        }
    }

        import Foundation

    struct Concentration
    {
        private(set) var cards = [Card]()
        private(set) var score = 0
        private(set) var flipCount = 0

        private var indexOfOneAndOnlyFaceUp: Int? {
            get {
                return cards.indices.filter({cards[$0].isFaceUp}).oneAndOnly
            }

            set {
                for flipDownIndex in cards.indices {
                    cards[flipDownIndex].isFaceUp = (flipDownIndex == newValue)
                }
            }
        }

        private var selectedIndex = Set<Int>()
        private var lastIndexWasSelected = false
        /// returns true if all cards have been matched
        var allCardsHaveBeenMatched: Bool {
            for index in cards.indices {
                if !cards[index].isMatched { return false }
            }
            return true
        }

        /**
         Choose a card at an index.
         Handles flip count, if a card is faced up, and matching of cards
         */
        mutating func chooseCard(at index: Int){
            assert(cards.indices.contains(index), "Concentration.chooseCard(at:\(index)): index is not in the cards")
            let cardWasPreviouslySelected = selectedIndex.contains(index)
            if !cards[index].isMatched {
                // only flip cards that are visible
                flipCount += 1
                if let matchIndex = indexOfOneAndOnlyFaceUp, matchIndex != index {
                    // 2 cards are face up, check if cards match
                    if cards[index] == cards[matchIndex] {
                        cards[index].isMatched = true
                        cards[matchIndex].isMatched = true
                        if lastIndexWasSelected {
                            // add extra to account for subtracting earlier
                            score += 3
                        } else {
                            score += 2
                        }
                    }else {
                        // no match
                        if cardWasPreviouslySelected {score -= 1}
                    }
                    cards[index].isFaceUp = true
                } else {
                    // one card is selected, turn down other cards and set this card
                    if cardWasPreviouslySelected { score -= 1 }
                    indexOfOneAndOnlyFaceUp = index
                    lastIndexWasSelected = cardWasPreviouslySelected
                }
            }

            selectedIndex.insert(index)
        }

        init(numberOfPairsOfCards: Int){
            assert(numberOfPairsOfCards > 0, "Concentraation.init(numberOfPairsOfCards:\(numberOfPairsOfCards) you must have multiple pairs of cards")
            for _ in 0..<numberOfPairsOfCards {
                let card = Card()
                cards += [card, card]
            }
            shuffleCards()
        }

        mutating private func shuffleCards() {
            for _ in 0..<cards.count {
                // sort seems better than .swap()
                cards.sort(by: {_,_ in arc4random() > arc4random()})
            }
        }
    }

    extension Collection {
        var oneAndOnly: Element? {
            return count == 1 ? first : nil
        }
    }

import Foundation

class Theme
{
    enum Theme: UInt32 {
        case halloween
        case love
        case animal
        case waterCreatures
        case plants
        case weather
    }

    /// get an array of icons by theme
    func getThemeIcons(by theme: Theme) -> [String] {
        switch theme {
        case .halloween:
            return ["", "", "", "", "", "☠️", "", ""]
        case .love:
            return ["","", "", "", "❤️", "", "", ""]
        case .animal:
            return ["", "", "", "", "", "", "", ""]
        case .waterCreatures:
            return ["", "", "", "", "", "", "", ""]
        case .plants:
            return ["", "", "", "", "", "", "", ""]
        case .weather:
            return ["", "❄️", "☀️", "", "☔️", "", "☁️", "", "⛈"]
        }
    }

    private func random() -> Theme {
        let max = Theme.weather.rawValue
        let randomIndex = arc4random_uniform(max + UInt32(1))
        return Theme(rawValue: randomIndex) ?? Theme.halloween
    }

    /**
     get a random array of themed icons

     - Author:
     Anna
     */
    func getRandomThemeIcons() ->[String] {
        return getThemeIcons(by: random())
    }

}

import UIKit

class ViewController: UIViewController {

    private lazy var game = Concentration(numberOfPairsOfCards: numberOfPairsOfCards)

    var numberOfPairsOfCards: Int {
        return (cardButtons.count + 1) / 2
    }

    @IBOutlet weak var finishedLabel: UILabel!
    @IBOutlet weak var scoreCountLabel: UILabel!
    @IBOutlet weak var flipCountLabel: UILabel!

    private var flipCount = 0 {
        didSet {
            flipCountLabel.text = "Flip Count: \(flipCount)"
        }
    }

    private var scoreCount = 0 { didSet { scoreCountLabel.text = "Score: \(scoreCount)"} }

    @IBOutlet var cardButtons: [UIButton]!

    @IBAction func touchCard(_ sender: UIButton) {
        if let cardNumber = cardButtons.index(of: sender){
            game.chooseCard(at: cardNumber)
            updateViewFromModel()
        }else {
            print("card is not in cardButton array")
        }
    }

    @IBAction func touchNewGame(_ sender: UIButton) {
        // reset game
        game = Concentration(numberOfPairsOfCards: (cardButtons.count + 1) / 2)
        // reset theme choices
        emojiChoices = theme.getRandomThemeIcons()
        // update view
        updateViewFromModel()
    }

    private func updateViewFromModel(){
        flipCount = game.flipCount
        scoreCount = game.score
        for index in cardButtons.indices {
            let button = cardButtons[index]
            let card = game.cards[index]
            if card.isFaceUp {
                button.setTitle(emoji(for: card), for: UIControlState.normal)
                button.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
            } else {
                button.setTitle("", for: UIControlState.normal)
                button.backgroundColor = card.isMatched ? #colorLiteral(red: 1, green: 1, blue: 1, alpha: 0) : #colorLiteral(red: 1, green: 0.5763723254, blue: 0, alpha: 1)
            }
        }
        finishedLabel.textColor = game.allCardsHaveBeenMatched ? #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) : #colorLiteral(red: 0.9999960065, green: 1, blue: 1, alpha: 0)
        finishedLabel.text = game.score >= 0 ? "Nice work! " : "Phew, ly made it"
    }
    private var theme = Theme()

    private lazy var emojiChoices = theme.getRandomThemeIcons()

    private var emoji = [Card: String]()

    private func emoji(for card: Card) -> String {
        if emoji[card] == nil, emojiChoices.count > 0 {
            emoji[card] = emojiChoices.remove(at: emojiChoices.count.arc4random)
        }
        return emoji[card] ?? "?"
    }
}

extension Int {
    var arc4random: Int {
        if self > 0 {
            return Int(arc4random_uniform(UInt32(self)))
        } else if self < 0 {
            return -Int(arc4random_uniform(UInt32(abs(self))))
        }else {
            return 0
        }
    }
}
EN

回答 1

Code Review用户

回答已采纳

发布于 2018-05-29 19:36:35

Concentration.swift

我几乎没有笔记:

  1. 最好描述一下这个实体是关于什么的。您可以在上述声明中添加注释。
代码语言:javascript
复制
import Foundation

struct Concentration
{
    private(set) var cards = [Card]()
    private(set) var score = 0
  1. 此代码可以是rewritеen:
代码语言:javascript
复制
var allCardsHaveBeenMatched: Bool {
        for index in cards.indices {
            if !cards[index].isMatched { return false }
        }
        return true
    }

更好/更短版本:

代码语言:javascript
复制
var allCardsHaveBeenMatched: Bool { !cards.contains(where: { !$0.isMatched } }
  1. 这种方法做得太多,很难读懂,考虑把它分成几个较小的方法(单一责任原则)。
代码语言:javascript
复制
/**
     Choose a card at an index.
     Handles flip count, if a card is faced up, and matching of cards
     */
mutating func chooseCard(at index: Int){

Card.swift

  1. 使用UUID()代替
代码语言:javascript
复制
private static var identifierFactory = 0

    private static func getUniqueIdentifer() -> Int {
        identifierFactory += 1
        return identifierFactory
    }

Theme.swift

可以这样重写(使用枚举而不包含类):

代码语言:javascript
复制
import Foundation


enum Theme: UInt32 {
    case halloween
    case love
    case animal
    case waterCreatures
    case plants
    case weather

    /// get an array of icons by theme
    var icons: [String] {
        switch self {
        case .halloween:
            return ["", "", "", "", "", "☠️", "", ""]
        case .love:
            return ["","", "", "", "❤️", "", "", ""]
        case .animal:
            return ["", "", "", "", "", "", "", ""]
        case .waterCreatures:
            return ["", "", "", "", "", "", "", ""]
        case .plants:
            return ["", "", "", "", "", "", "", ""]
        case .weather:
            return ["", "❄️", "☀️", "", "☔️", "", "☁️", "", "⛈"]
        }
    }

    static func randomTheme() -> Theme {
        let max = Theme.weather.rawValue
        let randomIndex = arc4random_uniform(max + UInt32(1))
        return Theme(rawValue: randomIndex) ?? Theme.halloween
    }
}

总结一下:您的代码还不错,但是需要一些改进。您正在使用封装来隐藏实现细节,并且比引用类型(类)更喜欢值类型(如structs)。这是很好的陈述点!

PS:欢迎来到代码审查!!

票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/195113

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档