[Walkthrough] [Problem Set 3]
[Zamyla Chan] [Harvard University]
[This is CS50.] [CS50.TV]
All right, welcome everyone to Walkthrough 3.
Pset 3 is a really fun one.
It's a new one to CS50 called Scramble,
so if you've ever played Scramble or the similar board game Boggle
essentially it's a game where you have a grid of letters, 
and in the time allotted you need to find as many
2-letter or longer words that exist on the board,
and so there are certain rules such as you can only use one letter
in the grid, one block in the grid once, and you can't go back to it.
You can only construct letters by linking together the adjacent letters,
so this is going to be a really fun pset, so let's look at our toolbox.
Again, the appliance is still being updated, so make sure
every time you enter the appliance to right open your terminal window
and in the terminals do the command sudo yum -y update.
This is important also if you want to be able to
 run the staff solutions, which we definitely recommend.
Sometimes it's good once you've finished your code
to test it against the staff solution, make sure that everything
you enter into the staff solution, whatever comes out there,
same thing that happens with your code.
All right, so make sure to update your appliance.
Now, also, since we're dealing with a grid in this case
we're actually going to be delving into 2-dimensional arrays.
We've dealt with 1-dimensional arrays, 
but now we're going to extend them so that they have
multiple rows as well as multiple columns.
Then we're going to definitely be using functions in this pset,
basically calling a function, sending some parameters out
and then getting a return value back.
And in Scramble we're not asking you to actually make the whole thing from scratch,
but rather, we're actually giving you something called distribution code,
so code functions that we've already written that kind of lays out 
the skeleton of the pset as well as implements some of the tougher things
that you'll definitely be able to read over and understand
but don't need to quite make it yet.
To quickly rehash over the 1-dimensional arrays.
Arrays are data structures that hold multiple values of the same type, 
and as a reminder, these arrays are zero-indexed,
so most of you are probably familiar with an array such as this.
If we wanted an int array with length 3,
then we could initialize it by having int values 
and then the square brackets indicating the length of it,
and then we would assign values to the specific elements within that array.
Here we have an int array with the first index at index 0, 2,
index 1 is 4, index 2 is 6.
Say we wanted a larger array and to hold multiple values.
Then we could have a 2D array.
Now, this is very similar to our 1-dimensional array.
It's 0 indexed, so that means that the first column
is indexed at 0.
The next one is at 1, and then the next one is at 2,
and then similarly we have rows, and so you see that when we
declare our array we also—just like before—we indicated the size of the array.
We also similarly indicate the size where the first bracket
indicates how many rows  you have, and the second one indicates
how many columns.
All right, in this pset you'll want to be able to 
iterate over the 2D array, be able to access every element 
in this 2D array, so essentially you want to reach
all possible combinations of the row and column values.
We want to reach row 0 at column 1, 2, and 3.
We want to reach row 1 at column 0, 1 and 2.
We have to have some kind of structure that allows us to 
iterate over all of the rows and all of the combinations
of columns within that.
Here I have a 2D int array.
It has 3 rows and 3 columns,
and so this is the quick way to 
find the whole 2D array.
I'm saying the first row is going to have 2, 4, and 6, 
kind of similar to the previous example in this slide.
Then I'm going to have the 2nd row be 3, 6, 9,
and then the 3rd row is 4, 8, 12.
We have our 2D array,
and we know that it looks like this.
We have 2, 4, 6,
3, 6, 9, 
4, 8, 12.
Now if we add in the indices,
this would be row 0.
This would be row 1.
This would be row 2.
Similarly we have column 0,
column 1, and column 2.
Yes.
[Male] Which three are the column, and which one is the row?
The columns are these ones, 
so your columns are these ones.
This is column 0, and this is column 1.
This is column 2.
[Male] How many in the declaration of int to table [3] [3]?
When you're declaring the 2D array then the first number in the square brackets
is going to be how many rows you have,
and then the second one is going to be how many columns.
Great, so we want some kind of structure,
some kind of loop that's going to give us every possible combination.
Say we start by saying—okay, to access anything in this row—
let's just look at this row for now.
These are rows here.
We know that our row index is going to be 0,
but to access this element it's at the 0th row and the 0th column,
so then we would access it by the index of [0] [0].
Then this one, similarly, is still on the first row,
but it's on the second column, so we access that by [0] [1].
Then the last one would be [0] [2].
Whenever we're at a specific row we're going to want to
iterate over all of the possible column values.
Let's start with a for loop
that starts at 0, and goes to the length of how many rows we have.
This is cycling through every row.
Then what we want to do is within that, 
whenever we're at a specific row we want to cycle through all of the available columns,
so then we'll have another loop.
Let's call it j.
I, j and k are very common row indexing loop variables,
so you can use these if you like.
Also try to avoid then—if these variables are commonly used in loops
try to avoid using them like as variable names for other things in your code
just because it's common convention to use i, j, and k within the loop or indices.
Okay, then here we have a for loop that iterates over all of the rows.
Then every time that it's at a different row
we'll iterate over all of the different columns.
This way we can actually get to every possible combination
of 0, 1, and 2 with 0, 1, and 2.
That make sense?
This way we're able to access over every value.
Now, we could have chosen to do columns first as well.
It really doesn't matter as long as you iterate through 
all of the columns and all of the rows.
Now let's do something with these values.
Let's say print.
Now let's print their integers
and then the variable at that place is the—it's going to be a value n table.
Now the specific row index would be i because we used that to iterate through our rows,
and then j to iterate through our columns.
Now let's make 2D.
Now when we run 2D it prints out all of the values 
in the order that we specified above, 
so you see that it goes through all the rows first,
so it's at row 0, and then it prints all of the values within that row
and then continues.
That's an example of a way that you would iterate over
and conduct actions on values within a 2D array.
Great, now, what we'll see in the distribution code are many functions,
and so some of these functions will be boolean functions
where they return a boolean to you.
Some will be integers, for instance, and so essentially to
review functions a little bit basically functions have
a return value, a name, with which you use to call the program,
and then they can have any number of parameters.
Essentially when you call the function within the next function,
basically like you're saying now I want you to execute this function,
you have to pass in certain values, so in this case our function foo
would have to take 2 integers, and within that function then
it would be able to access them, refer to them as x and y.
A similar example is lower functions
that you may have used in your crypto program,
and so essentially those functions were already written for you,
but depending on their return type you could use them within the functions.
Say you have a boolean function called foo.
Then you could use that because you know that it will represent a boolean.
Essentially when you call it, it will return back a boolean,
so you can treat that as this will represent a boolean.
Within your condition you can simply say 
if foo, and then you pass in its required parameters,
5 and 9 for instance, 2 integers,
then you know that that will return either true or false,
and so then you can use that as your condition itself.
Similarly you could also say foo(5, 9) == true
or == false or something like that,
but that is slightly unnecessary as the function itself
already values to either true or false.
We're going to keep this in mind when we see some examples in the distribution code.
Okay, back to Scramble after we have 2D arrays
and understanding functions under our belts.
In Scramble essentially you're going to have a grid of letters,
and then you're going to help implement a program
whereby the user can input different letters that they see on the grid,
so that also means that you're also going to have to draw the game board. 
Then the user will be inputting certain words, 
but you have to check, A, whether those words are valid in the dictionary,
or B, whether they actually exist in the board, can be found in the board.
Then in the distribution code we'll go over that in a second.
You'll see what's already made for you, 
and then within the given structure of the distribution code add the functions.
There are certain functions that are left empty.
There are certain functions that you just have to add to.
A certain function that you're going to be working with is draw,
so you have to implement the draw function, 
actually drawing all of the letters on the board.
You're going to have to implement the lookup function whereby you have to check
whether the string that the user inputted is a valid word,
and so then as I mentioned before, that includes whether that's in the dictionary or not
as well as whether it's a valid game move.
Then you're going to implement Scramble
where in the game if the user is, for instance, having trouble finding any word
then if they type in "Scramble" into the prompt
then the game board actually rotates 90°, 
keeping the same letters but just rotating  90° clockwise.
And then finally we're going to deal with case and sensitivity,
essentially when all of the words in the dictionary included in the distribution code
are all stored as uppercase, but we want to allow the user, for instance,
if they enter in a mixture of lowercase and uppercase
or just lowercase letters then if that word is valid
then they should be able to get points for that as well.
Okay, so distribution code, it might be a little tough to get through at first.
You might not want to read all of it and just get straight to
writing your program, but please do read it once,
read it twice, read it thrice, read it over and over again
so that you have a good sense and can feel really comfortable
with the code, even though you didn't write these functions yourself,
that you kind of know what they're doing and you can expect 
the way that they might interact with the functions that you will implement.
Without further ado, let's actually get into this distribution code,
and I'll help you guys make sense of it.
I've already downloaded the distribution code.
You can do this.
There's instructions in the spec where you have to make your own directory for pset 3,
and then if you execute a command that's found in the spec
then you'll be able to download the words file, 
which contains basically the dictionary file, if we just look at that quickly.
This essentially contains a whole list of words that are going to be our dictionary.
Okay, let's start at the top.
Also here you'll notice that the good style of this distribution code
is to our benefit because we can see comments
that explain how the code is being used.
We have this, including our libraries.
Notice that here we have #include ,
and so that library allows us to keep track of time because 
in Scramble you have to essentially enter in as many words as possible
within a given time frame.
Here we have some variables.
The duration of the game we've set it to be 30 seconds.
We say that the dimension of the grid—it's a square grid—
is going to be 4 x 4.
We say that there are words, a number of words in the dictionary,
that anywhere can only have a maximum of 29 letters.
Then here there's a file called log.
Essentially we're going to be automating some of the results from your code,
so try not to alter anything to do with log because we'll be dealing with that.
You don't have to quite understand that yet,
but just try not to alter anything to do with log.
Notice that here this variable grid, which is a 2D array of characters, 
is declared outside of our main function,
so this is what we call a global variable.
Because we're dealing with a game here, 
if you recall all the way back to scratch
when we had something like a score, for instance,
when we were dealing with a game, that had to be accessible to
a lot of the various scripts, so similarly, we have this variable
that needs to be accessible to a lot of the functions in our program,
so grid here is a 2-dimensional array that will store
the letters in the Scramble game.
Later on we'll see the use of this later,
but then we also have a 2D array of booleans called marks,
and so essentially when we go into checking whether a word
is valid or not we need to know whether we've been visited a certain block,
visited a certain letter, and so then marks basically is going to 
contain either true or false at a given index,
so it will let us know whether we've been there before, 
whether we've visited that letter during our certain check,
and so marks, as you'll see later on, 
will essentially exactly mirror the grid.
Here we decided that we wanted our own data type.
We weren't happy with just string.
We actually wanted something called a word,
so we have this typedef struct here,
and then within it it has a boolean called found,
so whether this word has been found or not.
Then it has an array of characters, 
essentially the actual word that it is.
Now then, word is an actual new data type that we've made,
so we can have an array of words, for instance,
or we can make a new word and have multiple instances of them.
But we only have one dictionary, and so that's why we only have a
struct call a dictionary as opposed to a typedef struct.
The struct has an integer with the size of the dictionary
as well as an array of words, and again, 
we use this global variable words, which is defined above,
to be the number of words that's actually in our dictionary.
Here we have a whole list of prototypes, function prototypes,
essentially saying, okay, now you can expect to have
all of these functions later on in the program.
I'm going to have a void function called clear,
a boolean function called crawl that takes in 
a string and then 2 integers, et cetera, so you see these here.
Also a nice feature in gedit is that along the side here
if you make sure that you selected this functions tab here, 
the source code tab, then it will actually show you all of the functions
that you have in your program.
It will show you several things that you can use.
For instance, here it has that you've defined a new data type called word
and then the certain global variables that you have.
But this functions tab is quite useful because you can click back and forth
and jump to the specific points in your program.
All right, we're at the main function now.
When the user enters in the command,
basically they can either say ./scramble,
or they can also enter in a number after that to basically indicate
which board they want to play with.
Usually whenever you only enter in one command line argument
then it's just going to give you a random board, but say for debugging purposes
you want to make sure that you just check the same board over and over again
then what you can do is just say ./scramble1, for instance,
and it will always give you the same board.
Here it's ensuring the proper usage,
so if the user enters in more than 2 command line arguments,
then it will instruct them on how to properly use the program
and then exit.
Here if argc is 2, that means if the user has inputted a number
of the specific word that they want to use then 
essentially when the program later on makes a random board
then we essentially are giving it a seed, kind of like forcing it
to use a certain value.
Then here we load our words file.
Basically if it can't open the dictionary, if something goes wrong,
then it will return 1.
We initialize the grid. We'll look into that function later.
We set the score to 0.
We calculate when the game will end, 
so that's 30 seconds, as we set.
Then here, again, is the log file, which you don't need to alter.
Here's the meat of the program where we have a while (true) loop,
so notice that if you just have a while (true) loop by itself
then it will just keep on executing whatever is in its body,
but as you'll see later on, we actually have a break
so we actually allow it—we have some way of it actually breaking out
of the function and not executing forever.
First what happens is the screen will clear
so that you can draw a new board, and then it will have the function called draw.
Again, it will log it, so essentially every time that it goes through this loop
it will report the score to you.
Check whether the game should be ending,
whether you're out of time or not, and then report how much time you have left
if the game is still in play.
Then here we have a prompt for a word, 
and then we have the GetString function,
so that's where the user actually inputs a word for you.
Then essentially if they've actually entered a word, if it's not null,
then the program will log it.
Then you want to check whether you need to scramble the grid,
so basically if they enter in the command scramble, the word scramble,
then it's going to rotate 90°.
Then otherwise if it's not the word scramble
then what you want to do is you'll want to look for the word.
The (find(word) is true. We'll go into that function later.
And then you'll want to look it up, so basically is it on the grid,
and is it in the dictionary?
And if it is the case, then it will increase your score by the number of letters
that that word is.
That's our main function there.
This here is essentially like an escape code,
so you don't need to worry about that quite so much,
but essentially whenever you call the clear it will clear the terminal
and move the cursor back and kind of erase whatever it had written before.
Let's not go to crawl quite just yet.
Instead we'll scroll down and see the draw function here,
which is your job TODO.
Essentially you have to print the grid in its current state,
so we've already taken care of actually initializing the grid,
and so you don't need to worry about which letters to put in the grid
or something like that, but in the draw function you're going to want to
print out whatever is in the grid.
Then here we have a boolean function called find, 
which we saw above in the main function.
If the word was found and also was looked up in the dictionary,
if both of those returned true, then it would increase the score.
Here is the find function where it takes in the word as a string,
and it has to be 2 or more characters,
and then what this does is it searches the grid for that word.
Here we see an example of iterating over every element in the grid
where they iterate over the rows and then within that iterate over the columns.
Here remember the marks 2D array that basically stores either true or false
whether we've been to that letter already.
Essentially this resets all of the marks because we're only dealing with marks
every time that we're checking a specific word.
Then here once we've reset all the marks
it actually searches for the word, and so to search for the word
that's where we use the crawl function, so let's go back up to crawl
and take a look at it.
What crawl does is it takes in a string called letters
as well as basically x and y, which is the starting index
of where the user has said the word is.
Essentially it checks if x is  the dimension
basically that means that that index actually doesn't exist in our game,
so then that returns false.
If you've already visited the specific letter
then that's going to return false as well because a rule in Scramble
is that when you have 
a letter here, for instance,
you can join a letter by going up or diagonal like this,
so basically your next letter can be at any of these adjoining blocks,
but what you can't do, for instance, is go to this letter
and go back to the A, so you can only use each letter once.
Then that makes sense that here are marks that if we've been there before,
if marks is set to true, then that's not a valid word.
Then what it does is it checks.
It says I'm going to check whether at this specific location
the letter that we want is there.
If it's not, it returns false.
Since it's already checked that block, then it's going to set the mark
at that specific point as true.
Now it checks that basically if we're continuing
that means that we're going to search for the next letter
in the word that the user is trying to submit.
Here recall back to the rules.
You're trying to check all adjacent values,
the ones above, below, left and right as well as the diagonals,
and so similarly when we thought of iterating over 2D arrays 
where we wanted to iterate over every possible and check
every possible permutation between the row indices and the column indices
here we want to check every possible combination,
if it's to the left of the letter, directly above, or to the right.
Here we see that this loop checks to the left
when i is -1.
When it's at 0 it checks at the same column that the letter is at,
and then if i is 1, which is its final value, then it checks to the right,
and then that's not enough, right?
We need to check all of the vertical values, 
so then here we have a loop that gets checked whether it goes below
at the same level or above, so then the combination of that
will access every single adjacent block to A.
However, it also checks the block here at A,
so then we want to make sure that we don't check that one.
Now then, to actually check whether the preceding words are valid or not
then we want to do the same process for the rest of the word
barring the one that we've already done, so then here is a precursor function.
It calls itself, and we'll get into that a bit later, 
but it conducts the same process for all subsequent strings.
We've talked about the find function.
We understand what it's doing.
It's basically checking whether this word that the user gave
actually exists on the board and whether it's a valued move.
Here we have an initialize function.
Notice that it's void, so it's not going to be returning us anything,
but it's just going to be doing something for us.
Here off of Wikipedia there's a frequency
for every letter on the alphabet based on how often
it's used in the English language.
You see that e is, for instance, one of the most popular letters used.
We want to populate the grid.
What this function does is populate the grid with letters
kind of relative to their frequency in this array.
Now, this is using this language here 
saying size of frequencies, 
It's kind of only the specific case.
We can actually use size of frequencies, so when you actually want to 
find the length of an array you probably aren't going to be using size of
but rather just using the array length.
You can ask your TFs to talk to you a bit more about that,
but just know that this syntax here is more of a special case.
Now, for every element in the grid
we want to make a letter, and this is going to be pseudorandom, 
so random but not quite.
Essentially what this does is we set a new double 
with a random value between 0 and 1.
Based on that we're going to map that, 
so say that d is set to 0.6, for instance.
Then if d is 60% in
then we're going to look at all of the letters and find
relative to how often they're used 
what's 60% in.
This isn't just 60% of the alphabet but rather
a takes up this much space, and then b takes up this much,
and then e, for instance, will take up this much.
Based on the relative lengths or the frequencies
of these letters we're going to map that random value
between 0 and 1 to a specific letter.
That's what this code does here,
and then here k is like the shift of where along 
in the letter we want to be, and so we set the character in the grid
to be A + k.
Notice that back thinking to greedy
we had to use the round function to deal with floating-point imprecision here,
so similarly we had to take into account that sometimes
floats aren't exactly what we intend them to be,
so we want to make a catch for that.
Then here we go into file I/O, basically reading and writing to files,
which you will get into later but not quite yet,
so essentially this opens a dictionary file, reads what's in it,
and then sets it into an array.
Notice that we set it into the struct that we've declared, the dictionary struct,
and so dictionary has an array called words associated with it,
so what it's doing is saying dictionary, the words at this particular index
are such and such value.
Then we're almost finished with the distribution code.
We finally have the lookup function where you have comments
instructing you on what that code should do.
Lookup will look up a word in the dictionary
and as long as that word hasn't been found already
then flags it as found so the user can use it again
but also returns true thinking back to the main function again,
returns true, so says that that word can be scored.
And then finally you have the scramble function, 
which is another void function because it's doing something 
but not returning anything, so what the scramble function will do 
is rotate the grid 90° clockwise.
I know that might have been a little rough, but it's important to do.
Watch me going through the distribution code, 
but as well, try to go through it yourself.
What I like to do is map it out to understand
what does this program with all of these functions actually do?
If I were to go through the distribution code again,
now that I kind of have a sense of what's going on then I would say
we start with our main function,
and then I think the first thing that it does is it calls load,
so main calls load, but load is a void function,
so then what I do to indicate that is just putting a single arrow
pointing to load because main calls it.
The next thing is initialize.
Main calls initialize,
and then if we look back into our main function
I think this next thing that it does,
right here there are tons of different things that main is calling,
but right now I'm just focusing on the most major ones
relevant to the code, so I'm not including a to i or stuff like that.
Then the next thing that it does is it clears it,
and then it has draw,
and so I know that draw is something that we're going to do.
That's the draw function.
Later on we see that the next one is a bit—
so then we have scramble.
And then we have find, so find is another function.
We see that find is—if you recall back it's a boolean function,
so that's actually going to return something back to us.
Then here I indicate that by we have find,
and then we also have lookup.
But then remember that there's also this crawl function
that doesn't seem to have been called in main,
so that means that some other function is calling crawl,
and if you search back through the distribution code
you see that find here is the one that uses crawl,
so then find then also links to crawl, 
which is a boolean value, which returns something, 
so I'm adding another thing, and then since crawl is recursive
it also loops back on itself.
Then if you see here I've drawn a picture of what our program looks like,
so understanding the relationships between certain functions,
and going back to that you also see the order of the game
and the logic of how the game program is going to proceed.
We've read the distribution code.
The first function that you're going to want to implement, 
or one of the functions that you want to implement is draw,
and so here you actually have a little bit of freedom with this.
If we look at the staff solution—
I'm going to open the terminal window, actually,
pset3/scramble.
Scratch that. I think I need to update my appliance.
If you play with the staff solution of Scramble—
instructions are in the spec for that—
then you can see how they've printed out the game board,
but essentially what they do is they put spaces between each character,
but you have a little freedom with this, so if you want to print lines, for instance,
between them then you can do that.
You want to think back to how we iterate over all elements of a 2D array,
and you'll want to print those, make sure that you have your loop
and have your print functions such that you're printing in the right order.
If you want your iteration loop to—when you iterate over it
and you use the indices make sure that you're printing in the right order.
Dealing with 2D arrays at first can be a little confusing,
so here on this slide I've made a table that shows you
for every given spot in the 2D array what the indices are,
so if you want to refer back to this for a quick check
or for a reference or something like that then you can use this.
The columns are in blue, and the rows are in red.
The lookup function is twofold. 
Lookup—and it's a boolean function—will tell us 
true or false whether the user-submitted word
can be accepted as a valid value,
and so a word in scramble is only valid 
if it's found in the dictionary and if it's actually found in the board,
and so remember that lookup you have to implement this by yourself,
so you want to check both things,
whether the word is actually in the dictionary and whether it's been found already.
Recall back to the global variable dictionary, 
which is a struct that we've made that basically has an int called size 
associated with it as well as an array of words, 
where word is a new data type. 
So to access, for instance, the size of the dictionary or the words array, 
then what you can do is just write 'dictionary.size,' 
similar to the way that you would just use any other variable. 
So if dictionary.size represents the size of the dictionary, 
similarly, dictionary.words represents the array. 
So if you wanted to access a certain word within the dictionary, 
then you would have to add an index
because you would have to say 'dictionary.words at index i'
and then do something based on that. 
So knowing that the dictionary has a certain size associated with it,
as well as an array of words, to check if something's in the dictionary, 
then you would have to interate over the dictionary 
to check whether that word is found. 
Now, if you think back to lecture, when we talked about different ways to search for things, 
then remember that linear search probably isn't always the best way to go. 
But it definitely is one way to search for something. 
Sometimes you might find that you implement your find function with 
linear search at first and then get the rest of your program going. 
And then later on you can go back and alter the way that you search through for a word. 
So that tackles--basically knowing that--knowing how to access the  
words array of the dictionary, that tackles looking to see 
whether that word is actually in the dictionary or not. 
But then we also need to tackle whether that word is on the board. 
And whether that's been found already. 
So we already have the find function, remember. 
It shows su, but what is a word?
This isn't a philosophical question but, rather, look at the type definitions.
We have a boolean called 'found' as well as the array of characters 
that represents that word. 
So when you return lookup, you will want to check whether that word has been found or not. 
Now, knowing that the boolean found--found is the name of the boolean
that's associated with every word--then how might you access that variable, 
thinking back to how we accessed the variables within dictionary? 
So here we had dictionary, and then we said dot size, right? 
Similarly, when we have a word and, in this case, be careful because
word is just any other data type, just like an int or a string. 
So you can't just say 'word' unless that's the name of it. 
You're going to have to have a variable with a name, and then once you have that, 
say that's called foo, for instance, then you can say 'foo.found,'
and that will return you the boolean value of whether that word has been found or not. 
So then the next part of the pset is to implement scramble, 
whereby whenever the user inputs scramble--and that's already been dealt with 
here in the distribution code--you just need to implement 
the function scramble that has already instructed you to rotate the board 90° clockwise. 
As per the spec, the instructions say that the board rotates 90° clockwise 
such that the value at grid [0] [0] then moves to grid [0] [dimension -1.] 
In this case, for scramble, our dimension is 4, so 0-0 would then map to 0-3. 
Let's draw this out to see what it might look like. 
I'm not going to do a 4 x 4 grid but rather a 3 x 3 one. 
Let's say this is an inch 2D array. 
I'm just going to just have--all right. 
So say we want to scramble this; we want to rotate it 90° clockwise. 
We know that, as a starting point, the value at 0-0, which in this case is the number 0, 
is going to map to row 0, then column dimension -1. 
And so that, in this case, the dimension is 3. 
So then 0 would move to row 0, column 2. 
So we have the number 0 there. 
Essentially what we're doing is we're taking this, 
physically rotating it so then the 2 would go to this corner, 
the 8 would then go to this corner, the 6 to this one. 
And then the rest of it would look like--
So that's what a grid looks like when you have successfully scrambled it. 
When you're implementing the scramble function, what you'll want to do
is see, well, how can I replace these values? 
Is there some kind of pattern or some kind of formula to determine
where a particular index goes?
For instance, I might look to see that 3-4-5 here is a row. 
Where else do I see 3-4-5?
Well I see it here. 
Similarly, I see 6-7-8 as a row, but then it's actually a column here. 
That's the pattern that I see right now, but there are probably a few other ones. 
Based on that, think of some kind of pattern, some kind of way. 
Once you've identified one, then you're going to want to reset the values in the grid. 
So grid 0-0 will become 6, grid 0-1 will become 3. 
But remember that you'll--for instance, if you reset this right away, 
say that grid 0-2 becomes 0 now, then you lose what 2 was there. 
So thinking back, it's not enough to just reassign right away.
You'll probably want to make a temporary copy of something 
before you actually put it in at the right place. 
The last thing is to implement case insensitivity. 
If you look back, search to the spot in the spec where the user inputs a string. 
If you recall back, thinking back to--oh, I erased the map. 
If you think back to the map of your program, it's within the main function, 
so look to where you're dealing with the user-inputted string, 
and then within there, think of the tools that you learned from your 
crypto pset, pset 2, and then think of ways that you might be able to 
allow for user input as mixed case. 
So they could have a mix of uppercases and lowercases, but that should still be valid. 
In the dictionary, recall when we opened up that file, every word was stored as all uppercase. 
But we don't want the user to have to input uppercase all the time. 
Can anyone think of a way that we might be able to allow the user, 
even though they inputted all lowercase, for instance? Yeah? 
[Student] You could make it to upper? 
Yeah, exactly. You could make it to upper. 
So you could convert all of the letters to uppercase, and then 
that way you ensure that that is going to be an exact copy 
of whatever's found in the dictionary, if it's in the dictionary. 
Great. We have a little bit of time left. 
So some things that you might encounter in this pset is a need to know
what your variables are at a certain point in time. 
Because in the spec we have the clear function that basically 
clears whatever you've drawn on the board, erases it all and then rewrites on top of that, 
you might, while you're writing your pset, not really want that to happen. 
Because you'll want to see, okay, once I enter in this scramble, for instance, 
once I enter in scramble, what does it do and what was it before, just for reference. 
So then what you might want to do is go back to your main function 
and comment out clear, for instance. 
So then when you run your program the next time, 
your program won't clear it instead and will just keep on printing on top of that. 
There are some other ways to debug as well. 
What you could do is you can include print f statements, I think. 
One thing that I saw in psets that I graded was that people included print f statements 
to print out variables at a certain point in time to keep track. 
But just make sure that at the end, once you've finished writing all your print f statements 
for you to keep track of things, that you comment them out afterwards, 
or delete them once you've finished. 
That's another way that you could do something; you could just write in a print f statement 
somewhere that's relevant and see, based on what the terminal prints out, 
what that variable was. 
Another way to do that, that we'll go into more detail during lecture, 
is GDB, which is a debugging tool. 
Essentially, when you run it, it'll go into your program and you can have it advance
a single step at a time instead of evaluating everything. 
So then you can break it up into little steps, and then based on the way--
and then along the way print things and see what the values are. 
And that helps you figure out where a bug in your code might be. 
What we could do right now is write a quick function and then 
see how we might be able to use GDB to see what's going on. 
So let's have an int main, and then what do we have as parameters to main?
We have int arg c, and string arg v. 
I'm going to save this in walkthrough as GDB.z. All right. 
I'm going to have return 0. 
So how about let's just have a simple for loop; let's have 12. 
Let's also have an int named counter, and 
we can start that at 0. Okay. 
So at every point in the for loop, let's say that we want to increase counter 
or multiply it by whatever i is.
This is a pretty short function. 
Let's make GDB. Oh! And then--Clang is smart. 
Tells me that I didn't include cs50.h. 
All right. So now we want to--
Actually, sorry guys. I'm going to rename the file just because it's a bit confusing. 
All right. So now what we want to do is, we want to start GDB. 
I said 'GDB debugging,' so essentially it's going to be set to focusing on this debugging,
the debugging file. 
I'm going to put a breakpoint. 
Essentially, the program is going to run until it hits at a certain breakpoint. 
I'm going to say break at the main function. 
So now I'm going to run debugging; so inside GDB I can run the code. 
It's running the program, and even though main was one of the first things that we wrote, 
we also have the include files; there's stuff going on already. 
It has the breakpoint at main. 
Let's say 'next,' so we can continue on. 
It says "int counter = 0."
I'm going to say 'print counter.'
This is strange. So essentially we expect counters to be 0, 
but GDB is one step back, so whenever you say next, 
it says int counter = 0. That's the next thing that it's going to execute. 
Then you click--you can say next again, or you can just say 'n,' 
and now if you print counter, counter is 0, as we expect. 
Basically, it creates its own kind of variables for it, but whatever's there--
like right here; that's what counter represents. 
So I'm going to click next, and I want to know what i is. 
You'll print i, i is 0, as we expect. 
Next again, it's indicating that it's going through the for loop again, 
so if I print i, for instance, I can see that we're on the--that i is 1 currently. 
So that's a way, that if you set a breakpoint at a certain function 
and then keep on going next, and then checking what i is, 
if you have a guess that maybe somewhere something's not happening as it should, 
and you suspect that maybe it's at the first index or the last index or something, 
you can use GDB, keep on printing i, to be able to check what those values are. 
So then, in GDB, because print and next are such common arguments, 
common commands, just like I abbreviated next to n, 
I can also just say p counter; that's still 0. 
Then I click next. I want to print counter again. 
Well, so that's still 0. 
And you're kind of wondering--well, I want counter to be a factorial function. 
Why--just in techniques of debugging--why might that be? 
Why is counter not increasing its value? 
Why is it staying at 0? 
Well, here I have--back in here I say counter = counter x i. 
So then if I go back to the beginning of my function, 
I see that when I printed i, i is 0, and what's 0 x anything? 
It's 0, right? So that's probably the reason why counter
is never going to be any other number. 
So then what I might want to do is go back to my fuction, 
say, okay, well actually, I want to start it at 1. 
Is that going to solve things? 
Not quite, because counter is still 0 here. 
So let's set that to 1. 
We want to reset our debugging tool, so let's quit. 
And then what we can do is we can GDB debugging again, 
put a break at main, and then run debugging again, next, next, next. 
Let's hit next a few times, and then we'll print counter, see that--
we did not correctly make the file again. 
Even though we changed the source code, then we actually 
didn't update our executable. 
I believe that you can make--yeah. 
Within GDB itself, you can actually make the file. 
So you don't have to quit GDB again. 
You can go back to the source file, save it, back in GDB, you can make it again. 
Great. So let's run debugging. 
We want to start it from the beginning because we have a new executable. 
We can go through a couple of times, and then print i, print counter, continue. 
All right. So now we see that counter is actually increasing its value as we want it to. 
That's just a tiny little bite-sized example of how you might use GDB
to enter your code, print certain values, click next to proceed to the next line, 
and abbreviate it and print it out. 
Obviously, the code in scramble is a bit more complex than that, but what you can do
is set a breakpoint at--you can set a breakpoint at your lookup functions, something like that. 
So whenever it reaches the point where it needs to look something up, 
then GDB will run everything up to that point and then you can start printing values out. 
Like is marks at this point false or is it true? 
That's probably something that you might want to use. 
GDB, don't stress too much about it, 
because we will go into more detail in lecture, 
but I just wanted to let you guys know how you might be able to use it
if you're getting started with the pset and want to understand 
a better way than just putting print f statements and littering them all through your code. 
Having GDB to actually print it for you and being able to set those breakpoints
so that your program can run up until a certain point 
and then allow you to really step into it and figure out the problem there. 
Right. So then if we look back to scramble, we've read the distribution code.
We've talked about a way to iterate over 2D arrays, and you'll definitely 
be wanting to iterate over the 2D array when you come to drawing your game grid. 
We talked about the lookup function, about how we want to make sure of a couple of things. 
We want to make sure that we haven't been to the word before.
We also want to make sure that it's actually in the dictionary. 
Then we talked about scramble, about how we want to rotate the board. 
And knowing that you might want to make a copy of something
to be able to move it. 
Finally, we talked about case and sensitivity, about how you want to make sure
that despite whatever combination of case that the user inputs, 
if it's a valid word in the dictionary, 
then it's going to be found correctly. 
So then all of that together is the scramble pset, and that is walkthrough 3. 
Thanks everyone for coming, and good luck with scramble. 
CS50.TV
