=
[ 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.
