用swift重写stanford CS193P的纸牌游戏 (2)- PlayingCard,PlayingDeck和ViewCotronller

本系列编号基本对应stanford CS193P的课程编号,可能有一两节课的误差:比如我标(1)就对应Lecture 1,但有时我做得快了就变成(1)对应lecture 1的全部和lecture 2的一部分。

正文:

本文包括三个类,PlayingCard和PlayingDeck,两个单元测试类,和两个单元测试的用到的工具类。

写完之后的感觉:只要写完view controller这个程序就能在iphone上有个用户界面可以点了,刚做出来的时候还是挺有成就感的。在看swift的电子书只看了一两章的时候我就想把这个做出来,但是没写对。

后来在网上一搜发现别人也有在做这个,而且也在问这个怎么写。然后我借鉴他贴的代码把这个写出来了。再后面把书又读了几章,才决定再次重新开始继续看这个CS193P的课程,这次总算能跟上进度了。

 

具体值得记录的点有:

1.每个类都可以选TargetMembership,单元测试类应该只选CardGameTest,待测类应该同时选CardGame和CardGameTest。CardGame是我的应用名字。

 选对之后我就不用一直用默认提供的CardGameTests这个类了,我后面写了两个分开的单元测试类

2.PlayingCard类里,suit和rank做了合法值校验,比如rank不能大于13,suit不能取四种花色以外的值。

  这点在CS193P里,OC下用的做法是重载了这两个变量的setter,我的做法是用了swift的did set功能来校验。

3.PlayingCardTests是我写来测试PlayingCard的。原CS193P的老外是不写单元测试的。但我现在主职业是做测试的,所以我写了单元测试。

思路是一点一点校验PlayingCard类提供的所有东西,包括suit和rank的默认值或最大值,单个变量成功的设置、不成功的设置时的校验、

 4.PlayingCardDeckTests里我通过检查deck里所有元素来检查待测的init方法。

并且在其后做了2次抽牌,抽牌之前先记录当前卡组,做随机抽牌,抽牌之后先用正则表达式证明抽到的牌在抽牌之前在卡组中,再用正则表达式判断被抽出的牌在抽牌之后不再在卡组中。

5.DeckPrintHelper只是用来打印当前卡组中的所有牌和打印随机抽出的牌,为了减少重复代码用。Regex是我从网上找来的swift正则表达式封装好的工具类

代码:

 

首先是ViewController,里面只有一个IBOutlet和一个IBAction

复制代码
 1 //
 2 //  ViewController.swift
 3 //  CardGame
 4 //
 5 //  Created by colin.zt on 14-6-6.
 6 //  Copyright (c) 2014 Ting. All rights reserved.
 7 //
 8 
 9 import UIKit
10 
11 class ViewController: UIViewController {
12                             
13  
14     @IBOutlet var flipCount : UILabel
15 
16     var flipCountNum: Int = 0
17     override func viewDidLoad() {
18         super.viewDidLoad()
19         // Do any additional setup after loading the view, typically from a nib.
20     }
21 
22     override func didReceiveMemoryWarning() {
23         super.didReceiveMemoryWarning()
24         
25         // Dispose of any resources that can be recreated.
26     }
27     
28     @IBAction func touchButton(sender : UIButton) {
29     //check the card title to know which side is upside
30     //then flip it by change the background image and title
31         if (sender.currentTitle.isEmpty){
32             sender.setTitle("A♣︎", forState: UIControlState.Normal)
33             sender.setBackgroundImage(UIImage(named:"CardFront"),forState:  UIControlState.Normal)
34         } else {
35             sender.setTitle("", forState: UIControlState.Normal)
36             sender.setBackgroundImage(UIImage(named:"CardBack"),forState:  UIControlState.Normal)
37         }
38     //increse the flip count number
39         flipCountNum++
40     //update the flip count on screen
41         setFlipCount()
42     }
43     
44     func setFlipCount(){
45         // update the flip count by reset the text of the label
46         flipCount.text = "Flips:" + String(flipCountNum)
47 
48     }
49     
50 
51 }
复制代码

 

然后是PlayingCard类,他是Card类的子类

复制代码
 1 //
 2 //  PlayingCard.swift
 3 //  CardGame
 4 //
 5 //  Created by colin.zt on 14-10-18.
 6 //  Copyright (c) 2014 Ting. All rights reserved.
 7 //
 8 
 9 import UIKit
10 
11 class PlayingCard: Card {
12    //in did set, do a check and make it can't set to invalid value
13     var suit: String = "?" {
14         didSet {
15             //#####could improve or not: is there a simpler way to check if an element is in an array?
16             for it in PlayingCard.valid_suits{
17                 if it == suit{
18                 return
19                 }
20             }
21             suit = oldValue
22         }
23     }
24    //in did set, do a check and make it can't set to invalid value
25     var rank: Int = 0 {
26         didSet {
27             if rank > PlayingCard.max_rank{
28                 rank = oldValue
29             }
30 
31         }
32     }
33     
34     //all valid ranks in this game,"?" means unset
35     class var rank_strings:String[] {
36     return ["?","A","2","3","4","5","6","7","8","9","10","J","Q","K"]
37     }
38     
39     //define the max rank
40     class var max_rank:Int{
41     return rank_strings.count - 1
42     }
43     
44     //all valid suits
45     class var valid_suits:String[]{
46     return ["♥︎","♦︎","♠︎","♣︎"]
47     }
48     
49     init() {}
50 
51     //just pirnt the rank and suit, and rank 11 will be rank "J",and so n
52     func contents() -> String{
53         return PlayingCard.rank_strings[self.rank]+self.suit
54     }
55     
56     
57 }
复制代码

接着是PlayingCardDeck类,他是Deck类的子类

 

复制代码
 1 //
 2 //  PlayingCardDeck.swift
 3 //  CardGame
 4 //
 5 //  Created by colin.zt on 14-10-20.
 6 //  Copyright (c) 2014 Ting. All rights reserved.
 7 //
 8 
 9 import UIKit
10 
11 class PlayingCardDeck: Deck {
12     //just init the deck with 52 cards
13     init(){
14     super.init()
15     for suit in PlayingCard.valid_suits{
16         for (var rank = 1; rank <= PlayingCard.max_rank; rank++){
17             var card: PlayingCard = PlayingCard()
18             card.rank = rank
19             card.suit = suit
20             cards.append(card)
21             }
22         }
23     
24     }
25     
26 }
复制代码

为了测试这两个类,写了两个单元测试:

PlayingCardTests

  View Code

PlayingCardDeckTests

  View Code

其中有写打印所有card的方法写在了工具类里

DeckPrintHelper

  View Code

还有一个正则表达式的工具类

Regex

复制代码
 1 //
 2 //  Regec.swift
 3 //  CardGame
 4 //
 5 //  Created by colin.zt on 14-10-20.
 6 //  Copyright (c) 2014年 Ting. All rights reserved.
 7 //
 8 
 9 import Foundation
10 
11 class Regex: NSObject {
12     let internalExpression: NSRegularExpression
13     let pattern: String
14     
15     init(_ pattern: String) {
16         self.pattern = pattern
17         var error: NSError?
18         self.internalExpression = NSRegularExpression(pattern: pattern, options: .CaseInsensitive, error: &error)
19     }
20     
21     func is_found_in(input: String) -> Bool {
22         let matches = self.internalExpression.matchesInString(input, options: nil, range:NSMakeRange(0, countElements(input)))
23         var count = matches.count
24         return matches.count > 0
25     }
26 }
27 
28 //Usage Example: Regex("\\w{4}").is_found_in("abdddcd")
复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值