(3/18) re-learn Standford_iOS7 development _ Objective-C _ course notes, iPhone 4 upgrade ios7
Lesson 3:
This course is mainly a demo of game implementation. Therefore, I will extract some simple programming skills from the course, focusing on how to implement the requirements in my homework.
Card game implementation:
① The game is a part of the Model (understand What the Model is: Model = What your application is (but not how it is displayed) UI is irrelevant.
② Programming skills: when creating a new class, first consider the public part (API), that is, how others use this class, and then consider its implementation details to drive the entire design.
③ When NSInteger, NSUInteger, int, and unsigned int are used in attributes, only style consistency is required.
Official definitions of NSInteger and NSUInteger:
1 #if __LP64__ || (TARGET_OS_EMBEDDED &&! TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64
2 typedef long NSInteger;
3 typedef unsigned long NSUInteger;
4 #else
5 typedef int NSInteger;
6 typedef unsigned int NSUInteger;
7 #endif
④About the attribute read-only problem: the attribute can be set to read-only in the public API, and the attribute can be declared as read-write again in the implementation code. Unless specified during attribute declaration, the default is read-write attribute.
E.g:
1 @interface example: NSObject
2
3 @property (nonatomic, readonly) Objectype number;
4
5 @end
1 @interface example ()
2
3 @property (nonatomic, readwrite) Objectype number;
4
5 @end
6
7
8 @implementation NUNetWork
9
10 @end
⑤ IBOutletConllection: Multiple output ports must be strong, because the NSArray stores the output port, the UI is pointed by the view pointer, and NSArray must be specified as strong to remain in the heap.
Such as: @property (strong, nonatomic) IBOutletCollection (UIButton) NSArray * cardButtons;
IBOutletCollection (UIButton) is similar to IBOutlet or IBAction, and the compiler will ignore it.
The order of UI in NSArray is unknown (cannot be regarded as the order of dragging in)
⑥ Homework
A. Run the current version of Matchismo on the simulator
B. Add a button to restart the game (including UI reset, card pile reset, score reset, etc.)
C. Use UISwitch or UISegmentedControl to switch between two card matching and three card matching game modes. (Note that the score of three cards matching success or failure is more significant than the two cards, in the three card matching two cards will not produce a matching result) (you can consider n cards matching)
D. After the game starts, the function of controlling the game in c is invalid until the game ends or restarts.
e. Adding lable to indicate the game progress status (for example: "Matched J ♥ J ♠ for 4 points." or "6 ♦ J ♣ don't match! 2 point penalty!" or "8 ♦" means only one card is returned. No matching, etc.) (Do not violate MVC rules)
F. Expand the number of cards from 12 to 30 (40 * 60)
G. Don't change the previous code, you can add public or private API
Homework answer:
The final effect is as shown
1. Add the following output ports:
1 @property (weak, nonatomic) IBOutlet UIButton * restartButton;
2
3 @property (weak, nonatomic) IBOutlet UISegmentedControl * gameModelSelectSegmented;
4
5 @property (weak, nonatomic) IBOutlet UILabel * gameModelLable;
6
7 @property (weak, nonatomic) IBOutlet UITextField * matchModelTextFiled;
8
9 @property (weak, nonatomic) IBOutlet UILabel * gameStateLable;
2. Restart the game function
Considering that the game mode has not been determined after restarting the game, it is necessary to rewrite the initialization that does not include the game attribute (the game setter will automatically initialize the game)
1-(IBAction) touchRestartButton
2
3 {
4 // Restore the default value
5 self.gameModelSelectSegmented.enabled = YES;
6 self.matchModelTextFiled.enabled = YES;
7 self.matchModelTextFiled.enabled = YES;
8 self.gameModelSelectSegmented.selectedSegmentIndex = 0;
9 self.selfDefiningModel = 2;
10 self.gameModelLable.text = [NSString stringWithFormat: @ "game model:% d", _ selfDefiningModel];
11 self.matchModelTextFiled.text = nil;
12
13 self.game = nil;
14 [self updateUIWithNotCreateGame];
15}
16
17-(void) updateUIWithNotCreateGame
18 {
19 for (UIButton * cardButton in self.cardButtons)
20 {
21 [cardButton setTitle: @ "" forState: UIControlStateNormal];
22 [cardButton setBackgroundImage: [UIImage imageNamed: @ "cardBack"] forState: UIControlStateNormal];
23 cardButton.enabled = YES;
twenty four }
25
26 self.gameStateLable.text = @ "State";
27 self.scoreLable.text = @ "Score: 0";
28}
3. Realization of multiple game modes and game status output
// Viewcontroller added user-defined game mode
@Property (nonatomic) NSUInteger selfDefiningModel;
Selector initialization (the viewDidLoad method is placed here, which is a bit out of range. The target-action of the selector is a method for the MVC view to communicate with the controller. SelfDefiningModel is the game mode that the user can set by himself. For 2)
Can also use UISwitch. In order to achieve multi-card matching, this article uses UISegmentedControll. Interested friends can try UISwitch implementation.
1 [self.gameModelSelectSegmented addTarget: self action: @selector (segmentAction :) forControlEvents: UIControlEventValueChanged]; // target-action
2
3 _selfDefiningModel = 2; // default model
Selector response method (action)
1-(void) segmentAction: (UISegmentedControl *) Seg
2 {
3 if (self.gameModelSelectSegmented.selectedSegmentIndex == 2) // This is a custom input
4 {
5 [self assertSelfDefiningModel: self.matchModelTextFiled.text]; // detect user input
6}
7 else
8 {
9 self.selfDefiningModel = self.gameModelSelectSegmented.selectedSegmentIndex + 2; // SegmengtdControll selector selection bar starts from 0
10}
11
12 self.gameModelLable.text = [NSString stringWithFormat: @ "game model:% d", self.selfDefiningModel];
13}
Custom input detection, set to a numeric keyboard, only detect the input range (due to the arbitrariness of user input, you need to consider various possible input situations, this article uses a numeric keyboard for simplicity, so you only need to detect the rationality of numeric input Just)
1-(void) assertSelfDefiningModel: (NSString *) text
2 {
3 if ([self.matchModelTextFiled.text integerValue] <2)
4 {
5 [[[UIAlertView alloc] initWithTitle: @ "Wrong" message: @ "game model at least 2" delegate: nil cancelButtonTitle: @ "certain" otherButtonTitles: nil, nil] show]; // The matching mode is at least 2
6 self.matchModelTextFiled.text = @ "";
7 self.gameModelSelectSegmented.selectedSegmentIndex = 0;
8 }
9 else if ([self.matchModelTextFiled.text integerValue]> 30)
10 {
11 [[[UIAlertView alloc] initWithTitle: @ "Wrong" message: @ "beyond card max number" delegate: nil cancelButtonTitle: @ "certain" otherButtonTitles: nil, nil] show]; // The matching card mode cannot exceed the maximum card in the interface Quantity
12 self.matchModelTextFiled.text = @ "";
13 self.gameModelSelectSegmented.selectedSegmentIndex = 0;
14}
15 else
16 {
17 self.selfDefiningModel = [self.matchModelTextFiled.text integerValue]; // Save the input result when the custom input is correct
18}
19}
UITextFiled delegate (that is, another way of communication between View and Controller in MVC, slightly out of range, do n’t understand and do n’t make a request), the purpose is to click the return button of the keyboard
1-(BOOL) textFieldShouldReturn: (UITextField *) textField
2 {
3 [textField resignFirstResponder];
4 return YES;
5}
4, Mode Partial realization
PlayingCard rewrite match: method
Before rewriting (only two cards are matched):
1-(int) match: (NSArray *) otherCards
2 {
3 int score = 0;
4
5 // two card match
6 if ([otherCards count] == 1)
7 {
8 PlayingCard * otherCard = [otherCards firstObject];
9 if ([self.suit isEqualToString: otherCard.suit])
10 {
11 score = 1;
12}
13 else if (self.rank == otherCard.rank)
14 {
15 score = 4;
16}
17}
18 return score;
19}
After rewriting (applicable to multi-card matching): Here I simply implemented the following rules: any two cards with the same attributes are considered to match this card with the cards in the array, the reader can try more complex rules, such as Only cards with equal numbers or suits can be considered as matches, etc.)
1-(int) match: (NSArray *) otherCards
2 {
3 int score = 0;
4
5 // n card match (at least two card have same element, we think they are matched)
6 for (PlayingCard * otherCard in otherCards)
7 {
8 if ([self.suit isEqualToString: otherCard.suit])
9 {
10 score + = 1;
11}
12 else if (self.rank == otherCard.rank)
13 {
14 score + = 4;
15}
16}
17
18 return score;
19}
Game public API added game mode and status attributes
@Property (nonatomic) NSUInteger gameModel; //> = 2
@Property (nonatomic, readonly) NSString * gameState;
Realize file change permission
@Property (nonatomic, readwrite) NSString * gameState;
Rewrite the logic of selecting card method:
The hardest part of this assignment is the logical core of the entire game. First, keep the matching frame of the two cards unchanged. Introduce a new array variable otherCards to save the cards that need to be matched. First use the for loop to traverse to detect the status of the cards. If it meets the requirements, add otherCards. After traversal, check whether the array size meets the game mode requirements (Note that the size of the matching array of n cards should be n-1, think about why? :)) If it does not match, it returns, and if it matches, it starts to match. When the size of the array is smaller than the requirements of the game mode, it should be noted here that the storage position of the card state is different from that when the two cards are matched. The code comments below have detailed instructions. Scoring logic during matching: Multiply the number of game modes on the original basis, and the higher the matching success score, the harder the matching rules are. And save the game state to gameState during the matching process.
1-(void) chooseCardAtIndex: (NSUInteger) index
2 {
3 Card * card = [self cardAtIndex: index];
4 if (! Card.isMacthed)
5 {
6 if (card.isChosen)
7 {
8 card.chosen = NO;
9 }
10 else
11 {
12 // match against other chosen cards
13
14 NSMutableArray * otherCards = [NSMutableArray arrayWithCapacity: self.gameModel];
15 for (Card * otherCard in self.cards)
16 {
17 if (otherCard.isChosen &&! OtherCard.isMacthed)
18 {
19 [otherCards addObject: otherCard];
20}
twenty one }
twenty two
23 // Cannot be placed before the for loop, otherwise the selected card will be added to the cards this time, cannot be placed after the if below, otherwise it will return when the if is established, the cost of this flop is not recorded and cannot be turned brand
24 self.score-= COST_TO_CHOOSE * self.gameModel;
25 card.chosen = YES;
26
27 if ([otherCards count] <self.gameModel-1)
28 {
29 self.gameState = [NSString stringWithFormat: @ "State:% @", card.contents];
30 return;
31}
32 else
33 {
34 int matchScore = [card match: otherCards];
35
36 if (matchScore)
37 {
38 NSMutableString * state = [NSMutableString stringWithFormat: @ "State:% @ matched", card.contents];
39 self.score + = matchScore * MATCH_BOUNDS * self.gameModel;
40 for (Card * otherCard in otherCards)
41 {
42 [state appendFormat: @ "% @", otherCard.contents];
43 otherCard.matched = YES;
44}
45 [state appendFormat: @ ". Get% d score!", MatchScore * MATCH_BOUNDS * self.gameModel];
46 card.matched = YES;
47
48 self.gameState = state;
49}
50 else
51 {
52 NSMutableString * state = [NSMutableString stringWithFormat: @ "State:% @ with", card.contents];
53 self.score-= MISMATCH_PENALTY * self.gameModel;
54 for (Card * otherCard in otherCards)
55 {
56 [state appendFormat: @ "% @", otherCard.contents];
57 otherCard.chosen = NO;
58}
59 [state appendFormat: @ "not matched!% D point penalty!", MISMATCH_PENALTY * self.gameModel];
60
61 self.gameState = state;
62}
63}
64}
65}
66}
Summary of homework: Although the requirements of the homework have been completed, there are still many areas for improvement. For example, if the 30 threshold of the input detection is a specific number, you can consider changing to [cardButtons count]. The scoring logic of the game is not perfect. In the case of a large game matching mode (it seems to appear when 5 cards are matched: p ) Extreme scores are prone to occur, you can download the source code and try it out. Display problem when the number of Lable characters in the game state is too large. Is there a better way to implement the logic of the restart button? In this article, in order to prevent the updateUI method in restart from re-initializing nil immediately after the game is set to nil (at this time selfDefiningModel is the initial value of 2), a method for updating the UI has been rewritten. Is there no lighter method (such as more in line with MVC)? These questions are all intrigues, I did not think about it, I hope everyone will actively think about communication, if you are wrong, please correct me :)
Assignment source address: https://github.com/NSLogMeng/Stanford_iOS7_Study_Machismo/commit/39819086ac1c0b7a38679b75307b1cf0a687a190 (in the future, I will send the commit link to everyone for the same project for each assignment in the future)
------------------------------------------------I'm Later added ------------------------------------
Just found a serious problem when playing on the real machine. . . . The numeric keyboard does not have a return key, the numeric keyboard does not have a return key, and the numeric keyboard does not have a return key! ! ! The emulator typed it directly on the keyboard of the computer, and did not realize it at all _ (: 3 ∠) _
Angrily changed, added view response event, hide the keyboard, but this part of the source code is not posted, just add a method, this part has been seriously out of outline. But if you are interested, you can take a look, github has been updated.
Latest version: https: