You are a detective and there has been a breakthrough in a tough case you've been assigned to work on. The cell phone of one of the prime suspects has been discovered!
This is great! But there are two problems:
1. We don't know the pin
2. We don't know HOW LONG IT WILL TAKE to figure out the pin
The second problem is arguably the most important one because we can sit and try different pins but if it takes years to go through all the possible combinations, that is not going to be fast enough.
What we really need is BOTH a method to scan through the possible pins AND an estimate of how long it should take to go through all the different possibilities.
In the image of the phone at the top of the page, it has a passcode that is four digits long and the digits can be anything from 0 to 9. In this activity we are going to start with a simpler problem: a passcode that is three digits long and the digits can be anything from 0 to 9.
The reason we are doing this is (1) it shouldn't take a crazy amount of time to scan through all the possible three digit pins, and (2) what we really need to do is figure out how to estimate how long it would take to crack a pin of a particular length with a particular range of digits.
So we are going to start with three digits and 0 to 9 but we will think about other possibilities later.
Click here to open up a simple code
Go ahead and press in the top left to run the code. The output it produces will look like this:
If the program can detect that something is wrong with your code it will show a red next to that objective.
If the program can detect that you have completed the objective it will show a green check mark next to that objective.
But the program is not very smart and if it can't tell whether you have completed the objective it will indicate a question mark like this next to that objective.
By the end of this activity your goal is to have green check marks next to all the objectives like this:
The directions below will help you meet all these objectives.
There are also some challenges in this activity (for which there are no milestones). The directions will give you some advice on those too.
Here is what the code looks like:
secretpin = 123; guesspin = 0; function draw() { clearscreen(240,240,240); display(); setframeRate(2); // tries per second textSize(30); text('Crack the PIN',100,25); text('guess pin: ' + guesspin,100,75); // check for a match here guesspin += 1; } // DO NOT ADD ANY CODE AFTER THIS LINE!!!
The code here is pretty simple. There is a secret pin that is set to 123. The program guesses the pin one by one, starting with 0 and increasing each time the draw function is run because at the end of the draw function there is this line:
guesspin += 1;
The problem with this program right now is that it does not check to see if guesspin
is the same as secretpin
. Let's add some code to do that.
In the code there is a comment:
// check for a match here
In that spot, add this code:
if (guesspin == secretpin) { textSize(80); text('A match!',25,200); exit(); }
At this point your program should behave like this
By now you have probably noticed that it takes a pretty long time for the program to guess the secret pin of 123.
If you look closely at the program you will see this line:
setframeRate(2); // tries per second
This function sets the number of times per second that the draw function is run. Each time draw is run a new frame is drawn so the number in the parentheses is the frames per second. Since we guess one pin per frame this means that our frames per second is also our tries per second. Right now it is set to 2 frames per second.
Increase the frames per second by changing the number in the parentheses from 2 to something larger like 60.
60 is the maximum frames per second. Most displays do not go faster than 60 frames per second so if you put something like 100 or 120 in the parentheses it will throw up an error.
At this point your program should behave like this
By default the secret pin is set to 123. To make the program more realistic we can configure it so that each time you run the program a different secret pin is selected.
At the beginning of the code, comment out or erase this line:
secretpin = 123;
and replace it with this line:
secretpin = floor(random(0,1000));
In the code above, a random DECIMAL number between 0 and 1000 is selected. Then the floor() function rounds this decimal to the next LOWEST INTEGER. So for example floor(9.9)
would evaluate to 9. If you are curious for more information on the floor()
function you can check out this reference page
At this point your program should behave like this
Optional: Show the secret pin on screen by adding this to your code on a new line after the line that reads text('Crack the PIN',100,25);
text('secret pin: ' + secretpin,100,125);
We need to add some code to our program in order to measure the elapsed time, which is just the amount of time that has passed since our program began running.
Mathematically the elapsed time is calculated like this: $$ t_{\rm elapsed} = t_{\rm now} - t_{\rm begin} $$
where $t_{\rm begin}$ is the time (on the clock) when the program began and $t_{\rm now}$ is the time (on the clock) right now. The difference between these two numbers is how much time has passed so far.
We will implement this into our code in a few sub-steps:
Step 6a. Add time_begin
At the BEGINNING of your program add this line of code:
time_begin = Date.now();
This will set the value of time_begin
to the current time in milliseconds
Why are we setting time_begin
to Date.now()? Don't we want it to be the time at the beginning?
Step 6b. Add time_now
Somewhere inside the draw function after the clearscreen command add this line of code:
time_now = Date.now();
Step 6c. Calculate time_elapsed
In the line right AFTER time_now
is defined, add this line:
time_elapsed = time_now - time_begin;
Step 6d. Write the value of time_elapsed on screen
Now we need to write the value of time_elapsed on screen. Here is some code you should add inside the draw() function AFTER the clearscreen command.
textSize(15); text('milliseconds elapsed so far: ' + time_elapsed,25,110);
At this point your code should behave like this
max_time
One of the main goals that we have is to anticipate how long it would take to scan through all the possible pin combinations. We may get lucky and the program will find a match well before all the pin combinations are explored. But what we need is an estimate for how long AT MOST will it take for the program to finish.
Step 7a. Think about max_time
Let's break this down into a few questions:
1. If the pin can go from 0 to 999 then how many possible pins are there?
This is going to be the total number of tries that we are going to need to do.
2. How many tries per second is our program doing?
An important line of code to think about is this one:
setframeRate(60); // tries per second
If you have set the number in the parentheses to 60 then our program will try 60 different pins each second.
3. How many milliseconds are there in one second?
Remember that our elapsed time is being measured in milliseconds, not seconds. If you don't know how many milliseconds are in a second you can google it.
The above information should be all you need to calculate how long (in milliseconds) it should take to scan through all the pin combinations.
Step 7b. Modify the program
Here is some code you can add to the draw function to show your estimate for the maximum time on screen:
max_time = ???; textSize(12); text('This should not take more than about '+ floor(max_time) + ' milliseconds',15,125);
Your job is to replace the ???
with a mathematical expression that will accurately predict how long it should take in milliseconds to scan through all the pin combinations.
What happens when you change floor(max_time) to max time? Why is this a bad idea?
At this point you should have all green check marks! Yay!
Why is it important to run the program a few times? Why can't we just run it once to see if the calculation of max_time is correct?
Is it possible to choose a secret pin that the program would not eventually try?
Once you have an expression for max_time
that you think is correct, run the program a few times.
Why is it important to run the program a few times? Why can't we just run it once to see if the calculation of max_time is correct?
Is it possible to choose a secret pin that the program would not eventually try?
Let's imagine that the pin on the phone is four digits with numbers from 0 to 5 (in other words a pin with no 6, 7, 8 or 9 in it). How long should that take to scan through all the possible pins?
We can modify the program to explore this possibility by replacing this:
secretpin = floor(random(0,1000));
with this:
secretpin = 5555;
Note: You will lose the green check for "Randomize secret pin" but that's ok.
Now change the match detection from this:
if (guesspin == secretpin) { textSize(80); text('A match!',25,200); exit(); }
to this:
if (guesspin.toString(??) == secretpin) { textSize(80); text('A match!',25,200); exit(); }
And change this:
text('guess pin: ' + guesspin,100,75);
to this:
text('guess pin: ' + guesspin.toString(??),100,75);
The toString()
command will convert guesspin
into a different base. Your goal is to change this number to a base where the numbers 6,7,8 and 9 never appear. To do this you will replace ??
with either a 5 (for base 5) or a 6 (for base 6). Which is correct? Base 5 or Base 6?
Advice: Decrease the frame rate to 2 and then try base 5 and base 6 and watch the screen to make sure that the guessed pin has the right range of numbers (no digits between 6 and 9). Once you decide on a correct base you can change the frame rate back to 60.
Very important: Change your estimate of max_time
to account for the fact that we are scanning over four digits (not three) but we are NOT scanning over any numbers that include 6, 7, 8 or 9. See if you can accurately predict max_time
even in this situation!
It would be nice to have something visual to help the user see how long it will take to explore every possible pin. One way to do this would be to add a progress bar like this:
textSize(12); text('Progress bar (match may occur before scan is complete):',20,220); x = 100; // change this!!! line(50,230,x,230); line(50,240,350,240);
Paste this code inside the draw() function anywhere after clearscreen(240,240,240);
Your goal is to replace x = 100;
with something that will grow as the program gets closer exploring all the possible pins. So at the beginning of the program x will be equal to 50 and if the program gets all the way to exploring all possibilities (for example if secretpin = 999;
) then x will be equal to 350. What we need is a line of codde that takes the value of guesspin and calculates what the value of x should be.
Note: The screen goes horizontally from x = 0 to x = 400, so the line here ranges from 50 to 350.
If you can configure this correctly your program will behave like this
Extra challenge: Get this to work for the 4 digit pin with numbers between 0 and 5 (challenge #1).
1. Complete Steps 1-9
You should be able to get all green check marks by the end of Step 7. If you are having trouble ask another student or the teacher for advice.
Also make sure to do the part where you modify the program to explore a four digit pin but with only numbers between 0 and 5 (Step 9).
2. Answer all the questions in the question document
Getting the code to work is only part of the task of this activity. There are various reflection questions that you should answer!
3. The Challenge
There is to add a progress bar to the program. Ask your teacher if they want you to do the challenge! If they say no you can still do it just for fun!
4. Submit your code
Submit your code to your teacher before the deadline so they can view it and give you feedback. Talk to your teacher if you are not sure how to do this.