Tip:
Highlight text to annotate it
X
=
[ Music ]
>> Stanford University.
>> Okay, well welcome to Lecture number 3
of CS193p for fall of 2013/14.
Today I'm going to jump right into a demo and then
after that I have some slides, time permitting,
assuming the demo doesn't take [pause] the whole time here,
and after, the demo I'm going to do is I'm going
to take the little card thing we did last week and turn it
into a real card matching game
where we're actually matching cards, okay,
rather than just flipping them over.
And, like I say, if I have the time I'll talk a little bit more
about objective-C and we're really going to go
into objective-C on Wednesday in quite a bit of detail.
I also included on the stuff I posted some review slides
at the end just kind
of reviewing what we will have learned
in the first three lectures, just so you can kind of look
through it real quick and say oh yeah, do I know that?
Yeah I do, and if not, than you can obviously post
and ask us questions about it.
Okay? So, let's do this demo.
So for the demo [background sounds],
I'm going to start this demo actually
by giving you the solution to the homework,
I told you I was going to do this, this is the only time
that I'm going to do this this quarter.
Normally I don't go over the solution, but the solution's
so simple and because obviously we need the solution of this
to move on to what I'm going to do today.
We'll do the solution first.
So here I'm just launching XCode, you can see now
in my recents I have this machismo from last time.
So, we'll bring that up.
There it is.
Make sure that we're using
as much screen real estate as we can here.
Get these wires out of my way.
Okay. So, from where we left off, hopefully you remember
because you did your homework.
We just have this single, this card, single card,
and it flips back and forth between the ace and the clubs,
and your homework was to use the model that we worked
on in lecture to make it flip through an entire deck.
So, the solution to that is quite straightforward.
We obviously need a deck so I'm just going
to add a property here, strong property, should be strong
because we need that deck to, to stay around, and it's going
to be a deck and I'm going to call it deck.
Okay? Now we have an error here because of deck,
so we have to go up here and import deck.
Alright? To make that error go away.
So now we got this property that's cool, obviously we want
to lose lazy instantiation to instantiate that property,
so I'm going to do that, that's a deck [inaudible] deck,
and I'm just going to see if my instance variable is null
or nil, rather, the 0, basically.
Then I'm going to say, sorry, underbar, underbar deck, equals,
and I'm actually going to create deck using another method here,
you'll see why in a second and then I'm going
to return underbar deck.
Okay? And create deck is just going to create a deck.
Create deck and I'm going to create a playing card deck,
because that's what you were asked to do so I'm just going
to do [inaudible] to do that.
I got an error because not only do I need to import deck,
but playing card deck, and it's actually kind
of unfortunate here that in this nice, generic card game
that I'm building, that I'm importing a playing card deck.
Why is that unfortunate?
Well, I'm going to try and build a card game here
that has nothing to do with playing cards.
Okay? It's going to be a generic,
should work with any kind of deck, okay, a deck of any kind
of cards and, in fact, in your homework, you're going
to be asked to enhanced the game next week
to play a different deck.
Okay? So it's unfortunate that I have to do this and in lecture,
either on Wednesday or probably on Monday, we will talk
about how we can get rid of this.
Okay, get this import playing card deck
and this create deck method to be more generic, okay,
not be so specific to playing cards.
But anyway, so now I have this deck
and it's lazily instantiated so now that I have a deck,
I can use it to get rid of this little ace
of clubs thing right here, okay?
And, I'm going to do that by saying here card star card
equals self dot deck, draw random card.
So I'm going to draw a random card out of the deck
and then instead of putting ace of clubs here,
I'm going to put the cards contents.
Okay? And that's really your entire homework assignment,
there's one other minor thing that I'm going to do here,
actually two minor things.
Because we don't want just a solution that works,
this will work if we run this.
We're going to see it work, but it's kind of not very elegant
and not really, it's not really a really very good solution
to the problem, even though it functions, you see, it's,
it's going through the random cards here.
But it was kind of annoying, a couple of things.
One, it started out with the ace of clubs, that was kind
of gross, okay, because if I keep clicking here,
eventually I'm going to get the ace of clubs,
there it was back again, so that's kind of bad.
The other thing is when this deck is empty, this is not going
to particularly elegantly, you know, finish off,
and we want to have some elegant solution and I said
in the hints come up with an elegant solution.
Also, this flips thing here,
once I flip through the whole deck,
it's going to keep flipping.
You know, it's going to be 102, 103, 104, 105,
that's not very elegant either.
So let's fix all three of those things with simple,
elegant solutions, okay?
So my simple, elegant solution to the ace of clubs
which I hinted at for you is simply to start it face down.
So I'm going to get the card back here, get rid of the ace
of clubs, and now this card starts out facedown.
So I didn't have to write any code and I just use my brain
over my brawn to make sure that this works, right?
So, that's kind of the elegant way of thinking
about solving that problem.
So we'll just start it face down, there's no,
there was no required task that said you had to start
with the ace of clubs face up, so that's a good solution.
When it comes to running out of cards,
I think an elegant solution is it just will stop flipping
at that point.
I mean, you could make arguments, load up another deck,
other stuff, but I think a simple solution is just once you
run out of cards, you keep clicking, and it stops flipping.
Okay? So how are we going to do that?
Well, I know some of you are going to say something like,
if number of flips equals 102, then stop flipping,
and that's really, really bad.
That's a very bad design, because that 102 is
like a magic number you just put into your program
and there's completely no reason for that bad design either.
All you need to do is just say if card, then flip it, okay,
so I'm going to flip it here,
I'll make some more space so you can see.
Otherwise, I'm not going to flip it.
Okay? So I'm just, this is a super elegant solution to,
you know, not continuing to flip this thing
over when the deck runs out,
and we know that draw a random card returns nil,
if you remember from our implementation it returns nil
when the deck is empty, so, perfect!
Once it's nil, it's just not going to flip back
over to the contents sides,
it's going to always stay on the backside.
Question? [Inaudible background question]
And flip count is the third thing that was kind
of not very elegant, so how can we fix that?
Well, you know, there's a number of ways to go at that,
but I think a simple way is to only flip, sorry,
when we actually do the flipping over.
Now, this is kind of not a great solution
because here we're not actually flipping over, you know, if,
if we're on the card back, then we're flipping over here,
so this one's kind of not so good, because we kind of gonna,
once we flip over to the back, we'll be okay
because when we start to do [pause],
we'll be executing this code over and over right here
because we'll always be on the back.
So I think this'll work, right?
Is that a good solution?
The reason I don't like it is I don't like having this line
of code in two different places, kind of eh.
I could have done a lot of other things here,
we could have factored out the image and the string
into separate local variables and had our if,
apply those, and stuff like that.
I think all of that would have been a little bit of overkill.
So, let's see if this works.
So here's our thing here, so it started facedown.
Let's click through the deck here,
I'll click through it quickly.
So I'm clicking so quickly through, you'll notice,
that I'm not giving time for the thing to finish animating, okay?
And we're going to start talking about animation
in the week after next.
And [pause] one thing about animation is it's going
to happen a little bit out of band
with what's actually happening.
So I am actually flipping here and all
that flipping is happening, but the animation is kind of slow
and it's staying behind, and that's kind of just,
unfortunately, the way it is,
the animation will eventually catch up, but here we go
to our last card, then we get facedown, and now we click,
and it's not clicking over and it's stopped at 104.
Okay? Any questions about this solution?
Pretty straightforward.
Again, elegance, simplicity, that's what you're shooting
for in your homework, okay?
Big, overwrought solutions where you're adding a bunch of API
and checking a lot of things are generally not preferred
over more simple solutions, so like this,
even if you have something where you kind of have these two lines
of code that are doing the same thing,
maybe shouldn't be replicated like this, it's a close call
as to the really perfect elegance, but I was going
for simplicity here too because I only have
so much time [laughing].
Okay?
>> Alright.
So now, we're going to go into doing the next phase
of our card matching game,
which is to make the game actually play.
Now the playing of the game is part of our model.
It's really important to understand, it's not part
of our controller, its part of our model.
Because I told you that the model is the what your game is.
Well, what is this?
It's a card matching game, so the what better be in the model.
So we're going to create a class in our model that is going
to encapsulate the logic of the game playing and it's not going
to know anything about user interface, okay?
It's not going to have any things in it that have anything
to do with user interface
and that's a really important distinction to make.
So, let's create that new class,
remember that we always create new class the same way you did
with your assignment today by saying new file.
Okay? And we want an objective-C class and I'm going
to call it card matching [pause] game.
Okay? And it's going to inherit from NSObject as all of our kind
of base classes do, and I'm going to put this thing
in the same directory as the rest of my model
and I'm also going to put it in the same group
than the navigator as my model, as well.
Okay? So it goes with all these guys and it goes in this group.
It's a nice thing to remember to do.
Alright? So we create it.
Here it is.
Okay? Here's its header file right here and I'm going
to use this counterparts, automatic counterparts,
to show the implementation, okay?
So there is its header file and its implementation,
and I always, when I design a new class, I always try
to give my first crack at its public API first.
Okay? I'll go do its implementation later,
but I want to kind of think of how are people going
to use my class first?
Just to drive my overall design, okay?
And that's for a simple class like this,
if you get into a more complicated class,
you might be having significant design meetings which are teamed
to understand what's this object, how does it fit
into the world, but if you're just doing a simple
straightforward class,
especially if you're doing its first iteration,
it sometimes nice to just think what is it's API, we call it,
okay, API is the Public Programming Interface
for a class.
So, I need to think of what this card matching game needs to do.
Well, one thing I know it needs is an initializer.
Okay? And int.
But when I think about my card gap matching game,
there's a couple of things it just has to know to initialize.
It can't just initialize itself like a playing card deck can.
A playing card deck knows everything it needs to know
about a playing card deck when it's started,
but this doesn't really know that, so,
I need a couple of things.
One thing I need is how many cards are we playing with?
Okay? How many cards are, is the person allowed to match total?
Right? What's the total amount of cards?
So we need that.
So I'm going to say, int with card count,
and we'll make an NSUInteger.
Really, that count has got to be at least two, you would think,
so I'd probably, in my initializer, should check
to make sure it's greater than one
and if it's not I'll probably return nil from self.
In other words, I won't initialize,
my [inaudible] will return nil.
Okay? And we'll, actually, we'll pick one way
where it does return nil, but we should probably check that too.
The second thing that I need is a deck, a deck of cards,
because I got to deal these cards out, right?
I'm going to deal them out and then you're going to be able
to pick some of them and do it.
So, I'm going to say using deck.
Deck star deck.
Okay, so there's the initializer, and, of course,
to do that I need to import deck, alright?
So that's pretty good.
Start there.
What else do I need for my game?
Well it's a game, so I think it should have a score.
[Pause] Eh, we'll say NSInteger score.
And, again, NSInteger,
NSUInteger versus unsigned int is kind of a style thing,
I used NSUInteger above, I'm going to use NSInteger
to be consistent here and my score can be negative possibly.
So that's why it's not an NSUInteger, it can be negative.
And notice I made this property read only.
It's the first time we've seen that.
And why is that?
Well that's because I'm the game logic,
I get to determine what the score is,
nobody can set the score, I tell you what the score is.
Therefore, there should be no setter for this property.
At least not publicly.
You're going to see in a moment, privately,
we're going to make this rewrite
so that we can set it privately, right?
Because we obviously need to be updating our score all the time
as people flip these cards over and get matches,
they get points, we need to update it.
But publicly, we want it to be a read only.
Okay? The only other thing I need to do is someone's going
to be clicking on these cards; they're going to be flipping
over and being chosen and possibly matching,
so I need some sort of method to let somebody choose a card.
So, I'm going to call this choose card at index,
NSUInteger, again, index.
So, there's a lot of ways in API you could have
for letting someone choose a card.
The person who creates this card matching game, not the person,
but the other object, like a controller
that creates this model class, knows the count,
because it specified the counter cards.
So, it's pretty reasonable to have them specify an index,
which means 0, in this count minus 1,
anytime someone chooses a card.
Okay?
So this is just a simple way of specifying
which card did the user choose?
And similarly, I actually need to be able to return a card
at a given index, and why do I need this?
Well, I need to be able to find out the state of the game
at any given time, I mean, how is my controller going
to display a UI for this game if it can't, you know,
if it can't find out what the cards, what the state
of the cards is, so this is just a little way for it
to get the cards, and it could iterate through all the cards
and get them all, and update them all, or it can get one
in a particular index and could kind of,
whatever fits best to what we're doing.
Alright, so, that's my public API.
Now before I go and do my implementation over here,
you can see that I got this warning right here
and what's this warning saying,
it's saying there's actually three of them, you can click
on this little three by the way,
it's saying you have not implemented these [pause],
these three methods that you made public, so that,
that's a good warning.
I need to go do that.
But before I do that, I'm going to go back to my controller,
I want to show you how we're going to,
what kind of UI we're going to have over here so that
as we're doing our implementation, you can kind
of imagine how they're going to work together,
but I actually wouldn't necessarily have
to do the UI before I do the card matching game
and one could argue I should do the card matching game first
and not be influenced by the UI so much
when I'm designing my model.
Okay? But, you know, this model is going to be served by some UI
so we're going to do them at the same time
so you can imagine it a little better.
So what do we need for this UI?
Well one thing is we need a lot more cards, okay, this one card,
it can't be matched against anything else,
so let's make more cards, this is very easy to do.
I'm just going to move this card up into the corner here
and I'm just going to copy and paste it, so I can select it
and copy and paste, okay?
Place it, use the nice blue guidelines there.
I can even copy two and paste them.
Okay? Or copy four, and paste them.
Okay? So now I'm going to have 12 cards,
that's a good number of cards.
I actually don't need this flips thing anymore, I'm not going
to be just flipping cards, I'm going to be matching cards,
I'm probably going to need something for the score
which we'll do a little bit later.
But that's pretty much my entire UI, I'm just going
to have these cards and I'm going to click on them,
it's going to show a card and then I'm going,
I could either click on it again to turn it back facedown,
un-choose it, or I could click on another card
and if it matches I should get some points
and if it doesn't match, the other one,
the last one I had is going to flip facedown.
Okay? Now those of you who are used to a game
like Concentration, it's a little different,
usually you pick a card, then you pick another card,
and if they match you get points,
if they don't match they usually both turn back over, okay?
Which would be a cool UI, but I haven't taught you how
to do animation and that's what you would need there
because that second card, when it comes up, would need to be
on screen for a little bit before they both went
down because you got to at least get to see this one.
So since you don't have animation, when you click
on that second one, it's going
to facedown the previous one if they don't match.
Okay? And then you just keep clicking around trying
to find matches and you get points, and we'll show you,
kind of the point system that I'm going to use.
So this is my entire UI.
Very, it's a very content-central UI, right?
The UI is really focused on these cards, there's not a lot
of adornments and other stuff around it.
And we're really not going to have much other stuff except
for the score and you're going to add like a redeal button
and maybe a little bit of stuff about some status
about what's going on in your homework,
but this is the fundamental basis of the UI.
Okay? So now let's go back to our card matching game,
and let's talk about how we're going to implement this thing.
I'm going to go back to automatic here.
Get this thing back.
Just to make this look nicer, I'm going to go like that.
And I'm going to leave this header file up while we go
and do the implementation so you can kind of see
where we're shooting, this is what we're shooting for.
[Pause] So, the first thing I want
to do is make this be readwrite in my implementation only.
And I do that with this little, private interface,
remember I showed you about this, that you can have one
of these with the little open parentheses, close parentheses
like that, and now you can declare your own things.
Well, I'm going to redeclare this thing
to be nonatomic readwrite, NSInteger score.
Okay?
Now this readwrite, we don't use that very much
because it's the default, right?
Is chosen, remember the properties chosen
and match that are in card.
Those didn't say readwrite, but they had a setter and a getter.
Okay? They were readwrite.
We really only use this when we're trying
to redeclare a readonly one from public to private,
this is about the only time we really use this.
There are probably programming styles
where people put readwrite all the time,
even though it's the default, some people do that with strong
since strong is the default.
I like to specify strong everywhere just
so it's really clear what's going on in my mind.
But readwrite, not necessary for most things except for here
where we're redefining it.
So everyone understand what I'm doing here?
This is score, this is exactly the same score,
it's just that this says there's going to be a setter,
but I'm only going to be able to call that setter, at least not
without a compiler warning in my implementation.
Okay, because I declared the readwrite part here.
No public person is going to be able to set the score,
call set score, without compiler giving a warning.
Okay? So the next thing I want to do is I want to think
about my internal data structure for my card game, really simple,
it's just an array of cards.
Okay? I'm going to have an array of cards,
it's going to be this many cards, I'm going to pull them
out of this deck, and, people are going to be able
to choose those cards, someone can go look at the cards,
and we'll adjust the score as people choose the cards, okay?
So I need that internal data structure, it's internal,
so I'm going to put it here, nonatomic, strong.
It's going to be an NSMutableArray, okay?
And this is similar to what we had in deck.
Alright? And I always like to put of card just to say what's
in here because as we said, there's no way in objective-C
to kind of have the compiler enforce what's in here.
The things that are in this MutableArray are just objects.
And the compiler does not know what class they are.
Okay? So it's up to you to make sure you don't send messages
to things you pull out of it that are wrong.
So here, we are trying
to at least give the person reading our code know our
intent, our intent is for this to be an array of cards.
Okay? And, of course, we want our lazy instantiation.
[ Typing Sounds ]
Okay? So that's good.
So now we have this array of cards,
we can use it anytime we want.
Again, we could do this initialization
in the initializer, right, we can do this alloc init in here,
but I happen to like using the lazy instantiation, I think it,
it's kind of, makes the code
in our initializer look a little cleaner.
So let's do our initializer next though.
So I'm just going to copy and paste here.
You know, it probably not necessary to copy and paste
because if you just start typing this,
it's going stay [inaudible],
we'll do that with the other method just
to show you that one.
And then we all know that we do this weird thing here,
self equals super init [phonetic].
Now, this is our classes designated initializer,
in other words, you have to call this initializer
or our class will not be properly initialized,
we can have other initializers that could call this one, okay,
if there were ways to default things or whatever.
There is no way to do that, default it,
so this has to be our designated initializer, so,
I'm actually going to put a comment
in my public header file saying this is my
designated initializer.
That way if anyone ever subclassed my card matching
game, they would know that in their designating initializer,
they'd have to call super, our designated initializer.
Okay, that's the way designated initializers work.
You have to call your super designated initializer
from your designated initializer.
Question?
>> Does the compiler know that this is the.
>> Designated initializer?
No, the compiler does not know.
This is a purely commented thing, it's similar
to this kind of comment thing.
It's unfortunate that the compiler does not,
there's no key word or anything
that says this is my designated initializer.
You had a question first here?
Okay, question?
[ Inaudible Background Question ]
Well, followup with me, I don't understand the question.
If you have other initializers, I guess the,
your question is how do I disable another initializer?
[ Inaudible Background Question ]
Right. Oh, I see what you mean.
Yeah, you, okay, so the question is could I have another
initializer, designating initializer not be public
or something be private and have things call from it?
Yeah, you absolutely could do that,
although if you make your designating initializer not
public, than subclasses don't know about it
because there's no protected in objective-C,
so anything subclassers need has to be made public for them
to see it, it's still there, they can still subclass it, but,
you know, to document it you want it,
you have to put it in your public API.
So. Yeah, the whole thing with initializers
in objective-C is less
than nicely supported by the language.
Question?
[ Inaudible Background Question ]
Yeah, so the question is would it make sense here to,
for me to implement an init here, right?
To do something.
And actually it might well make sense to override an init,
and you know what you would do?
Return nil.
Okay? Because if you do card matching game alloc init
[phonetic], it's not properly initialized
and there's no default for the number of cards
or the deck, so return nil, okay?
So, yeah, so the answer is yeah you could.
Alright, so just back to our designating initializer,
we need to call our supers designating initializer,
which for NSObject is an init.
No arguments.
Okay? Then we just say if self, then we can initialize ourselves
and then we're going to return self.
And if anything goes wrong in here,
we will set self equal to nil.
Okay, and break out of this thing.
And, in fact, something is going to go in wrong
in here, as you will see.
Okay? So, what do we need to do to initialize our thing here?
Well, we need to pull this many cards out of this deck
and put it in our internal data structure here.
Alright? So how do we do that?
How about four int i equals 0 [pause], i is less than count,
5 plus, plus, so that's just me going
through this many of these things.
I'm going to say card star card equals deck, draw random cards,
so I'm drawing a random card of the deck,
and then I'm just going to say self dot cards,
sub i, equals card, okay?
So I've got this MutableArray, it's always going to be non-nil.
So this is perfectly fine.
Okay? There's one problem here though.
What if we run out of cards?
Okay? What if you pass a playing card deck here
and you say 100 cards for your game, okay?
This is going to eventually return nil.
Okay, and run out of cards.
So we should check here and say if card,
then we'll do what we normally do, otherwise, self equals nil,
break out of that four loop because we're dead.
Okay? Question?
[ Inaudible Background Question ]
So the question is how can I access cards here to set it,
in this line of code,
when I haven't put anything in the cards?
Well, card starts out as nil, and then when I call the getter,
self dot cards right here is the getter,
it's going to initialize it
to an empty array, but it's mutable.
So I can add objects here, Actually, oh I'm sorry.
You're right about that, yeah, well, this is fine too,
but maybe a better way to do this is to say self dot cards
at object card, because that's a little clearer.
In fact, you might be right, that wouldn't have worked.
So, this is a better way to do it,
we just add cards to the deck.
Okay? Make sense?
Sorry about that, I had a little different one.
[Pause] And actually I'm not sure if that would work,
let me think about that, so you're saying insert object,
yeah, that, actually that probably would work too.
Because you'd be doing insert object at index, it wouldn't be,
you know, it would be just at the end of the array,
that would probably work too.
So you could do it either way.
Because self dot cards sub i, that sub i thing,
it's really just calling a method, insert object
at substring index, that's what the method is calling.
You can look at the documentation
to see the name the method is calling there,
but if you insert object at index and it's at the end
of the array, I believe that'll work.
But if you do it at 500, that's not going to work, okay?
Because it can only grow the array as you go, I believe.
Question? [Inaudible background question]
So the question is can I put different kinds of objects
in the same array and the answer is absolutely.
You can and we do, occasionally, and we'll talk
about on Wednesday how you deal with that.
Right? How, how we manage the fact
that we have different kinds of objects in there, but yes,
absolutely, perfectly legal.
Okay? Alright.
So there's that.
And, again, as I said, we could probably say
at the beginning here, if self, we could also have an
if count is less than two, right?
Then return nil, we could do that, check that, as well.
Okay? Okay, let's do some of our other methods here.
How about choose card at index.
Okay? Actually let's do card at index.
Because card and index is super easy.
Right? This is card star, and notice if I start to type here,
it knows that its card index so it's going [inaudible] press tab
to get there, and this one it just returns self dot cards
of index.
But, you know, this is a public method.
What happens if someone passes a bad index there?
Right?
An index that's greater than the count.
Are we just going to go ahead and crash here?
One could argue that might be good,
because we'll help find the bug.
Certainly some kind of assertion in here would be good,
we'll talk about that later, but I'm actually just going
to protect myself against it by saying if self,
if this index is less than self dot cards count,
then I'll return.
Okay? Otherwise, oops, if, actually we'll do it this way,
use the old question mark.
Some people were asking about this, okay?
Return question mark nil,
everyone know this question mark colon c thing,
this is totally a c thing, nonobjective c thing, alright?
Just like an if then.
Yeah, question?
>> So [inaudible], how does array access with these methods
for the MutableArray to work without that index, if you,
or without the guard, if you pass the large index,
would it necessarily crash or would?
>> Yeah. So the question is,
what if I pass too large an index here, would this crash?
And it would, and what would happen is it would crash
with the exception array index out of bounds.
[Inaudible background question] No, no, it would crash, it,
raise an exception, array index out of bounds.
Okay? NSArray class would raise that exception, and we'll talk
about raising exceptions.
For now, until you go to this debugging thing,
maybe on Friday, for now, you're just going to see exceptions
like that happen on your console, it's not even going
to stop where the exception happened, which is unfortunate,
but that debugging session, we'll talk about how
to make it stop there, but that's what's going to happen,
it's going to raise an exception.
So that's carded index, really, really easy.
And now let's talk about this other one, choose carded index.
This is really the heart of our logic.
Because here's where you're choosing the cards,
here's where the matching actually has
to happen, in the scoring, okay?
So this is basically our entire logic is going
to be in this method.
So what do we need here?
Well, they're choosing a card,
so let's get the card they chose, and I'm going
to call self carded index, to get that card.
Okay, so now I have the card that they,
they're choosing here.
Now, if a card that they chose has already been matched
against another card, then I'm going to do nothing here.
I'm going to ignore when you try
to choose a card that's already been matched,
successfully matched with another card, so I'm just going
to say here, if card [pause] is matched, [pause]
and actually I'll just say if not card matched,
we'll do something, otherwise we'll just do nothing.
Okay? So I'm only going to match these cards if, or only going
to try and match two chosen cards
if the card you just chose is not already matched.
Okay? Does that make sense?
Does everyone see why we do that?
It's already matched, you can't match it against another one.
So now the question is if the card is already chosen,
then what am I going to do?
Then I'm actually going to flip the card back over,
un-choose it, so I'm going to say card dot is,
dot chosen, rather, equals no.
Okay? So if you'd pick the card that's already chosen
and you choose it again, it's going to un-choose it.
So it's kind of a toggle.
Choosing a card is kind of a toggle thing, on and off.
Notice that we have the getter is chosen,
remember we renamed it in our header file,
with that getter equals is chosen, but the setter, okay,
we don't use the is chosen.
The setter is still chosen.
Chosen is the name of the property.
Okay? Everyone remember that?
From card, hopefully, you had to type it in so remember it.
So otherwise we're in here and in this case,
we're choosing a new card and we need
to match it against other card.
Okay? Let's say another card.
Now our matching game only matches two cards.
In your homework, you have to extend this game
to match it to three cards, okay?
That's going to be part of your homework assignment,
but here we're only going to match one other card.
So all I need to do here is look through all the other cards
in my cards array up here, alright,
this is my internal data structure.
I just need to look through them all and find, and go and see
if there's another card that is chosen and not matched.
And if it is, I'm going to try to match it
against this card that was just chosen.
So to search, I'm just going to go through my cards,
for card other card, in self dot cards.
And we go through all the other cards,
and if I can find an other card that is chosen
and is not matched, [pause], okay?
Then bingo!
I found another card to try and match.
Now, there can only be one other one,
because I only do two card matches and I'm always looking
for that second match, so, if it doesn't match,
I'm going to flip that, un-choose that other one anyway.
So, I'm ready to go here,
I basically found the only other possible card that can match.
Now, again, when you do a three card match or an end-card match,
if you so choose in your homework,
which might be a good idea,
you might find a number of cards here.
You might have to collect them somehow in array or something
so you can match them against each other, but here,
I don't have to worry about that.
So I found this other card that's also chosen,
let's match them.
And I'm going to do that by saying match score equals
[pause] the card that we chose up here, right?
This is the one that the user is choosing.
Match colon, remember that's our method in card
that matches two cards.
It takes an array though, an array, so I'm going
to have make an array on the fly and put the other card in it.
Okay? Everyone understand this line of code?
I'm matching this card against this card using the match method
in card.
Okay? But I had to create this little array on the fly
because match is actually capable
of matching multiple cards, which is good
because your homework's going to require that.
But here I'm only doing one, so I just create this little,
blue at sign square brackets thing to create an array.
So now I've got this match.
Now, we've defined match, kind of the semantics of match,
are that if it returns non-zero,
then there was a match of some sort.
If it returns zero, no match.
Okay? That's what match colon means.
Okay, that's what we just defined it that way
in the semantics of our model.
Probably we should have put a comment in our card dot h
that says match colon, return zero if no match, otherwise,
how good a match it is basically.
So match should be returning high scores
if it's a really good match and a lower score
if it's not so good a match.
You know, that's kind of the semantics of it.
Alright, so, what if it is a match or it's not a match.
We have to deal with both of those cases.
Alright, so in the case that it is a match,
then let's give ourselves that score.
[Pause] Okay?
And, both these cards matched, so let's mark them both
as matched, so we're going to say card dot matched equals yes,
and the other card dot matched equals yes.
Alright? So they're matched,
they're out of the game, we got some points.
Now what if they don't match, well I told you
if they don't match, I'm going to turn that other chosen card,
I'm going to un-choose it, basically, so I'm going
to say other card dot chosen equals no.
Okay? And also, I think I'm going
to impose a penalty for doing this, okay?
I'm going to subtract something from the score,
I'm going to call it my mismatched penalty here
and I can make a constant.
Now, let's talk a little bit about constants.
You know, this is c. Okay?
So you're going to make these constants however you want.
One way to do it is to say pound sign defined, right?
So I could say pound sign defined, mismatched penalty.
And we can make the mismatched penalty be, you know,
the mismatched penalty, what did I decide, I think something
like two, so I'm going to take away two points if you mismatch,
so that's one way to do it.
Another way to do constants is const, okay,
its static const even.
Static const int mismatched penalty, if equals two.
Okay? So that's another way to do it.
This is kind of as you prefer.
The nice thing about these static const's is they're typed.
Right? Whereas a pound sign defined is not typed,
it's just substituting, okay?
But here you've got to type in and you'll be able to see this
in the debugger better.
Because it's typed.
But it's really kind of your own thing,
I would just say be consistent about what you choose
to pound sign define versus what you decide
to make a static const.
Okay? Totally up to you.
You know, the other thing I'm going to do here is
if you match, I actually,
since I'm basically charging you two points if you mismatch,
if you match I want to give you a lot of points,
so I'm actually going to give you a match bonus.
Match bonus.
Okay? And this is going to be another constant here.
Put this up here, actually let's copy and paste this over this,
paste, and I'm going to give you four times whatever your
matching is because I'm giving you this penalty so I want
to give you a bonus if you actually match.
So whatever the match score is, however good a match it is,
you're going to get four times as many points if you match.
Okay? And these are things that you would want to tweak
or maybe, like, possibly in your homework, you might even want
to make these be public API to set these bonuses and penalties.
Okay? Maybe that's something that wants to be settable,
but we're going to make them constants
for expediency in our game.
The other thing we can do here is if we find this match,
right here, we can break out of this four.
Okay? And that's because we're a two card matching game,
once we found a match, we're, we're done, okay?
We found another chosen card, we processed it, we don't need
to keep looking for matching cards.
Again, if you have, matching more than two
and you're collecting cards, you may not be breaking
out of this loop down here.
The other thing I wanted to do here is
if you are choosing the card and flipping it face up,
I want to make it cost something.
So I'm actually going to give, make a cost to choose,
and I'm going to make it be one point.
Okay, that's because I don't want you to be able to just,
you know, flip the card over, flip it back down,
flip the card over, flip it back down,
you'd eventually memorize all the cards and then flip them up
and get all your matches.
So it costs you a little bit.
If you forget a card and you flip it again,
it's going to cost you just a little bit, okay?
Not as bad as mismatching, but it's going to cost you a little.
Question? [Inaudible background comment] Oh yeah, you're right.
Good call.
See now I rely on all of you to make sure I don't make mistakes
like that, so yeah, absolutely.
This break needs to be inside this if because we only break
out of this four when we find another card.
Good, good call.
The last thing, of course,
is I want to mark this card as chosen.
And sorry for the apps there.
Okay? This card [pause], woops, not is chosen, chosen,
this card is chosen after we've done all of this thing.
In any case, it's going to be chosen,
it's going to be the new chosen card.
Okay? It might also be matched, but it's also chosen.
Okay? So, that's it, okay?
That's the entire logic of my card matching game.
It's pretty simple, it's kind of in a way ultra-simplified.
You can imagine much more complicated things, but,
you know, I'm doing this on the fly here and we only have,
you know, an hour and 15 for, for lecture, so,
I've kept it kind of intentionally simple,
but the main point I want you to understand
from this logic is it has no UI in it.
Right? It's purely just dealing with the cards and setting them
to be matched or not, whether they're chosen or not,
depending on using the match colon method,
which is also part of our model.
There's no UI here.
Okay? It's up to our controller
to take this logic and turn it into UI.
Alright? So let's take a look at that.
I'm going to go back
to our storyboard here and make more space.
Move this over a little.
Give me more space.
Okay. So, here's our controller, right?
Our simple controller just as we had left it off,
and I need to use this logic in this thing.
So the first thing I'm going to do is create a property
to hold my card matching game.
Okay? Now, one could argue, some people would call this model,
I don't like that so much,
because sometimes a model will expand multiple properties
or they might call it game model, okay?
That's not so bad.
I'm okay with that.
I like game, I think it reads a little nicer in the code, but,
it's kind of a matter of personal preference,
but in any case, I need
to import my card matching game header file here,
to make this work, and I'm going to lazily instantiate it.
[Pause] I'm just going to say if the game is nil, in other words,
just our object is freshly initialized, then I'm going
to say game equals card matching game alloc, woops, game alloc,
and then init [phonetic], okay there's two inits there,
the one inherited from NSObject which we know is going
to return nil so I don't want that one,
and init with card count.
Okay? So I'm going to do that one, tab over here,
how many cards are in this game?
Well there's 12.
So I should type 12 here right?
[Speaker makes noise] Okay, no.
That's like putting a 102 in your homework solution, right?
We might add more cards someday,
we absolutely do not want 12 here, so I'm going to put 0 here
for now, and we'll, I'll show you how we're going to figure
out what this number is.
And using deck, luckily I have self-create deck,
that's why I did that that way.
That's going to create my, my deck.
Okay? Then we'll return underbar game and it's nice
and lazily initialized.
Okay? Alright, so let's talk about this zero right there.
How are we going to find out how many cards there are?
Well it turns out it's possible to create an outlet
to multiple things in your UI.
Remember that we have this outlet right here flips label,
which was an outlet that went to this little flip count thing,
that we had down here.
It was a single outlet, which by the way,
we can delete this single outlet.
But it went to one object, the UI label, so let's get rid
of that, and we don't need to put county there,
we actually don't need deck either, there's lots
of stuff we can get rid of now.
Alright, so we're going to redo this whole thing, [inaudible].
We'll get rid of that in a second.
You can see our games gotten significantly simpler now
that the model's taking care of a lot of our stuff here
and it's going to get even simpler when we delete all this.
But anyway, that was a single outlet.
We can actually create an outlet to multiple things,
and as you might imagine, that outlet will be an array.
Okay? So how we do that?
Very simple.
Exact same way, I'm holding down the control key, okay?
Pick the card here, I'm going to hold down control and drag
into my interface, just like I do
with any other outlet I'm trying to create, and when I let go,
you can see that at the top here where it says connection,
there's actually the choice of making an outlet collection.
So that's an array of things.
Okay? We can also make an action messenger,
we'd be declaring it here.
Or an outlet to a single button, but here I'm going
to do an outlet collection, when you do outlet collection, XCode,
not objective-C, but XCode wants to know what kind of objects are
in there, that's purely for XCode, there's,
I told you there's no way to know what's in an array
in objective-C and the compiler can't know that,
so this is purely for XCode and you're going
to see how XCode remembers this answer in a second,
and here's the name, I'm going to call it card buttons,
that's what these are, these are buttons
that are holding all the cards.
Notice it's not asking me strong or weak here.
That's because this property has to be strong.
Okay? And it has to be strong
because while the view has a strong pointer
to all these cards individually,
the view does not have a strong pointer to this array.
And if we did not make this strong,
than this would be constantly being set to zero
because no one would have a strong pointer to it.
Okay? So, that's why this has to be strong,
because it's an array, it's not a button.
Now, this little stuff right here,
compiler completely ignores this, it's very much
like IB action, it's just some stuff that XCode puts in there
so that it knows that this particular property right here
is an outlet collection, and you can see if I mouse
over this it shows me the one button that I put in here.
Now, I'd love to tell you we can just select all of these
and control drag, but you can't, okay?
I've been asking for that feature for years,
but they never give it to me.
So, I have to drag these one-by-one,
it's kind of unfortunate, but at least, you know,
I drag it to the thing that's already existing, and you notice
as I get close, it highlights the thing
that is appropriate and, again,
it knows that because it knows this an outlet collection
of buttons, so that's why I can highlight this property.
Okay? So I'm going to collect all of them here,
and when you do this, you know, it's somewhat error prone,
you might miss, so it's nice to go back here and check,
and you can see all 12 buttons in here.
Question? [Inaudible background question] Okay.
Great question!
The question is does the order matter?
Or is the order determined?
And the answer is no.
This order, the order
of the object mirror is completely unknown to you,
and you cannot depend on it.
If you need the order, you're going to have
to do this a different way.
Outlet collections are fundamentally,
the order is not known.
Okay? So no matter what order I control drag them,
that's not going to be the order in the array.
Okay? Which was a good decision by Apple, it seems like oh,
it'd be cool, but it'd be just too hard for them to,
to throw a lot of things in here, it'd be too hard to show
and you could get confused, so, you need to use something,
a different mechanism, and you're going
to learn many mechanisms later in this class
that you could do this with.
This is just a pretty simple one right here.
For a fairly small numbers of things.
So anyway, we got this connection to these things.
So now we can do card count.
Okay? We know the number of cards,
we can just say self dot card buttons,
that's this property right here, alright?
Count. Okay?
So this is the number of buttons that's in this array.
Okay? So that was good.
That worked out well for us.
Okay? Now we also have a nice array of these buttons
so that we can update them
with what's happening in the model, okay?
So, first though, let's talk about touching a card,
when you touch on a card, what are we going to do,
well we don't want to do any of this junk.
Okay? So we're just going to rid of all of that.
Okay? Because we're going to let the model handle it.
So all we need to do to let the model handle this is
to get the card that this button is associated with,
because these buttons are all still sending this,
if you look at this, see all 12 of them are sending this action
and the sender is still the actual button you touched on,
not the array, but the actual button,
because this is the target action thing right here.
So, we can still find out who sending it and, in fact,
we can even find out it's index in this array
by saying card index equals self dot card buttons,
index of object, sender, okay?
So this is going to tell us
where this sending button is in this array.
Okay? So now that we know which card it is in the array,
we can just tell our game please choose the card at that index.
[Pause] Okay?
And we're just going to tell our model, hey, choose that card.
Now, one thing here though is choosing
that card might change the state of the game.
Okay? It might cause some points or match some cards,
a lot of things can change, so we're going
to put a little update UI here, okay?
And this update UI method, which we're going to have
to write has got to keep our UI in sync with the model.
And remember that's one
of the primary things a controller does,
it syncs up the model with the UI.
Okay? So let's go ahead and put a little thing here.
Update UI.
Okay. So what do we need to do when we're updating this UI?
It's actually pretty simple, we're just going to go
through all the card buttons, okay?
Get that card button, simultaneously look
into the model for that card,
and make sure the card button is showing what should be
on that card.
So, let's go four UI button, card button,
in our card buttons, okay?
So we're iterating through all these buttons.
Card button is going to be the variable.
Let's go ahead and get that card index, again, for,
for the same thing, self dot card buttons, index of object,
the card button that is our iteration variable
and we're cool with what we're doing there.
Alright? So we're just figuring out which card it is.
Then we're going to ask our model, give us the card
at that index, using card at index.
[Pause] Okay?
So now we have the card button and the card, awesome.
Now we can make sure the card button reflects the card
that goes along with it.
Okay? So, what do we need to set on the button?
Well, let's see, we have to set the card buttons title, okay?
So set title for state UI control state,
control state normal.
Okay? And we have to set the background image, right?
Depending on whether it's the Stanford logo
or the blank background.
Okay? Also, if the card is matched,
I'm going to disable the button.
Okay? Because you've already matched this card,
you can't click on it anyway, so I'm going to disable it
because a disabled button looks a little different
and I want buttons that are matched to look different.
Yeah?
>> [Inaudible] card buttons, does that go from 0 to N?
>> It does.
So the question is does a fast enumeration like this,
when you do this four N thing, does that go from the zero
to the N and the answer, it does.
It does go in order.
[Inaudible background comment] You could.
So the question is do you, do you not need this,
you could just have another iteration variable
or you could use an iteration variable here,
like four i equals 0 to the length?
You could.
I don't like to depend on that going from 0 to whatever,
so that's why I used this here.
It's a matter of style.
Totally a matter of style.
This is also kind of a little clearer,
because here I'm saying I want the card that goes with,
you know, the card button that goes with this thing.
So, so the last thing I'm going
to say is the card button enabled equals the card,
not card is matched.
Okay? So, the card, the button will only be enabled
if the card is not matched.
Okay, now of course I have these two things,
which I haven't [laughing] provided, right?
I've just left them, we don't have that argument.
And actually for both of those,
I'm going to create little other methods here, helper methods.
So, I'm going, for the title,
I'm going to have a helper method called title for card.
It's going to take a card as the argument.
And it's going to return the title of that card,
and for the background I'm going to have UI image,
background image for card.
[Pause] Hopefully as we'll go along you'll start
to see the naming conventions that we use.
We often try to have this last part of a name
of a method before a colon indicate what we're looking for.
So here we're looking for a card, so we try to make a thing.
Look at this one, button, right?
This is a button.
So we try to make these arguments guide the reader
towards what we're asking for there.
We don't want to get too overwrought about it,
but it's a general naming convention there.
So, what is the title of a given card?
So I have the card, what's its title?
Well, if the card is chosen, then I'm going
to return the contents of the card.
If it's not, I'm going to return empty string or nil,
so I'm just going to say return card dot is chosen,
question mark, car dot contents, otherwise,
empty string let's say or nil, either one in this case.
And how about the background image?
This is kind of a cool one, I'm going to say return to UI image,
image name is card dot is chosen,
so if the card is chosen, then I want the card front,
otherwise the card back, now you probably think I'm just in love
with this question mark colon [pause] syntax,
which I do like it a lot, it's kind of clean.
But anyway, you understand what I'm doing here, right?
I'm actually having the name in here
with the question mark colon nested inside,
[inaudible] to get the, the image.
Okay? So now, I can use that here.
Let's do the title first.
I'm just going to self, title for card, the card,
and then here I'm going to say self background image for card,
card, and both of these I'm going to hit return just
to make this a little easier to see.
Okay? So, that's pretty much it.
Okay? I've matched up my UI with my model, when I touch
in the UI I let my model know to choose a card
and we're pretty much good to go.
I think that's all I had to show, yeah, we'll,
we'll do the score in a second here.
We need to score, but before we do the score, let's go ahead
and run this and make sure that it's working.
Okay, so when I click, hopefully I get a random card,
and when I click again, hopefully it continues
to be the same card, okay?
It'd be bad if that was constantly getting random card,
but we know that we got rid of that code
so it's not going to do that.
So there's a king, five, two, okay,
now we got two clubs right here.
So I could do that, oh, didn't match.
Okay? So why don't these match?
They should match.
And the answer, anyone want to tell me?
Yeah? [Inaudible background comment] Absolutely.
The only match function we have is this really bad match
function, let's go look at it.
It's right here in card, okay, this is the only match function
that exists in our entire application
and it only says it's a match if both cards are identical,
well that's never going to be true in our thing,
because we have a deck of 52 cards,
every single one is different.
So it's never going to match.
So how do we deal with this?
Well we need to teach playing card how to be a better matcher.
Okay? Because cards implementation
of match is simply not sufficient.
So what we're going to do is we're going to override this,
we use object-oriented programming,
that's what we're here for, so we're going to override it.
Let's go to playing card, here's playing card.
Now, notice the playing card doesn't declare match
in its public API.
Okay? It inherits it from card and I'm not going
to redeclare it just because I'm going to implement it.
So I am going to go here and I'm going to re-implement match.
Okay? It knows that match is method I inherit,
that's why it was able to escape, complete it like that.
But I'm not going to put it in my public API
and that's generally the way we do it.
Okay? Generally, if you inherit a method and you,
a public method, and you override it, you don't have
to put it in your header again.
Some stylistically would say, yes, put it in there,
so that someone knows that you override it.
But most object-oriented people would say you shouldn't have
to know that you override it.
Alright? This is object-oriented programming.
You should not have to know that.
That, that's implementation detail that you happen
to override match here.
So, I'm a fan of the not putting match in playing card,
it's already in playing cards public API
because it inherits it from card.
Alright, so what are we going to do in match?
Well, I'm going to have a really dumb match.
You're going to need a better one for your homework.
My dumb match only can match one other cards.
Okay? So and the first thing I'm going to say here,
let's go ahead and do in score equals zero and return score.
The first thing I'm going to say is
if other cards count [pause] equals one.
Okay? So I'm only going to match one other card.
Okay? If there's two cards in there, no match.
Okay? Too, too much for me.
So I'm just going to say this one thing.
Now, I need that other card though,
how do I get the other card?
I'm going to say card star other, in fact,
I'm going to say playing card star other card equals,
and I could do a lot of things here.
I could say other cards subzero, but I'm actually going
to use a method here I want you to know called first object.
Other cards, first object.
Okay, first object returns the first object in an array.
If the array is empty, it returns nil.
Okay? That's different than saying other cards subzero.
Because if that array is empty, that will crash.
That will say array index out of bounds.
You see the difference?
First object, there's also a last object,
they just have this magic piece to them
that they don't do array index out of bounds.
Okay?? But otherwise they return the first object or nil
if there are no objects in there.
Okay?
I just want you to know that.
I don't actually need that here,
because I know there's one object in that array.
So this is not really necessary, I could say other card subzero,
I'd be okay here, but I'm just trying
to teach you the method first object, that's all.
So I got this other card.
So let's go ahead and match it, what's a good match here?
Well, if the suits match, I'll give a little bit of points,
but if the ranks match, I'm going to give a lot of points,
so, let's say if my [pause] self dot suit is equal
to string the other card's suit.
Okay? So the suits match, they're both clubs.
Then I'm going to say the score equals one, okay?
But, and we can say else or not, because we're going
to assume the cards are all different.
So if the cards are the same, then you're only going
to get a suit match, which doesn't really make sense,
but let's say if self dot rank, oops, we don't need
to send a message there if self dot rank equals the other cards
rank, then let's give four points.
Now why do I give four versus one?
Well, think of the math, right?
If you have a club in your hand, how many other cards are there
in a full deck that will match a club?
12. Okay? If I have a king, how many other kings are there?
Three. Okay?
So 12 versus 3, it's four times easier to match that club,
assuming you have a full deck.
I'm just picking numbers kind of at random here.
It's, it's not a bad choice for the scoring here,
but most times trying to get these relative scoring right.
Question? [Inaudible background question] Yeah,
so the question is am I using magic numbering and absolutely.
And you probably, you know, this whole thing
of the scoring here is somewhat magic numbers
in our simple implementation, you probably, although,
[pause] this, okay, this is not necessarily a magic number.
If you define match to say make the easiest match verse, verse,
equal one, and then make any more difficult matches
to be multiplicatively, you know, more difficult like this,
than this is actually right, because that four is fundamental
to a playing card, it's fundamental
to how a playing card ranks and suits work, alright?
So, assuming you define this match only match
against other playing cards in this same deck,
that four is magic, but it's magic to this class.
So, yeah, you could put a pound sign define,
but that doesn't make it any less of a magic number.
So it is magic, but you could put it in there.
You see what I'm saying, see the difference between that
and like 102 in your controller, which is trying to be, you know,
maybe generic decks, that's a little different.
Good question though.
Alright, so now we have a better match.
So now if we go back to our controller, so let's do that.
Just [inaudible] on screen right here.
And run. [Pause] Hopefully now,
let's see if we can find a match.
Okay, so there's a club, right, and this is a club
so let's match them, ready?
Oh! It matched!
And it even disabled them.
Okay? But I have no idea how many points I got
because there's no score on here, so, obviously,
we need a score, so let's put the score in.
Hopefully by now you can imagine easily how we would do the
score, simple, just like flips, we just grab a label here
and then drop it down in here, I'm going to say score zero,
because that's what I wanted, oops, that's what I wanted
to say when we start up.
And yes, it's possible you could load these strings
up at start up, we'll talk about when and where to do
that in your code in the next couple lectures.
So I have this score, I obviously need to be able
to talk to it, so I control drag up here
into my interface to create an outlet.
I let go, this one wants to be an outlet,
not an outlet collection, but an outlet.
I'm going to call it score label, okay?
It can be weak because we know that the view is going
to point it, it is the UI label.
There's an outlet for it.
I'm just going to update it in update UI.
So I'm going to say self dot score label equals NSString,
string with format, we'll say score colon percent d,
and where do we get the score?
[Pause] Anyone know where we get the score?
From the game, exactly!
From our model, self dot game dot score.
Okay? Now I'm going to go show that just
to make sure everyone understands that.
Here's my card matching game,
remember that in its public API, it has the score.
Okay? And we're keeping the score when we're choosing.
Okay? Everybody cool with that?
So that's it.
That's all we need to do here, to update the score.
Normally we have, oops, this needs score label dot text.
Sorry. Alright, we need the text property of the UI label class
and we're calling it setter here, set text,
this is basically what's happening here
and setting the score.
Okay? One other thing I'm going to do just
in case the score is really big, so make that wide, and run.
And we'll talk about, by the way, text fields that get larger
when you put text in them and stuff like that, there's a way
to handle that in iOS, as well, we're not, we can't talk
about it, everything all at once though.
Alright, so let's see here.
Minus one.
Why did I get minus one?
Because I have a cost to flip.
So every time I flip a card, I got to pay, alright?
Now here's a spade and here's a spade, alright?
So what's going to be my score after I click this?
Well, clicking this still going to cost me one, so that's going
to make my score go down to minus six, but I'm going
to get one point for matching times my match bonus
of four, is four more points.
So my score should be minus two.
Alright? And it is!
Woohoo. Okay, and let's see if we can find ranks that match.
[Pause] Oh, there's a six and here's a six.
Okay, so I'm going to make these two match,
so what's this going to be?
Alright, so we're at minus 9 now, when I click this one,
we're going to be at minus 10, but they're going to match.
I'm going to get four points
for the match times my match bonus of four is 16 points.
So I'm going to be at plus 6.
Everyone agree with that?
And there we are, score plus six.
Okay? Alright, so that's it.
That's as much as I'm going to do and I'm,
we got some slides here at the end,
but that's it on the demo here.
And your assignment is going to be to make it
so you can match two cards or three cards,
you can have a little switch or some sort of UI to choose
between whether you're matching two cards or three cards,
and so that's going to require some change
to your logic in your model.
It's going to require a little bit of UI and it's going
to require your controller to do a little bit
of glue in between that.
You're also going to be asked to add another label in here
that says what's going on.
So when I click this, it should say you chose the seven
of hearts.
When I choose this, it should say seven hearts and two
of clubs did not match, minus 2, or something like that.
Okay? So, if you pick two things that do match, like,
[pause] those two hearts, it should say four of hearts,
seven of hearts match for whatever points.
Question?
>> How would you test your program on a device?
>> How would you test it on a device?
Okay, let's run this on a device actually.
Great question.
So I have a device attached over here, which you can see,
and it's asking me to update, which we're not going
to do right now, and if you look up at the top of XCode,
you'll see that there's a bunch
of different simulators you can run on and you can also run
on a device if you have it attached, and we're going
to have a Friday section probably next week,
or maybe the week after, where we're going to show you how
to register your device if you don't know how to do that
and get this all set up.
So this is a bit of a preview, but I'm going
to actually run this on the iPad.
So I just pick iPad, and hit Run, and it runs on the iPad.
And I'm going to start doing this for most of the demos,
is running it on a device instead
of running it in the simulator.
It's a little nicer because the screens a bit, little bigger
as you can see, and so here it is on my iPad here.
And so I can tap and oop, it crashes.
Oh, well, that's not good.
What did I do wrong here?
Well, I don't know what I did wrong, but I messed it
up when I preset this up so I'm sorry about that,
but I will show you that,
I'll start running all my demos hopefully on a device starting
with next Wednesday's thing
and hopefully I won't make this mistake, sorry about that.
Anyway, okay, so that's it.
Any other questions about it?
>> For more, please visit us at stanford.edu.