用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

 1 //
 2 //  PlayingCardTests.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 XCTest
10
11 class PlayingCardTests: XCTestCase {
12
13     override func setUp() {
14         super.setUp()
15         // Put setup code here. This method is called before the invocation of each test method in the class.
16     }
17
18     override func tearDown() {
19         // Put teardown code here. This method is called after the invocation of each test method in the class.
20         super.tearDown()
21     }
22
23     func testExample() {
24         // This is an example of a functional test case.
25         var p_card: PlayingCard = PlayingCard()
26
27         println(PlayingCard.valid_suits)
28         println(PlayingCard.rank_strings)
29         println(PlayingCard.max_rank)
30
31
32         XCTAssert(PlayingCard.valid_suits == ["♥?","♦?","♠?","♣?"], "Pass")
33         XCTAssert(PlayingCard.rank_strings == ["?","A","2","3","4","5","6","7","8","9","10","J","Q","K"], "Pass")
34         XCTAssert(PlayingCard.max_rank == 13, "Pass")
35
36         XCTAssert(p_card.contents == "??","Pass")
37         println(p_card.contents)
38
39         p_card.suit = "♥?"
40         p_card.rank = 11
41         println("this card:\(p_card.contents)")
42         XCTAssert(p_card.contents == "J♥?","Pass")
43
44         p_card.suit = "♀" // try to set an invalid value, it will be ignored  because I do the check in didSet of the suit
45         println(p_card.contents)
46         XCTAssert(p_card.contents == "J♥?","Pass")
47
48
49         p_card.suit = "♣?"
50         println(p_card.contents)
51         XCTAssert(p_card.contents == "J♣?","Pass")
52
53         p_card.rank = 33
54         println(p_card.contents)
55         XCTAssert(p_card.contents == "J♣?","Pass")
56
57         p_card.rank = 13
58         println(p_card.contents)
59         XCTAssert(p_card.contents == "K♣?","Pass")
60
61     }
62
63     func testPerformanceExample() {
64         // This is an example of a performance test case.
65         self.measureBlock() {
66             // Put the code you want to measure the time of here.
67         }
68     }
69
70 }

PlayingCardDeckTests

 1 //
 2 //  PlayingCardDeckTests.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 XCTest
10
11 class PlayingCardDeckTests: XCTestCase {
12
13     override func setUp() {
14         super.setUp()
15         // Put setup code here. This method is called before the invocation of each test method in the class.
16     }
17
18     override func tearDown() {
19         // Put teardown code here. This method is called after the invocation of each test method in the class.
20         super.tearDown()
21     }
22
23     func testExample() {
24         // This is an example of a functional test case.
25
26         //to test the init method, I create a new deck
27         var card_deck: PlayingCardDeck = PlayingCardDeck()
28
29        // the expected result
30         var expected_card_string: NSString = "A♥?,2♥?,3♥?,4♥?,5♥?,6♥?,7♥?,8♥?,9♥?,10♥?,J♥?,Q♥?,K♥?,A♦?,2♦?,3♦?,4♦?,5♦?,6♦?,7♦?,8♦?,9♦?,10♦?,J♦?,Q♦?,K♦?,A♠?,2♠?,3♠?,4♠?,5♠?,6♠?,7♠?,8♠?,9♠?,10♠?,J♠?,Q♠?,K♠?,A♣?,2♣?,3♣?,4♣?,5♣?,6♣?,7♣?,8♣?,9♣?,10♣?,J♣?,Q♣?,K♣?,"
31
32         //print and check the deck, if it has all 52 cards
33         XCTAssert( DeckPrintHelper.printDeck(card_deck) == expected_card_string,"Pass" )
34
35         //check the card number in the deck
36         XCTAssert(card_deck.cards.count == 52, "Pass")
37
38         //draw a card and check again
39         var draw_this_card = DeckPrintHelper.drawRandomCard(card_deck)
40        // Regex("K♥?").is_found_in(DeckPrintHelper.printDeck(card_deck))
41        // Regex(",").is_found_in(DeckPrintHelper.printDeck(card_deck))
42         XCTAssert( Regex(draw_this_card.contents).is_found_in(expected_card_string),"Pass" )
43         // use regex to check if still contain this card
44        var after_draw_once = DeckPrintHelper.printDeck(card_deck)
45         XCTAssert( Regex(draw_this_card.contents).is_found_in(after_draw_once) == false,"Pass" )
46         XCTAssert(card_deck.cards.count == 51, "Pass")
47
48         //do it again
49         draw_this_card = DeckPrintHelper.drawRandomCard(card_deck)
50     XCTAssert( Regex(draw_this_card.contents).is_found_in(after_draw_once),"Pass" )
51         XCTAssert( Regex(draw_this_card.contents).is_found_in(DeckPrintHelper.printDeck(card_deck)) == false,"Pass" )
52         XCTAssert(card_deck.cards.count == 50, "Pass")
53
54
55     }
56
57
58
59     func testPerformanceExample() {
60         // This is an example of a performance test case.
61         self.measureBlock() {
62             // Put the code you want to measure the time of here.
63         }
64     }
65
66 }

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

DeckPrintHelper

 1 //
 2 //  DeckPrintHelper.swift
 3 //  CardGame
 4 //
 5 //  Created by colin.zt on 14-10-20.
 6 //  Copyright (c) 2014 Ting. All rights reserved.
 7 //
 8
 9 //a help class which contains some test logic for reuse
10 import UIKit
11 class DeckPrintHelper: NSObject {
12
13     // to print and return the deck string in my format
14     class func printDeck(deck: Deck) -> String{
15         var card_string: String = ""
16         println("\n_______________________________________")
17         println("Now these cards in deck")
18         for card in deck.cards{
19            card_string += ("\(card.contents),")
20         }
21         println(card_string)
22         println("_______________________________________")
23
24     return card_string
25     }
26
27     // to draw a random card while printing some comments
28     class func drawRandomCard(deck: Deck) -> Card{
29         var random_card = deck.drawRandomCard()
30         println("Now draw this random card:")
31         println(random_card.contents)
32         return random_card
33     }
34 }

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

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

时间: 2024-10-09 20:28:14

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

用swift重写stanford CS193P的纸牌游戏 (1)- Card 和Deck

本系列编号基本对应stanford CS193P的课程编号,可能有一两节课的误差:比如我标(1)就对应Lecture 1,但有时我做得快了就变成(1)对应lecture 1的全部和lecture 2的一部分. 前言: 我没学过OC,想学swift,可是网上只有教swift基本语法和写命令行程序的初级教程. 所以我只好拿个OC的教程,一边学swift,一边把OC的教程里的代码改成swift的,我想改完了之后应该就等于看了swift的教程了吧. 正文: 本文包括两个类,Card和Deck,以及一个单

hdu2209翻纸牌游戏(bfs+状态压缩)

Problem Description 有一种纸牌游戏,很有意思,给你N张纸牌,一字排开,纸牌有正反两面,开始的纸牌可能是一种乱的状态(有些朝正,有些朝反),现在你需要整理这些纸牌.但是麻烦的是,每当你翻一张纸牌(由正翻到反,或者有反翻到正)时,他左右两张纸牌(最左边和最右边的纸牌,只会影响附近一张)也必须跟着翻动,现在给你一个乱的状态,问你能否把他们整理好,使得每张纸牌都正面朝上,如果可以,最少需要多少次操作. Input 有多个case,每个case输入一行01符号串(长度不超过20),1表

HDU 2209 翻纸牌游戏(DFS)

题目链接 Problem Description 有一种纸牌游戏,很有意思,给你N张纸牌,一字排开,纸牌有正反两面,开始的纸牌可能是一种乱的状态(有些朝正,有些朝反),现在你需要整理这些纸牌.但是麻烦的是,每当你翻一张纸牌(由正翻到反,或者有反翻到正)时,他左右两张纸牌(最左边和最右边的纸牌,只会影响附近一张)也必须跟着翻动,现在给你一个乱的状态,问你能否把他们整理好,使得每张纸牌都正面朝上,如果可以,最少需要多少次操作. Input 有多个case,每个case输入一行01符号串(长度不超过2

翻纸牌游戏(dfs回溯)

翻纸牌游戏 Time Limit : 9000/3000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Submission(s) : 2   Accepted Submission(s) : 2 Problem Description 有一种纸牌游戏,很有意思,给你N张纸牌,一字排开,纸牌有正反两面,开始的纸牌可能是一种乱的状态(有些朝正,有些朝反),现在你需要整理这些纸牌.但是麻烦的是,每当你翻一张纸牌(由正翻

拉米纸牌游戏开发之路学习篇2

在篇1中的Deck类中表示一副纸牌采用的是Card数组的方法,该种方法灵活性较小,在纸牌游戏中经常会用到一组纸牌的操作,在此有必要创建纸牌集合类Cards 1.通过继承集合类实现 首先介绍System.Collection空间中的ArryList类吧,该类继承了IList接口,可以动态添加或者移去元素,很好用.对之前的代码只需略加修改.具体修改如下: (1)处,需要修改Deck类的字段 //private Card[] _Cards=new Card[52]; private ArrayList

HDU2209 ( 翻纸牌游戏 )

思路:枚举然后深搜,时间复杂度有点高. 代码: 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 int a[25]; 7 char c[25]; 8 int flag; 9 int len; 10 int judge() 11 { 12 int i,j; 13 int cnt=0; 14 for

纸牌游戏之六 游戏概述

游戏规则概述: 进入纸牌游戏之后,会输入名称进入游戏: 二:游戏的主界面,五局制和七局制: 三:游戏完毕之后,出现游戏排行榜,使用SQLite保存到数据库

NYOJ 614 纸牌游戏

纸牌游戏 时间限制:1000 ms  |  内存限制:65535 KB 难度:2 描述 设2n张牌分别标记为1,2,-,n,n+l,-,2n,初始时这2n张牌按其标号从小到大排列. 经一次洗牌后,原来的排列顺序变成n+l,l,n+2,2,··,,2n,n. 即前n张牌被放到偶数位置2,4,·,·,2n,而后n张牌被放到奇数位置1,3,-,2n-l. 可以证明对于任何一个自然数n,经过若干次洗牌后可恢复初始状态. 编程任务:对于给定的n的值(n<=24000),编程计算最少经过多少次洗牌可恢复到初

HDU 2209 翻纸牌游戏(dfs)

翻纸牌游戏 Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2180    Accepted Submission(s): 787 Problem Description 有一种纸牌游戏,很有意思,给你N张纸牌,一字排开,纸牌有正反两面,开始的纸牌可能是一种乱的状态(有些朝正,有些朝反),现在你需要整理这些纸牌.但是麻烦的是,每当你翻一张