PPP2 Chapter 16 Exercise 3

[I hope someone who's read the book or is reading it will (also) reply, if possible. Thank you.]

My code:
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// Osman Zakir
// 8 / 2 / 2017
// Bjarne Stroustrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 16 Exercise 3
// chapter16ex3.cpp
// Exercise Specifications:
/**
* Place an Image on top of a Button ; move both when the button is pushed.
* Use this random number generator from std_lib_facilities.h to pick a
* new location for the “image button”:
*		#include<random>
*
*		inline int rand_int(int min, int max)
*		{
*			static default_random_engine ran;
*			return uniform_int_distribution<>{min,max}(ran);
*		}
* It returns a random int in the range [ min , max ).
*/

#include "../../GUI.h"
#include "../../Graph.h"
#include "../../Window.h"
#include <string>
#include <iostream>
#include <stdexcept>

namespace Graph_lib
{
	struct Image_button_window : Window
	{
		Image_button_window(Point xy, int w, int h, const std::string &title, const std::string &image_url, int button_w, int button_h,
			Point xy2);
		bool wait_for_button();
		void move_button();
	private:
		Image m_image;
		Button m_image_button;
		bool m_button_pushed;

		static void cb_button(Address, Address addr) { reference_to<Image_button_window>(addr).button_pressed(); }

		void button_pressed();
	};
}

int main()
{
	using namespace Graph_lib;
	using namespace std;

	constexpr int win_width = 600;
	constexpr int win_height = 400;

	try
	{
		Image_button_window win{ Point{100, 100}, win_width, win_height, "Moving Image Button",
			"Forum_Avatar.jpg", 180, 200, Point{(win_width / 2) - 100, (win_height / 2) - 100} };
		win.move_button();
		return gui_main();
	}
	catch (const runtime_error &e)
	{
		cerr << "Runtime_error: " << e.what() << '\n';
		return 1;
	}
	catch (const exception &e)
	{
		cerr << "Exception: " << e.what() << '\n';
		return 2;
	}
	catch (...)
	{
		cerr << "Some exception occurred\n";
		return 3;
	}
}

Graph_lib::Image_button_window::Image_button_window(Point xy, int w, int h, const std::string &title, const std::string &image_url,
	int button_w, int button_h, Point xy2)
	:Window{ xy, w, h, title },
	m_image{ xy2, image_url },
	m_image_button{ xy2, button_w, button_h, "", cb_button },
	m_button_pushed{ false }
{
	attach(m_image);
	attach(m_image_button);
}

void Graph_lib::Image_button_window::button_pressed()
{
	m_button_pushed = true;
}

void Graph_lib::Image_button_window::move_button()
{
	while (wait_for_button())
	{
		int x = rand_int(0, x_max());
		int y = rand_int(0, y_max());
		m_image.move(x, y);
		m_image_button.move(x, y);
	}
}

bool Graph_lib::Image_button_window::wait_for_button()
{
	show();
	m_button_pushed = false;
#if 1
	while (!m_button_pushed)
	{
		Fl::wait();
	}
	Fl::redraw();
#else
	Fl::run();
#endif
	return m_button_pushed;
}


Exercise Specifications:

Place an Image on top of a Button ; move both when the button is pushed.
Use this random number generator from std_lib_facilities.h to pick a
new location for the “image button”:
#include<random>
inline int rand_int(int min, int max)
{
static default_random_engine ran;
return uniform_int_distribution<>{min,max}(ran);
}
It returns a random int in the range [ min , max ).


I heard that the random number generator code shown here is a mistake in the book. I used this code:
1
2
3
4
5
6
7
8
9
int rand_int(int min, int max)
{
	using namespace std;

	unsigned seed = chrono::system_clock::now().time_since_epoch().count();
	default_random_engine generator(seed);

	return uniform_int_distribution<int> {min, max}(generator);
}


Anyways, right now when I push the button, the place it moves to is outside the window unless I maximize it and see. And it only moves the first time I push it. Every other time it won't move no matter how many times I push it. What should I do?
I heard that the random number generator code shown here is a mistake in the book.

And where did you "hear" that? And what was the stated reason for that observation?

I used this code:

Did you even try out both of those snippets?



I can't comment on your other issues because the code you supplied will not compile and link for me.


And please don't PM me with your problems. If I see a problem in the forum that interests me I will try to answer the question. However if I'm not interested in the problem I won't bother, and I usually never answer PMs begging for individual help.

Last edited on
I heard that the random number generator code shown here is a mistake in the book

the book code doesn't seed the engine and hence it generates the same 'random' number every time the program is run (for eg. 0 on my laptop):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# include <iostream>
# include <random>
# include <chrono>

auto unseeded_rand_int(const int minRange, const int maxRange)
//avoid variable names like min, max that are used elsewhere by the standard
{
    static std::default_random_engine generator;
    return std::uniform_int_distribution<>{minRange, maxRange}(generator);
}
auto seeded_rand_int(const int minRange, const int maxRange)
{
    auto seed = std::chrono::system_clock::now().time_since_epoch().count();
    static std::default_random_engine generator(seed);
    return std::uniform_int_distribution<> {minRange, maxRange}(generator);

}
int main()
{
    std::cout << unseeded_rand_int(0, 100) << "\n";
    std::cout << seeded_rand_int(0, 100);
}

As for your other queries I'm afraid I'd not be of much help Dragon, good luck!


the book code doesn't seed the engine and hence it generates the same 'random' number every time the program is run (for eg. 0 on my laptop):

Which is not a real problem in this case, in fact it may be a benefit since every time you run the program you get the same sequence. It may then be easier to tell if it is the changes you're making to your program that are changing things instead of the random numbers being the cause.

But regardless your code is producing much better random numbers than the OP's code.

Comparing the three functions:

Run 1
1
2
3
4
5
Your unseeded: 0 13 76 46 53 22 4 68 68 94 38 52 83 3 5 53 67 0 38 6 

Your seeded: 37 62 57 22 31 10 99 91 82 56 9 57 73 82 8 96 1 96 92 30 

The OP's: 68 68 68 69 69 69 69 69 70 70 70 70 70 71 71 71 71 71 72 72   


Run 2.
1
2
3
4
5
Your unseeded: 0 13 76 46 53 22 4 68 68 94 38 52 83 3 5 53 67 0 38 6 

Your seeded: 40 6 51 18 15 9 11 60 61 78 67 65 59 98 33 70 50 51 40 37 

The OP's: 70 70 71 71 71 71 71 72 72 72 72 72 73 73 73 73 73 74 74 74   


As you pointed out the unseeded version produces the same sequence, where the seeded version produces a different sequence each time the program is run.

But look at the output of the OP's "random" function, the output doesn't appear very random to me. If the OP would have checked his generator and not just assumed his code was correct he should have spotted this problem.

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
#include <iostream>
#include <random>
#include <chrono>

auto unseeded_rand_int(const int minRange, const int maxRange)
//avoid variable names like min, max that are used elsewhere by the standard
{
    static std::default_random_engine generator;
    return std::uniform_int_distribution<>{minRange, maxRange}(generator);
}
auto seeded_rand_int(const int minRange, const int maxRange)
{
    auto seed = std::chrono::system_clock::now().time_since_epoch().count();
    static std::default_random_engine generator(seed);
    return std::uniform_int_distribution<> {minRange, maxRange}(generator);

}

int rand_int(int minRange, int maxRange)
{
	using namespace std;

	unsigned seed = chrono::system_clock::now().time_since_epoch().count();
	default_random_engine generator(seed);

	return uniform_int_distribution<int> {minRange, maxRange}(generator);
}

int main()
{
    std::cout << "Your unseeded: ";
    for(int i = 0; i < 20; ++i)
        std::cout << unseeded_rand_int(0, 100) << " ";
    
    std::cout << "\n\nYour seeded: ";
    for(int i = 0; i < 20; ++i)
        std::cout << seeded_rand_int(0, 100) << " ";
    
    std::cout << "\n\nThe OP's: ";
    for(int i = 0; i < 20; ++i)
        std::cout << rand_int(0, 100) << " ";

}

Last edited on
You can't compile and link that code without the support code from the book. If you have it and it still won't compile and link, then I don't know what the problem could be.

Anyway, I'll change the random number generator code and see what happens.

Doesn't there seem to be anything wrong with move_button() or how I'm using it?

I used the seeded generator from your code:
1
2
3
4
5
6
7
8
int rand_int(int minRange, int maxRange)
{
	using namespace std;

	auto seed = chrono::system_clock::now().time_since_epoch().count();
	static default_random_engine generator(seed);
	return uniform_int_distribution<> {minRange, maxRange}(generator);
}


Now, the exercise solution code:
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// Osman Zakir
// 8 / 2 / 2017
// Bjarne Stroustrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 16 Exercise 3
// chapter16ex3.cpp
// Exercise Specifications:
/**
* Place an Image on top of a Button ; move both when the button is pushed.
* Use this random number generator from std_lib_facilities.h to pick a
* new location for the “image button”:
*		#include<random>
*
*		inline int rand_int(int min, int max)
*		{
*			static default_random_engine ran;
*			return uniform_int_distribution<>{min,max}(ran);
*		}
* It returns a random int in the range [ min , max ).
*/

#include "../../GUI.h"
#include "../../Graph.h"
#include "../../Window.h"
#include <string>
#include <iostream>
#include <stdexcept>

namespace Graph_lib
{
	struct Image_button_window : Window
	{
		Image_button_window(Point xy, int w, int h, const std::string &title, const std::string &image_url, int button_w, int button_h,
			Point xy2);
		bool wait_for_button();
		void move_button();
	private:
		Image m_image;
		Button m_image_button;
		bool m_button_pushed;

		static void cb_button(Address, Address addr) { reference_to<Image_button_window>(addr).button_pressed(); }

		void button_pressed();
	};
}

int main()
{
	using namespace Graph_lib;
	using namespace std;

	constexpr int win_width = 600;
	constexpr int win_height = 400;

	try
	{
		Image_button_window win{ Point{100, 100}, win_width, win_height, "Moving Image Button",
			"Forum_Avatar.jpg", 180, 200, Point{(win_width / 2) - 100, (win_height / 2) - 100} };
		win.move_button();
		return gui_main();
	}
	catch (const runtime_error &e)
	{
		cerr << "Runtime_error: " << e.what() << '\n';
		return 1;
	}
	catch (const exception &e)
	{
		cerr << "Exception: " << e.what() << '\n';
		return 2;
	}
	catch (...)
	{
		cerr << "Some exception occurred\n";
		return 3;
	}
}

Graph_lib::Image_button_window::Image_button_window(Point xy, int w, int h, const std::string &title, const std::string &image_url,
	int button_w, int button_h, Point xy2)
	:Window{ xy, w, h, title },
	m_image{ xy2, image_url },
	m_image_button{ xy2, button_w, button_h, "", cb_button },
	m_button_pushed{ false }
{
	attach(m_image);
	attach(m_image_button);
}

void Graph_lib::Image_button_window::button_pressed()
{
	m_button_pushed = true;
}

void Graph_lib::Image_button_window::move_button()
{
	if (wait_for_button())
	{
		int x = rand_int(0, x_max());
		int y = rand_int(0, y_max());
		m_image.move(x, y);
		m_image_button.move(x, y);
	}
}

bool Graph_lib::Image_button_window::wait_for_button()
{
	show();
	m_button_pushed = false;
#if 1
	while (!m_button_pushed)
	{
		Fl::wait();
	}
	Fl::redraw();
#else
	Fl::run();
#endif
	return m_button_pushed;
}


I still need to maximize the window to see where the button moves to one I click it, and it's also the same place each time. And, as before, I can't make it move from clicking it again (though I have a suspicion that that might be fine).
Last edited on
Anyway, I'll change the random number generator code and see what happens.

If you don't understand why your "random" doesn't work then just copying and pasting code really won't do much good. I suggest you study the differences and see if you can't reason out why your code is broken.

Doesn't there seem to be anything wrong with move_button() or how I'm using it?

I have no idea, I suggest you attempt to troubleshoot the issue instead of trying to rely on others to do the troubleshooting for you. A big part of your problems with the content of this book is that you don't seem to be developing your troubleshooting skills adequately. You really need to work on this. Use your debugger, set a break point early in the code and single step through the code and follow the logic. If you think the problem is within one function then set a break point in that function and single step through the function checking the variables at each step. You should also git rid of any extraneous code, such as that silly define in your wait_for_button() routine.

By the way you really should be implementing your class member functions inside the same namespace as the class definition. Just scoping (::) the functions to the namespace may not be enough.



I'm not sure how the debugger will help in this case since I don't know what to look out for, but I'll try anyway.

Edit: I guess I misunderstood what was happening earlier. The button actually moving to a different spot each time. But most of the time it goes to a place where I have to maximize the window to see it. I think it's fine like this, though. I'll move on.

Here's the code:
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// Osman Zakir
// 8 / 2 / 2017
// Bjarne Stroustrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 16 Exercise 3
// chapter16ex3.cpp
// Exercise Specifications:
/**
* Place an Image on top of a Button ; move both when the button is pushed.
* Use this random number generator from std_lib_facilities.h to pick a
* new location for the “image button”:
*		#include<random>
*
*		inline int rand_int(int min, int max)
*		{
*			static default_random_engine ran;
*			return uniform_int_distribution<>{min,max}(ran);
*		}
* It returns a random int in the range [ min , max ).
*/

#include "../../GUI.h"
#include "../../Graph.h"
#include "../../Window.h"
#include <string>
#include <iostream>
#include <stdexcept>

namespace Graph_lib
{
	struct Image_button_window : Window
	{
		Image_button_window(Point xy, int w, int h, const std::string &title, const std::string &image_url, int button_w, int button_h,
			Point xy2);
		bool wait_for_button();
		void move_button();
	private:
		Image m_image;
		Button m_image_button;
		bool m_button_pushed;

		static void cb_button(Address, Address addr) { reference_to<Image_button_window>(addr).button_pressed(); }

		void button_pressed();
	};
}

int main()
{
	using namespace Graph_lib;
	using namespace std;

	constexpr int win_width = 600;
	constexpr int win_height = 400;

	try
	{
		Image_button_window win{ Point{100, 100}, win_width, win_height, "Moving Image Button",
			"Forum_Avatar.jpg", 180, 200, Point{(win_width / 2) - 100, (win_height / 2) - 100} };
		win.move_button();
		return gui_main();
	}
	catch (const runtime_error &e)
	{
		cerr << "Runtime_error: " << e.what() << '\n';
		return 1;
	}
	catch (const exception &e)
	{
		cerr << "Exception: " << e.what() << '\n';
		return 2;
	}
	catch (...)
	{
		cerr << "Some exception occurred\n";
		return 3;
	}
}

Graph_lib::Image_button_window::Image_button_window(Point xy, int w, int h, const std::string &title, const std::string &image_url,
	int button_w, int button_h, Point xy2)
	:Window{ xy, w, h, title },
	m_image{ xy2, image_url },
	m_image_button{ xy2, button_w, button_h, "", cb_button },
	m_button_pushed{ false }
{
	attach(m_image);
	attach(m_image_button);
}

void Graph_lib::Image_button_window::button_pressed()
{
	m_button_pushed = true;
}

void Graph_lib::Image_button_window::move_button()
{
	if (wait_for_button())
	{
		int x = rand_int(0, x_max());
		int y = rand_int(0, y_max());
		m_image.move(x, y);
		m_image_button.move(x, y);
	}
}

bool Graph_lib::Image_button_window::wait_for_button()
{
	show();
	m_button_pushed = false;
	while (!m_button_pushed)
	{
		Fl::wait();
	}
	Fl::redraw();
	return m_button_pushed;
}
Last edited on
Topic archived. No new replies allowed.