Locker Game

Imagine a high school hallway with n lockers and n students. Now imagine a single student walking down the hallway and opening or closing the lockers. That's what this program will be simulating.

Before the school opens, the principal has closed each locker. The first student to enter the hallway opens every locker. The second student closes every other locker, shutting the door on lockers 2 and 4 and 6, etc. The third student begins with the third locker and changes every third locker (closes it if it was open, and opens it if it was closed). The fourth student begins with the fourth locker and changes every fourth locker. Do you get the idea? The fifth student starts at locker number five and changes every fifth locker, and so on until the nth student only changes the nth locker.

After all the students have passed through the building and changed the lockers, which lockers are open and which are closed? Write a program to display the status of the lockers after each student passes through the hallway.

Example run:
This is Brent's Locker Simulator. 
How many students are there in the school? 10
The configuration of the lockers is as follows, 
where 1 means open and 0 means closed.
10
1:      . . . . . . . . . .
2:      . X . X . X . X . X
3:      . X X X . . . X X X
4:      . X X . . . . . X X
5:      . X X . X . . . X .
6:      . X X . X X . . X .
7:      . X X . X X X . X .
8:      . X X . X X X X X .
9:      . X X . X X X X . .
10:     . X X . X X X X . X 


Here is what I have so far and now I am stuck.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/**
 * File: Locker Game
 * Author: Jake John
 * Course: CS I
 * Assignment: Locker Game
 * Due Date: March 10, 2021
 *
 * Write a program to display the status of the 
 * lockers after each student passes through the hallway.  
 */

#include <bits/stdc++.h>
using namespace std;

int getNumOfStudents(){
	int num;
	cout << "Enter number of students: ";
	cin >> num;
	
	return num;
}

void displayLockers(int numLockers, bool lockers[]){
	for(int i = 1; i <= numLockers; i++){
		cout << lockers[i] << " ";
	}
	cout << endl;
}

void runSimulation(int num){
	bool lockers[num+1};
	// walk each student thru the hall
	for(int i = 1; i <= num; i++){
		// have each student toggle lockers based on step size
		toggleLockers(i, lockers);
		// display lockers status
		displayLockers(num, lockers);
	}
}

int main(){
	
	int numOfStudents;
	
	// get number of students
	numOfStudents = getNumOfStudents();
	
	// run simulation
	runSimulation(numOfStudents);
	
	
	// terminate program
	cout << "Simulation complete. Goodbye." << endl;
	
	return 0;
}
Last edited on
Note that you can't specify at run time the size of a c-style array. You need to use something like a vector. So consider (NOT tested):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <vector>
using namespace std;

int getNumOfStudents() {
	int num {};

	cout << "Enter number of students: ";
	cin >> num;

	return num;
}

void displayLockers(const vector<bool>& lockers) {
	for (int i = 0; i < lockers.size(); ++i)
		cout << lockers[i] << ' ';

	cout << '\n';
}

void toggleLockers(int s, vector<bool>& lockers)
{
	for (int l = s - 1; l < lockers.size(); l += s)
		lockers[l] = !lockers[l];
}

void runSimulation(int num) {
	vector<bool> lockers(num);

	for (int i = 0; i < lockers.size(); ++i) {
		toggleLockers(i + 1, lockers);
		displayLockers(lockers);
	}
}

int main()
{
	const auto numOfStudents {getNumOfStudents()};

	runSimulation(numOfStudents);
	cout << "Simulation complete. Goodbye.\n";
}


First, "I'm stuck" is not all that descriptive, so we are at a disadvantage to help all that much.

However, to stab at a start, consider:

bool lockers[num+1};

The closing } is probably an accidental shift-key typo.

Setting that aside, what you have is a loop for every locker.

I see a call to "toggleLockers", but I don't find the function body. You'll need that to proceed.

What I don't see is the principal's pass...where he closes all of the lockers (which I assume is to ensure all bool's in the locker array are set to false). That isn't automatic in C/C++, but...I would need to know what version of C++ you're targeting (C++11, C++14, C++17?). There are initializers in newer versions that aren't in older ones, so the old/simple style is to loop through all of those bools and set each one to false (not toggle them).

That simulates the principal's pass.

Now, imagine the first student.

Every locker...that's the loop you've written, where you start at locker 0 and increment by 1. Toggle is fine here because you know every locker started closed from the principal's pass (if you write that).

Oops....you're not starting at locker 0. You're skipping it. Storage starts at zero, not 1.

Now, here's the part you need to really think about.


The second student.

Show me how you would construct a loop that toggles every other locker, not every locker.

That will be your second pass.

Also, keep in mind that arrays and vectors start numbering at 0, not 1. Interpret "every other" locker any way you want, but start at 0 if "every other" begins with the first locker, or start at 1 if "every other" skips the first locker, leaving it as it was.

Think carefully about your example. You show the second person toggling lockers 2, 4, 6....

Is that locker 2 starting from 1?

In the array, that would be locker 1 starting from zero....this is a typical thing new programmers bash their heads against all the time.

Now, the next student starts with the 3rd locker.

The first locker is zero.
The second locker is 1.
The third locker is 2.

Keep that clear, or your simulation will not follow the instructions.

....try to get that far....



Last edited on
I would start with locker 0, that's easier, and then when you want to display it, then display something like
cout << "Locker " << i+1 << " is open. \n";
That way you can start with element 0, which is easier, and only display starting with element 1. Did you understand that?

Best,
max
Last edited on
This is nifty:

The configuration of the lockers is as follows,
where 1 means open and 0 means closed.
10
1: . . . . . . . . . .
2: . X . X . X . X . X
3: . X X X . . . X X X


Notice the homework assignment text says "0" and "1", but the example output says "." and "X". I just love when requirements are internally inconsistent.

But what everybody else said was correct. Use a std::vector. Start indexing at 0. Etc.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <string>
using namespace std;

int main()
{
   int n;
   cout << "How many students? ";   cin >> n;
   string S = ".";
   for ( int i = 2; i <= n; i++ )
   {
      int c = 2;
      for ( int j = 2; j <= i / 2; j++ ) c += ( i % j == 0 );
      S += "X."[c%2];
   }
   cout << S << '\n';
}


How many students? 10
.XX.XXXX.X
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/**
 * File: Locker Game
 * Author: Jake John
 * Course: CS I
 * Assignment: Locker Game
 * Due Date: March 10, 2021
 *
 * Write a program to display the status of the 
 * lockers after each student passes through the hallway.  
 */

#include <bits/stdc++.h>
using namespace std;

int getNumOfStudents(){
	int num;
	cout << "This is Kolton Johnson's Locker Simulator." << endl;
	cout << "Enter number of students: ";
	cin >> num;
	cout << "This configuration of the locker is as follows, ";
	cout << "where 1 means open and 0 means closed." << endl << endl;
	
	return num;
}

void displayLockers(int numLockers, bool lockers[]){
	for(int i = 1; i <= numLockers; i++){
		cout << lockers[i] << " ";
	}
	cout << endl;
}

void runSimulation(int num){
	bool lockers[num+1];
	// walk each student thru the hall
	for(int i = 1; i <= num; i++){
		// have each student toggle lockers based on step size
		toggleLockers(i, lockers);
		// display lockers status
		displayLockers(num, lockers);
	}
}

int main(){
	
	int numOfStudents;
	
	// get number of students
	numOfStudents = getNumOfStudents();
	
	// run simulation
	runSimulation(numOfStudents);
	
	
	// terminate program
	cout << endl << "Simulation complete. Goodbye." << endl;
	
	return 0;
}


This is Jake John's Locker Simulator.
Enter number of students: 10
This configuration of the locker is as follows, where 1 means open and 0 means closed.

0 0 0 0 0 0 0 1 1 0 
0 0 0 0 0 0 0 1 1 0 
0 0 0 0 0 0 0 1 1 0 
0 0 0 0 0 0 0 1 1 0 
0 0 0 0 0 0 0 1 1 0 
0 0 0 0 0 0 0 1 1 0 
0 0 0 0 0 0 0 1 1 0 
0 0 0 0 0 0 0 1 1 0 
0 0 0 0 0 0 0 1 1 0 
0 0 0 0 0 0 0 1 1 0 

Simulation complete. Goodbye.


How do I get my code to get it to work properly?
What should I add to my code?
Last edited on
Does the fact that your routine toggleLockers() is currently empty not give you a clue?

BTW, your declaration
bool lockers[n+1];
is not standard c++, because you can't (at present) declare sizes of simple arrays at runtime. Also, you haven't initialised it, so you've got nothing to toggle.
I'm just confused about what to add to the code.
Where did you get the code from?
It seems this exercise is far beyond your head, so better start with easier tasks.
This is an assignment that I was given. I got all this but I don't know where to go from here.
This is an assignment that I was given. I got all this but I don't know where to go from here.


Well you could start with my code from above. Test it and change if required.
@seeplus

Is there any way that I can remove the vector<bool>& from the code and change it to a normal bool?
You can't can't do something like:
bool lockers[num+1]; because num is not a value known at compile-time. GCC allows this as an extension (called VLA, Variable-Length Array), but it still isn't standard C++.

You could have something like:
bool lockers[1000]; and still only use <num> number of indices, assuming 1000 is more than any realistic number of lockers you will need in practice.

If your instructor or whoever expects you to use a VLA, then do so, just note it isn't standard.
@jake john,
You could try dynamically allocating an array using a pointer, that would do what you want and get rid of undefined behavior cause by VLA (variable length array).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
bool *ptr;
int size;

std::cout << "Enter size: ";
std::cin >> size;

ptr = new bool [size];

// now "ptr" is a pointer to an array of length "size"

for (size_t i = 0; i < size; ++i)
{
      /* put code here to store bool value in ptr[i] */
}

// when you're done with ptr[], don't forget this:
delete [] ptr;
ptr = nullptr; // that makes sure you can't accidentally use it again 


Good luck,
max
Last edited on
It's not undefined behavior inherently (unless we are at the point that a stack overflow is happening, then that's bad).

Good point though, using a dynamic array can also solve this.
Ideally, you would also called delete[] ptr; when you're done with the array.
Last edited on
Yes, sorry, I forgot delete. I'll add it in. Warning, if you don't use delete, you can run into memory issues. I forget exactly what, but it can be bad.

Thanks, Ganado!
max
what does vector<bool>& mean? I am confused why it has to be a vector bool and cant be a bool by its self.
what does vector<bool>& mean? I am confused why it has to be a vector bool and cant be a bool by its self.


You need to keep track of each locker is open or closed. So you need 1 flag (bool) for each locker. If you use a single bool value, you cannot keep track of the state of all of the lockers.

A std::vector<bool> is like an array (bool x[]) on steroids. The vector will allow you to have a bool value for each locker.

If you are not allowed to use constructs that haven't been taught yet, then use a C-style array of bools. @agent max gave a good example in his post. (Called C-style because they are inherited from the C language.)

As you learn more about C++ you will learn that it is almost always better to use a std::vector rather than a raw C-style array.
Topic archived. No new replies allowed.