├── Chapter1
├── Chapter1.vcxproj
└── main.cpp
├── Chapter2.1
├── Chapter2.1.vcxproj
└── main.cpp
├── Chapter2.2
├── Chapter2.2.vcxproj
└── main.cpp
├── Chapter3
├── Chapter3.vcxproj
└── main.cpp
├── Chapter4
├── Chapter4.vcxproj
└── main.cpp
├── Chapter5
├── Chapter5.vcxproj
├── main.cpp
├── playing_cards.cpp
└── playing_cards.h
├── Chapter6
├── Chapter6.vcxproj
├── Race.cpp
├── Race.h
└── main.cpp
├── Chapter7
├── Chapter7.vcxproj
├── Smash.cpp
├── Smash.h
├── dictionary.csv
├── keywords.csv
└── main.cpp
├── Chapter8
├── Chapter8.vcxproj
└── main.cpp
├── Chapter9
├── Chapter9.vcxproj
└── main.cpp
├── Code.sln
├── LICENSE
└── README.md
/Chapter1/Chapter1.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | Win32Proj
24 | {b6ee4e15-5a1f-4b4f-a52c-667ae934ef7e}
25 | Chapter1
26 | 10.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v143
33 | Unicode
34 |
35 |
36 | Application
37 | false
38 | v143
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v143
46 | Unicode
47 |
48 |
49 | Application
50 | false
51 | v143
52 | true
53 | Unicode
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | Level3
76 | true
77 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
78 | true
79 | stdcpplatest
80 |
81 |
82 | Console
83 | true
84 |
85 |
86 |
87 |
88 | Level3
89 | true
90 | true
91 | true
92 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
93 | true
94 |
95 |
96 | Console
97 | true
98 | true
99 | true
100 |
101 |
102 |
103 |
104 | Level3
105 | true
106 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
107 | true
108 |
109 |
110 | Console
111 | true
112 |
113 |
114 |
115 |
116 | Level3
117 | true
118 | true
119 | true
120 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
121 | true
122 |
123 |
124 | Console
125 | true
126 | true
127 | true
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/Chapter1/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | // Needs C++14 for std::plus so compile with e.g.
5 | // g++ --std=c++14 hello_world.cpp -o ./hello.out
6 |
7 | template
8 | auto simple_plus(T lhs, U rhs) -> decltype(lhs + rhs)
9 | {
10 | return lhs + rhs;
11 | }
12 |
13 | auto main() -> int {
14 | std::cout << "Hello, world!\n";
15 | std::plus adder;
16 | std::cout << adder(1, 1.23) << '\n'; // you possibly get a warning because adder is created to add ints
17 | std::cout << std::plus<>{}(1, 1.23) << '\n';
18 | std::cout << simple_plus(1, 1.23) << '\n';
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/Chapter2.1/Chapter2.1.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | Win32Proj
24 | {273c3030-6833-475f-ab2f-6e8bf90346da}
25 | Chapter1
26 | 10.0
27 | Chapter2.1
28 |
29 |
30 |
31 | Application
32 | true
33 | v143
34 | Unicode
35 |
36 |
37 | Application
38 | false
39 | v143
40 | true
41 | Unicode
42 |
43 |
44 | Application
45 | true
46 | v143
47 | Unicode
48 |
49 |
50 | Application
51 | false
52 | v143
53 | true
54 | Unicode
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | true
76 |
77 |
78 | false
79 |
80 |
81 | true
82 |
83 |
84 | false
85 |
86 |
87 |
88 | Level3
89 | true
90 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
91 | true
92 | /std:c++latest %(AdditionalOptions)
93 |
94 |
95 | Console
96 | true
97 |
98 |
99 |
100 |
101 | Level3
102 | true
103 | true
104 | true
105 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
106 | true
107 |
108 |
109 | Console
110 | true
111 | true
112 | true
113 |
114 |
115 |
116 |
117 | Level3
118 | true
119 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
120 | true
121 |
122 |
123 | Console
124 | true
125 |
126 |
127 |
128 |
129 | Level3
130 | true
131 | true
132 | true
133 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
134 | true
135 |
136 |
137 | Console
138 | true
139 | true
140 | true
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
--------------------------------------------------------------------------------
/Chapter2.1/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | void generate_triangle()
5 | {
6 | std::vector data{ 1 };
7 | for (auto number : data)
8 | {
9 | std::cout << number << ' ';
10 | }
11 | std::cout << '\n';
12 | }
13 |
14 | int main()
15 | {
16 | generate_triangle();
17 | }
18 |
--------------------------------------------------------------------------------
/Chapter2.2/Chapter2.2.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | Win32Proj
24 | {740da552-2257-441e-8c77-ef5a9ce71a34}
25 | Chapter12
26 | 10.0
27 | Chapter2.2
28 |
29 |
30 |
31 | Application
32 | true
33 | v143
34 | Unicode
35 |
36 |
37 | Application
38 | false
39 | v143
40 | true
41 | Unicode
42 |
43 |
44 | Application
45 | true
46 | v143
47 | Unicode
48 |
49 |
50 | Application
51 | false
52 | v143
53 | true
54 | Unicode
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | true
76 |
77 |
78 | false
79 |
80 |
81 | true
82 |
83 |
84 | false
85 |
86 |
87 |
88 | Level3
89 | true
90 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
91 | true
92 | /std:c++latest %(AdditionalOptions)
93 |
94 |
95 | Console
96 | true
97 |
98 |
99 |
100 |
101 | Level3
102 | true
103 | true
104 | true
105 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
106 | true
107 |
108 |
109 | Console
110 | true
111 | true
112 | true
113 |
114 |
115 |
116 |
117 | Level3
118 | true
119 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
120 | true
121 |
122 |
123 | Console
124 | true
125 |
126 |
127 |
128 |
129 | Level3
130 | true
131 | true
132 | true
133 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
134 | true
135 |
136 |
137 | Console
138 | true
139 | true
140 | true
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
--------------------------------------------------------------------------------
/Chapter2.2/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | // In Visual Studio add /std:c++latest to 'properties | C++ | command line | additon options' to get the CTAD, ranges etc
13 | // Or at least C++17 for --std in g++ (CTAD has been around since C++17)
14 |
15 | //Listing 2.2 The next row of Pascal's triangle using the previous row
16 | std::vector get_next_row(const std::vector& last_row)
17 | {
18 | std::vector ret{ 1 }; // CTAD - otherwise say std::vector
19 | if (last_row.empty())
20 | {
21 | return ret;
22 | }
23 |
24 | for (size_t idx = 0; idx+1 < last_row.size(); ++idx)
25 | {
26 | ret.emplace_back(last_row[idx] + last_row[idx + 1]);
27 | }
28 | ret.emplace_back(1);
29 | return ret;
30 | }
31 |
32 | //Listing 2.3 Generating several rows of Pascal's triangle
33 | auto generate_triangle_first_listing(int rows)
34 | {
35 | std::vector data;
36 | std::vector> triangle;
37 | for (int row = 0; row < rows; ++row)
38 | {
39 | data = get_next_row(data);
40 | triangle.push_back(data);
41 | }
42 | return triangle;
43 | }
44 |
45 | //Listing 2.4 Moving a temporary
46 | auto generate_triangle(int rows)
47 | {
48 | std::vector> triangle{ {1} };
49 | for (int row = 1; row < rows; ++row)
50 | {
51 | triangle.emplace_back(get_next_row(triangle.back()));
52 | }
53 | return triangle;
54 | }
55 |
56 | //Listing 2.5 Sending the contents to a stream
57 | template
58 | std::ostream& operator << (std::ostream & s,
59 | const std::vector>& triangle)
60 | {
61 | for (const auto& row : triangle)
62 | {
63 | std::ranges::copy(row, std::ostream_iterator(s, " "));
64 | // If your compile doesn't support ranges, use std::copy instead:
65 | //std::copy(row.begin(), row.end(), std::ostream_iterator(s, " "));
66 | s << '\n';
67 | }
68 | return s;
69 | }
70 |
71 | // Listing 2.7 Center justified output
72 | void show_vectors(std::ostream& s,
73 | const std::vector>& v)
74 | {
75 | size_t final_row_size = v.back().size();
76 | std::string spaces(final_row_size * 3, ' ');
77 | for (const auto& row : v)
78 | {
79 | s << spaces;
80 | if (spaces.size() > 3)
81 | spaces.resize(spaces.size() - 3);
82 | for (const auto& data : row)
83 | {
84 | s << std::format("{: ^{}}", data, 6);
85 | }
86 | s << '\n';
87 | }
88 | }
89 | // This code is slightly more general than the text of the book, shown above
90 | // since it takes a width of 6, allowing you to try more rows
91 | // Recall, 6 is fine for 16 or so rows.
92 | // Once the entries are more than 4 digits the will overlap
93 | void show_vectors_more_general(std::ostream& s,
94 | const std::vector>& v, size_t width = 6)
95 | {
96 | const auto gaps = width/2;
97 | std::string spaces(v.back().size() * gaps, ' ');
98 | for (const auto& row : v)
99 | {
100 | s << spaces;
101 | if (spaces.size() > gaps)
102 | spaces.resize(spaces.size()- gaps);
103 | for (const auto& data : row)
104 | {
105 | s << std::format("{: ^{}}", data, width);
106 | }
107 | s << '\n';
108 | }
109 | }
110 |
111 | // Based on
112 | // https://en.cppreference.com/w/cpp/algorithm/ranges/equal
113 | // contexpr not mentioned in the text
114 | constexpr bool is_palindrome(const std::vector& v)
115 | {
116 | auto forward = v | std::views::take(v.size() / 2);
117 | auto backward = v | std::views::reverse | std::views::take(v.size() / 2);
118 | return std::ranges::equal(forward, backward);
119 | }
120 |
121 | // Some tests, using assert
122 | // fails for a 36 row triangle - think about why
123 | void check_properties(const std::vector> & triangle)
124 | {
125 | int expected_total = 1;
126 | size_t row_number = 1;
127 | for (const auto & row : triangle)
128 | {
129 | assert(row.front() == 1);
130 | assert(row.back() == 1);
131 | assert(row.size() == row_number++);
132 |
133 | assert(std::accumulate(row.begin(),
134 | row.end(),
135 | 0)
136 | == expected_total);
137 |
138 | expected_total *= 2;
139 |
140 | // symmetry
141 | assert(is_palindrome(row));
142 |
143 | auto negative = [](int x) { return x < 0; };
144 | auto negatives = row | std::views::filter(negative);
145 | assert(negatives.empty());
146 | }
147 | }
148 |
149 | //Listing 2.16 Show odd numbers as stars
150 | void show_view(std::ostream& s,
151 | const std::vector>& v)
152 | {
153 | const auto gaps = 1;
154 | std::string spaces(v.back().size() * gaps, ' ');
155 | for (const auto& row : v)
156 | {
157 | s << spaces;
158 | if (spaces.size() > gaps)
159 | spaces.resize(spaces.size() - gaps);
160 | auto odds = row | std::views::transform([](int x) { return x % 2 ? '*' : ' '; });
161 | for (const auto& data : odds)
162 | {
163 | s << data << ' ';
164 | }
165 | s << '\n';
166 | }
167 | }
168 |
169 |
170 | //Pulls together all the listing gradually added to main through the text
171 | int main()
172 | {
173 | auto triangle = generate_triangle(16); //Change 16 if you want
174 |
175 | // test triangle is correct
176 | check_properties(triangle);
177 |
178 | // display left justified
179 | std::cout << triangle;
180 |
181 | show_vectors(std::cout, triangle);
182 |
183 | // Rather than sticking with a block of 6, we can find out how much we need
184 | // for example if we have more rows
185 | auto biggest = std::max_element(triangle.back().begin(), triangle.back().end());
186 | auto width = std::to_string(*biggest);
187 | show_vectors_more_general(std::cout, triangle, width.size()+2);
188 |
189 | // Show odd numbers as stars
190 | show_view(std::cout, triangle);
191 | }
192 |
193 |
--------------------------------------------------------------------------------
/Chapter3/Chapter3.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | Win32Proj
24 | {cb04cc30-c39b-4113-8a17-79a38ce001b4}
25 | Chapter21
26 | 10.0
27 | Chapter3.1
28 |
29 |
30 |
31 | Application
32 | true
33 | v143
34 | Unicode
35 |
36 |
37 | Application
38 | false
39 | v143
40 | true
41 | Unicode
42 |
43 |
44 | Application
45 | true
46 | v143
47 | Unicode
48 |
49 |
50 | Application
51 | false
52 | v143
53 | true
54 | Unicode
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | true
76 |
77 |
78 | false
79 |
80 |
81 | true
82 |
83 |
84 | false
85 |
86 |
87 |
88 | Level3
89 | true
90 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
91 | true
92 | /std:c++latest %(AdditionalOptions)
93 |
94 |
95 | Console
96 | true
97 |
98 |
99 |
100 |
101 | Level3
102 | true
103 | true
104 | true
105 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
106 | true
107 |
108 |
109 | Console
110 | true
111 | true
112 | true
113 |
114 |
115 |
116 |
117 | Level3
118 | true
119 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
120 | true
121 |
122 |
123 | Console
124 | true
125 |
126 |
127 |
128 |
129 | Level3
130 | true
131 | true
132 | true
133 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
134 | true
135 |
136 |
137 | Console
138 | true
139 | true
140 | true
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
--------------------------------------------------------------------------------
/Chapter3/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | // if you are using fmt instead, swap the last include for the next two lines and change std::format to fmt::format
4 | //#define FMT_HEADER_ONLY
5 | //#include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 |
15 | // Listing 3.1
16 | unsigned some_const_number()
17 | {
18 | return 42;
19 | }
20 |
21 | // Listing 3.2
22 | unsigned input()
23 | {
24 | unsigned number; //try a negative number!
25 | while (!(std::cin >> number))
26 | {
27 | std::cin.clear();
28 | std::cin.ignore(std::numeric_limits::max(), '\n');
29 | std::cout << "Please enter a number.\n>";
30 | }
31 | return number;
32 | }
33 |
34 | //Listing 3.3
35 | void guess_number(unsigned number)
36 | {
37 | std::cout << "Guess the number.\n>";
38 | unsigned guess = input();
39 | while (guess != number)
40 | {
41 | std::cout << guess << " is wrong. Try again\n>";
42 | guess = input();
43 | }
44 | std::cout << "Well done.\n";
45 | }
46 |
47 | // Listing 3.4 Taking optional input
48 | // Allow a way to give up
49 | std::optional read_number(std::istream& in)
50 | {
51 | unsigned result{};
52 | if (in >> result) {
53 | return result;
54 | }
55 | in.clear();
56 | in.ignore(std::numeric_limits::max(), '\n');
57 | return {};
58 | }
59 |
60 | //Listing 3.5 Allow giving up
61 | void guess_number_or_give_up(int number)
62 | {
63 | std::cout << "Guess the number.\n>";
64 | std::optional guess;
65 | while (guess = read_number(std::cin))
66 | {
67 | if (guess.value() == number)
68 | {
69 | std::cout << "Well done.\n";
70 | return;
71 | }
72 | std::cout << guess.value() << " is wrong. Try again\n>";
73 | }
74 | std::cout << "The number was " << number << "\n";
75 | }
76 |
77 |
78 | // Listing 3.9
79 | unsigned some_random_number()
80 | {
81 | std::random_device rd;
82 | std::mt19937 mt(rd());
83 | std::uniform_int_distribution<> dist(0, 100);
84 | return dist(mt);
85 | }
86 |
87 | // Listing 3.11 Function to check if a number is prime
88 | constexpr bool is_prime(int n)
89 | {
90 | //https://en.wikipedia.org/wiki/Primality_test
91 | if (n == 2 || n == 3)
92 | return true;
93 |
94 | if (n <= 1 || n % 2 == 0 || n % 3 == 0)
95 | return false;
96 |
97 | for (int i = 5; i * i <= n; i += 6)
98 | {
99 | if (n % i == 0 || n % (i + 2) == 0)
100 | return false;
101 | }
102 |
103 | return true;
104 | }
105 |
106 | // Listing 3.14, which started as listing 3.13, a function to indicate which digits are correct
107 | // * means correct in the right place
108 | // ^ means correct in the wrong place
109 | // . means wrong
110 | std::string check_which_digits_correct(unsigned number, unsigned guess)
111 | {
112 | auto ns = std::format("{:0>5}", (number));
113 | auto gs = std::format("{:0>5}", (guess));
114 | std::string matches(5, '.');
115 | // which for guesses match...
116 | for (size_t i = 0, stop = gs.length(); i < stop; ++i)
117 | {
118 | char guess_char = gs[i];
119 | if (i < ns.length() && guess_char == ns[i])
120 | {
121 | matches[i] = '*';
122 | ns[i] = '*'; // don't reuse this digit
123 | }
124 | }
125 | // now for guesses that don't match...
126 | for (size_t i = 0, stop = gs.length(); i < stop; ++i)
127 | {
128 | char guess_char = gs[i];
129 | if (i < ns.length() && matches[i] != '*')
130 | {
131 | if (size_t idx = ns.find(guess_char, 0);
132 | idx != std::string::npos)
133 | {
134 | idx = ns.find(guess_char, idx);
135 | matches[i] = '^';
136 | ns[idx] = '^';
137 | }
138 | }
139 | }
140 | return matches;
141 | }
142 |
143 | void check_properties()
144 | {
145 | static_assert(is_prime(2));
146 | static_assert(is_prime(7321));
147 | static_assert(is_prime(56897));
148 | static_assert(is_prime(41521));
149 | auto got = check_which_digits_correct(12347, 11779);
150 | assert(got == "*.^..");
151 | got = check_which_digits_correct(12345, 23451);
152 | assert(got == "^^^^^");
153 | got = check_which_digits_correct(12345, 12345);
154 | assert(got == "*****");
155 | got = check_which_digits_correct(48533, 12345);
156 | assert(got == "..^^^");
157 | got = check_which_digits_correct(98041, 41141);
158 | assert(got == "...**");
159 | assert(is_prime(17231));
160 | got = check_which_digits_correct(1723, 17231);
161 | assert(got == "^^^^.");
162 | unsigned number = 78737;
163 | got = check_which_digits_correct(number, 87739);
164 | assert(got == "^^**.");
165 |
166 | }
167 |
168 | // Listing 3.15 A much better number guessing game
169 | void guess_number_with_clues(unsigned number, auto message)
170 | {
171 | std::cout << "Guess the number.\n>";
172 | std::optional guess;
173 | while (guess = read_number(std::cin))
174 | {
175 | if (guess.value() == number)
176 | {
177 | std::cout << "Well done.\n";
178 | return;
179 | }
180 | std::cout << message(number, guess.value());
181 | std::cout << '>';
182 | }
183 | std::cout << std::format("The number was {}\n", number);
184 | }
185 |
186 |
187 | // Listing 3.12 Generating a prime number
188 | int some_prime_number()
189 | {
190 | std::random_device rd;
191 | std::mt19937 mt{ rd() };
192 | std::uniform_int_distribution dist{0, 99999};
193 | int n{};
194 | while (!is_prime(n))
195 | {
196 | n = dist(mt);
197 | }
198 | return n;
199 | }
200 |
201 | // Listing 3.19 Using all the clues
202 | void guess_number_with_more_clues(int number, auto messages)
203 | {
204 | std::cout << "Guess the number.\n>";
205 | std::optional guess;
206 | while (guess = read_number(std::cin))
207 | {
208 | if (guess.value() == number)
209 | {
210 | std::cout << "Well done.";
211 | return;
212 | }
213 | std::cout << std::format("{:0>5} is wrong. Try again\n", guess.value());
214 | for (auto message : messages)
215 | {
216 | auto clue = message(guess.value());
217 | if (clue.length())
218 | {
219 | std::cout << clue;
220 | break;
221 | }
222 | }
223 | }
224 | std::cout << std::format("The number was {:0>5}\n", (number));
225 | }
226 |
227 |
228 | int main()
229 | {
230 | check_properties();
231 |
232 | // guess a number without a clue
233 | guess_number(some_const_number());
234 |
235 | // alow a non-number to indicate defeat
236 | guess_number_or_give_up(some_const_number());
237 |
238 | // Listing 3.10
239 | // Guess any number with a clue:
240 | guess_number_with_clues(some_random_number(), [](int number, int guess) { return std::format("Your guess was too {}\n", (guess < number ? "small" : "big")); });
241 |
242 | // Listing 3.20
243 | // Guess a prime number:
244 | auto check_prime = [](int guess) {
245 | return std::string((is_prime(guess)) ? "" : "Not prime\n");
246 | };
247 |
248 | auto check_length = [](int guess) {
249 | return std::string((guess < 100000) ? "" : "Too long\n");
250 | };
251 |
252 | const int number = some_prime_number();
253 | auto check_digits = [number](int guess) {
254 | return std::format("{}\n",
255 | check_which_digits_correct(number, guess));
256 | };
257 | std::vector> messages
258 | {
259 | check_length,
260 | check_prime,
261 | check_digits
262 | };
263 | guess_number_with_more_clues(number, messages);
264 | }
265 |
--------------------------------------------------------------------------------
/Chapter4/Chapter4.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | Win32Proj
24 | {7f372fe2-1c32-42e9-bd2b-d792d14aa41d}
25 | Chapter4
26 | 10.0
27 | Chapter4
28 |
29 |
30 |
31 | Application
32 | true
33 | v143
34 | Unicode
35 |
36 |
37 | Application
38 | false
39 | v143
40 | true
41 | Unicode
42 |
43 |
44 | Application
45 | true
46 | v143
47 | Unicode
48 |
49 |
50 | Application
51 | false
52 | v143
53 | true
54 | Unicode
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | Level3
77 | true
78 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
79 | true
80 | /std:c++latest %(AdditionalOptions)
81 |
82 |
83 | Console
84 | true
85 |
86 |
87 |
88 |
89 | Level3
90 | true
91 | true
92 | true
93 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
94 | true
95 |
96 |
97 | Console
98 | true
99 | true
100 | true
101 |
102 |
103 |
104 |
105 | Level3
106 | true
107 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
108 | true
109 |
110 |
111 | Console
112 | true
113 |
114 |
115 |
116 |
117 | Level3
118 | true
119 | true
120 | true
121 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
122 | true
123 |
124 |
125 | Console
126 | true
127 | true
128 | true
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
--------------------------------------------------------------------------------
/Chapter4/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | // If are using gcc 12 or earlier or clang 15 or earlier you need to clone Howard Hinnant's library for the parse method and use it's date.h
3 | // git clone https://github.com/HowardHinnant/date
4 | // If you get errors with operator<<, you also need to use the date.h from this library
5 | // Also, add
6 | // using date::operator<<;
7 | // just before any
8 | // std::cout <<
9 | //#include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | //Listing 4.2 Duration between two time points
17 | void duration_to_end_of_year()
18 | {
19 | std::chrono::time_point now = std::chrono::system_clock::now();
20 | constexpr auto year = 2022;
21 | auto new_years_eve = std::chrono::year_month_day(
22 | std::chrono::year(year),
23 | std::chrono::month(12),
24 | std::chrono::day(31)
25 | );
26 | auto event = std::chrono::sys_days(new_years_eve);
27 | std::chrono::duration dur = event - now;
28 | std::cout << dur << " until event\n";
29 | }
30 |
31 | //Listing 4.4 Use duration to move to a coarser representation
32 | void durations()
33 | {
34 | using namespace std::chrono;
35 | auto nearly_a_day = hours{ 23 };
36 | days a_day = duration_cast(nearly_a_day);
37 | hours round_trip = a_day;
38 | std::cout << nearly_a_day << " cast to " << a_day
39 | << " and cast back to " << round_trip << '\n';
40 | }
41 |
42 | //Listing 4.5 Defining a duration
43 | void defining_a_duration()
44 | {
45 | using namespace std::chrono;
46 | using centuries = duration>;
48 | // A type alias, which we used to write like this:
49 | // typedef duration> centuries;
51 | centuries two_hundred_years = centuries(2);
52 | seconds sec = two_hundred_years;
53 | hours hrs = two_hundred_years;
54 | days day_count = duration_cast(two_hundred_years);
55 | std::cout << "Two centuries is approximately " << day_count << '\n';
56 | }
57 |
58 | //Listing 4.6 Writing and using a concept
59 | // They are called in requirements_and_concepts below, but result in a compliation failure
60 | // Try uncommenting the calls and see what happens
61 | template
62 | concept Quacks = requires(T t)
63 | {
64 | t.Quack();
65 | };
66 |
67 | template
68 | void might_be_a_duck(T x)
69 | {
70 | x.Quack();
71 | }
72 |
73 | template
74 | requires Quacks
75 | void must_be_a_duck(T x)
76 | {
77 | x.Quack();
78 | }
79 |
80 | void also_must_be_a_duck(Quacks auto x)
81 | {
82 | x.Quack();
83 | }
84 |
85 | void requirements_and_concepts()
86 | {
87 | //might_be_a_duck(42); // error left of '.Quack' must have class/struct/union
88 | //must_be_a_duck(42); //'must_be_a_duck': no matching overloaded function found, could be 'void must_be_a_duck(T)', the associated constraints are not satisfied
89 | //also_must_be_a_duck(42);
90 | }
91 |
92 |
93 | //Listing 4.7 How many days until the last day of the year?
94 | void countdown()
95 | {
96 | using namespace std::chrono;
97 | time_point now = system_clock::now();
98 | const auto ymd = year_month_day{
99 | floor(now)
100 | };
101 |
102 | auto this_year = ymd.year();
103 | auto new_years_eve = this_year / December / 31;
104 |
105 | auto event = sys_days(new_years_eve);
106 | duration dur = event - now;
107 | std::cout << duration_cast(dur)
108 | << " until event \n";
109 | }
110 |
111 | //Listing 4.8 Days until pay day
112 | void pay_day()
113 | {
114 | using namespace std::chrono;
115 |
116 | time_point now = system_clock::now();
117 | const auto ymd = year_month_day{
118 | floor(now)
119 | };
120 |
121 | auto this_year = ymd.year();
122 |
123 | auto pay_day = ymd.year() / ymd.month() / Friday[last];
124 | auto event = sys_days(pay_day);
125 | duration dur = event - now;
126 | std::cout << duration_cast(dur)
127 | << " until pay day \n";
128 | }
129 |
130 | //Listing 4.9 A testable countdown
131 | constexpr
132 | std::chrono::system_clock::duration countdown(std::chrono::system_clock::time_point start)
133 | {
134 | using namespace std::chrono;
135 |
136 | auto days_only = floor(start);
137 |
138 | const auto ymd = year_month_day{ days_only };
139 |
140 | auto this_year = ymd.year();
141 | auto new_years_eve = this_year / December / last;
142 |
143 | auto event = sys_days(new_years_eve);
144 | return event - start;
145 | }
146 |
147 | //Listing 4.12 Reading a date
148 | std::optional read_date(std::istream& in)
149 | {
150 | using namespace std::string_literals;
151 | auto format_str = "%Y-%m-%d"s;
152 | std::chrono::year_month_day date;
153 | if (in >> std::chrono::parse(format_str, date))
154 | {
155 | return date;
156 | }
157 | in.clear();
158 | std::cout << "Invalid format. Expected " <<
159 | format_str << '\n';
160 | return {};
161 | }
162 |
163 | //Listing 4.13 Countdown to any event
164 | constexpr std::chrono::system_clock::duration
165 | countdown_to(std::chrono::system_clock::time_point now,
166 | std::chrono::year_month_day date)
167 | {
168 | using namespace std::chrono;
169 | auto event = sys_days(date);
170 | return event - now;
171 | }
172 |
173 | //Listing 4.14 Countdown in local time
174 | std::chrono::system_clock::duration
175 | countdown_in_local_time(std::chrono::system_clock::time_point now,
176 | std::chrono::year_month_day date)
177 | {
178 | using namespace std::chrono;
179 | auto sys_event = zoned_time(current_zone(), local_days{ date }).get_sys_time();
180 | return sys_event - now;
181 | }
182 |
183 | //Listing 4.10 Check the countdown function
184 | void check_properties()
185 | {
186 | using namespace std::chrono;
187 | constexpr auto new_years_eve = 2022y / December / last;
188 | constexpr auto one_day_away = sys_days{ new_years_eve } - 24h;
189 | constexpr auto result = countdown(one_day_away);
190 |
191 | static_assert(duration_cast(result) == days{ 1 });
192 |
193 | // An example of another test, not included in the text of the book
194 | auto now = sys_days{ 2022y / March / 27 };
195 | auto difference = duration_cast(countdown_in_local_time(now, 2022y / March / 28));
196 | // assert(difference == 23h); // The assert works for the "Europe/London" time zone. Yours might vary
197 | }
198 |
199 | int main()
200 | {
201 | //Listing 4,2
202 | duration_to_end_of_year();
203 |
204 | //Listing 4.3
205 | durations();
206 |
207 | //Listing 4.4
208 | defining_a_duration();
209 |
210 | //Listing 4.5
211 | requirements_and_concepts();
212 |
213 | //Listing 4.6
214 | countdown();
215 |
216 | //Listing 4.8
217 | pay_day();
218 |
219 | //Listing 4.9
220 | std::cout << countdown(std::chrono::system_clock::now()) << " until event \n"; // calling listing 4.7
221 |
222 | //Listing 4.10
223 | check_properties();
224 |
225 | //Listing 4.11 Call the countdown in a loop
226 | using namespace std::chrono;
227 | for (int i = 0; i < 5; ++i)
228 | {
229 | std::this_thread::sleep_for(5000ms);
230 | auto dur = countdown(system_clock::now());
231 | std::cout << duration_cast(dur) <<
232 | " until event\n";
233 | }
234 |
235 | //Listing 4.14 A general purpose countdown
236 | std::cout << "Enter a date\n>";
237 | std::string str;
238 | std::cin >> str;
239 | std::istringstream in(str);
240 | std::optional event_date = read_date(in);
241 | if (event_date)
242 | {
243 | auto dur = countdown_to(system_clock::now(), event_date.value());
244 | std::cout << duration_cast(dur) <<
245 | " until " << event_date.value() << "\n";
246 |
247 | // Calling the function from listing 4.15
248 | // WARNING - needs the date library compiled.
249 | // See Rainer Grimm's website has instructions for compiling
250 | // and using the library (https://www.modernescpp.com/index.php/calendar-and-time-zone-in-c-20-time-zones)
251 | // Or Howard Hinnant's instructions https://howardhinnant.github.io/date/tz.html#Installation
252 | // You need a curllib and to include the tz.cpp from the src folder in your date clone
253 | // So the build command will be along the line of
254 | // clang++ --std=c++20 main..cpp -o ./main..out
255 | // /dev/date/src/tz.cpp
256 | // -Wall -I/mnt/d/dev/date/include
257 | // -I/dev/date/include
258 | // -lcurl
259 | auto local_dur = countdown_in_local_time(system_clock::now(), event_date.value());
260 | std::cout << duration_cast(local_dur) <<
261 | " until " << event_date.value() << "in local time \n";
262 | }
263 |
264 | }
265 |
--------------------------------------------------------------------------------
/Chapter5/Chapter5.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | Win32Proj
24 | {d89bf596-102a-45c9-9938-90f3af03a405}
25 | Chapter5
26 | 10.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v143
33 | Unicode
34 |
35 |
36 | Application
37 | false
38 | v143
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v143
46 | Unicode
47 |
48 |
49 | Application
50 | false
51 | v143
52 | true
53 | Unicode
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | Level3
76 | true
77 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
78 | true
79 | /std:c++latest %(AdditionalOptions)
80 |
81 |
82 | Console
83 | true
84 |
85 |
86 |
87 |
88 | Level3
89 | true
90 | true
91 | true
92 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
93 | true
94 |
95 |
96 | Console
97 | true
98 | true
99 | true
100 |
101 |
102 |
103 |
104 | Level3
105 | true
106 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
107 | true
108 |
109 |
110 | Console
111 | true
112 |
113 |
114 |
115 |
116 | Level3
117 | true
118 | true
119 | true
120 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
121 | true
122 |
123 |
124 | Console
125 | true
126 | true
127 | true
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
--------------------------------------------------------------------------------
/Chapter5/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "playing_cards.h"
4 |
5 | #include
6 | #include
7 | void check_properties()
8 | {
9 | using namespace cards;
10 |
11 | try
12 | {
13 | FaceValue value(-1);
14 | assert(false);
15 | }
16 | catch (const std::exception & )
17 | {
18 | // could assert more here, but it shows an exception was thrown
19 | }
20 |
21 | FaceValue value(1);
22 | assert(value.value() == 1);
23 |
24 | auto cards = create_deck();
25 | assert(cards.size() == 52);
26 | auto as_set = std::set(cards.begin(), cards.end());//need comparator
27 | assert(as_set.size() == 52);
28 |
29 | assert(is_guess_correct('l', { FaceValue(9), Suit::Clubs }, { FaceValue(6), Suit::Clubs }));
30 | assert(is_guess_correct('h', { FaceValue(5), Suit::Clubs }, { FaceValue(7), Suit::Spades }));
31 | assert(is_guess_correct('h', { FaceValue(3), Suit::Spades }, { FaceValue(5), Suit::Clubs }));
32 |
33 | assert(is_guess_correct('l',
34 | std::variant(Card{ FaceValue(9), Suit::Clubs }),
35 | std::variant(Card{ FaceValue(6), Suit::Clubs })
36 | )
37 | );
38 | assert(is_guess_correct('l',
39 | std::variant(Joker{}),
40 | std::variant(Card{ FaceValue(6), Suit::Clubs })
41 | )
42 | );
43 | assert(is_guess_correct('l',
44 | std::variant(Card{ FaceValue(6), Suit::Clubs }),
45 | std::variant(Joker{})
46 | )
47 | );
48 | assert(is_guess_correct('l',
49 | std::variant(Joker{}),
50 | std::variant(Joker{})
51 | )
52 | );
53 | }
54 |
55 | int main()
56 | {
57 | std::cout << "Some warm up\n";
58 | cards::CardVersion1 card{ 2, cards::Suit::Clubs }; //after Listing 5.5
59 | std::cout << card << '\n';
60 |
61 | // This is UB if we don't initialize the fields
62 | cards::Card dangerous_card;
63 | std::cout << dangerous_card <<'\n';
64 |
65 | std::cout << cards::Card{ cards::FaceValue(1), cards::Suit::Hearts } << '\n';
66 |
67 | check_properties();
68 |
69 | std::cout << "Higher/lower game - aces low\n";
70 | cards::higher_lower();
71 |
72 | std::cout << "Higher/lower game - aces low, Jokers a free go\n";
73 | cards::higher_lower_with_jokers();
74 | }
--------------------------------------------------------------------------------
/Chapter5/playing_cards.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "playing_cards.h"
5 |
6 | namespace cards
7 | {
8 | // After Listing 5.29, we noticed the repetition, so said we wcould write a function template instead of having two shuffle functions:
9 | template void shuffle_either_deck(T& deck)
10 | {
11 | std::random_device rd;
12 | std::mt19937 gen{ rd() };
13 | std::ranges::shuffle(deck, gen);
14 | }
15 |
16 |
17 | // Listing 5.11 Define operator << for a card, improved in Listing 5.12
18 | //std::ostream& operator<<(std::ostream& os, const Card& card)
19 | //{
20 | // os << card.value << " of " << static_cast(card.suit) << '\n';
21 | // return os;
22 | //}
23 |
24 | //Listing 5.14 Turn an enum value into a string
25 | std::string to_string(const Suit & suit)
26 | {
27 | using namespace std::literals;
28 | switch (suit)
29 | {
30 | case Suit::Hearts:
31 | return "Hearts"s;
32 | case Suit::Diamonds:
33 | return "Diamonds"s;
34 | case Suit::Clubs:
35 | return "Clubs"s;
36 | case Suit::Spades:
37 | return "Spades"s;
38 | default:
39 | return "?"s;
40 | }
41 | }
42 |
43 | // Not in text, used in main to show first card
44 | std::ostream& operator<<(std::ostream& os, const CardVersion1& card)
45 | {
46 | os << card.value << " of " << static_cast(card.suit);
47 | return os;
48 | }
49 |
50 | // Listing 5.13 Use the enum name rather than value, improved on in listing 5.15
51 | // reanmed stream_insertion_operator here instead of operator<< to avoid name clash
52 | // std::ostream& operator<<(std::ostream& os, const Card& card)
53 | std::ostream& stream_insertion_operator(std::ostream& os, const Card& card)
54 | {
55 | os << card.value().value() << " of " << static_cast(card.suit());
56 | return os;
57 | }
58 |
59 | //Listing 5.15 Convert card value to a string
60 | std::string to_string(const FaceValue & value)
61 | {
62 | using namespace std::literals;
63 |
64 | switch (value.value())
65 | {
66 | case 1:
67 | return "Ace"s;
68 | case 11:
69 | return "Jack"s;
70 | case 12:
71 | return "Queen"s;
72 | case 13:
73 | return "King"s;
74 | default:
75 | return std::to_string(value.value());
76 | }
77 | }
78 |
79 | //Listing 5.16 Show ace, jack, queen, king or number
80 | std::ostream& operator<<(std::ostream& os, const Card& card)
81 | {
82 | os << to_string(card.value())
83 | << " of " << to_string(card.suit());
84 | return os;
85 | }
86 |
87 |
88 | // Listing 5.17 Build a deck of cards, given as
89 | // std::array create_deck() in the book
90 | std::array create_deck_first_way()
91 | {
92 | std::array deck;
93 | auto card = deck.begin();
94 | for (auto suit :
95 | { Suit::Hearts, Suit::Diamonds, Suit::Clubs, Suit::Spades })
96 | {
97 | for (int value = 1; value <= 13; value++)
98 | {
99 | *card = Card{ FaceValue(value), suit };
100 | ++card;
101 | }
102 | }
103 | return deck;
104 | }
105 |
106 | // Listing 5.18 increment our enum
107 | Suit& operator++(Suit& suit)
108 | {
109 | // Dangerous! See https://stackoverflow.com/questions/3475152/why-cant-i-increment-a-variable-of-an-enumerated-type
110 | using IntType = typename std::underlying_type::type;
111 | if (suit == Suit::Spades)
112 | suit = Suit::Hearts;
113 | else
114 | suit = static_cast(static_cast(suit) + 1);
115 | return suit;
116 | }
117 |
118 | //Listing 5.19 Generating the deck of cards
119 | std::array create_deck()
120 | {
121 | std::array deck;
122 | int value = 1;
123 | Suit suit = Suit::Hearts;
124 | std::ranges::generate(deck, [&value, &suit]() {
125 | if (value > 13)
126 | {
127 | value = 1;
128 | ++suit;
129 | }
130 | return Card{ FaceValue(value++), suit };
131 | });
132 | return deck;
133 | }
134 |
135 | // Listing 5.22 Shuffle the cards
136 | void shuffle_deck(std::array& deck)
137 | {
138 | std::random_device rd;
139 | std::mt19937 gen{ rd() };
140 | std::ranges::shuffle(deck, gen);
141 | }
142 |
143 | // Listing 5.23 Is the guess correct?
144 | bool is_guess_correct(char guess, const Card & current, const Card & next)
145 | {
146 | return (guess == 'h' && next > current)
147 | || (guess == 'l' && next < current);
148 | }
149 |
150 | //Listing 5.24 Higher lower game
151 | void higher_lower()
152 | {
153 | auto deck = create_deck();
154 | shuffle_deck(deck);
155 |
156 | size_t index = 0;
157 | while (index + 1 < deck.size())
158 | {
159 | std::cout << deck[index]
160 | << ": Next card higher (h) or lower (l)?\n>";
161 | char c;
162 | std::cin >> c;
163 | bool ok = is_guess_correct(c, deck[index], deck[index + 1]);
164 | if (!ok)
165 | {
166 | std::cout << "Next card was " << deck[index + 1] << '\n';
167 | break;
168 | }
169 | ++index;
170 | }
171 | std::cout << "You got " << index << " correct\n";
172 | }
173 |
174 | //Listing 5.28 Create an extended deck
175 | std::array, 54> create_extended_deck()
176 | {
177 | std::array, 54> deck{ Joker{} , Joker{} };
178 | std::array cards = create_deck();
179 | std::ranges::copy(cards, deck.begin() + 2);
180 | return deck;
181 | }
182 |
183 | //Listing 5.28 Shuffle an extended deck
184 | void shuffle_deck(std::array, 54>& deck)
185 | {
186 | std::random_device rd;
187 | std::mt19937 gen{ rd() };
188 | std::ranges::shuffle(deck, gen);
189 | }
190 |
191 | //Listing 5.30 Is the guess correct for an extended deck
192 | bool is_guess_correct(char c,
193 | const std::variant& current,
194 | const std::variant& next)
195 | {
196 | if (std::holds_alternative(current) || std::holds_alternative(next))
197 | return true;
198 | Card current_card = std::get(current);
199 | Card next_card = std::get(next);
200 | return is_guess_correct(c, current_card, next_card);
201 | }
202 |
203 | //Listing 5.31 Stream out cards and jokers
204 | std::ostream& operator<<(std::ostream& os, const std::variant& card)
205 | {
206 | if (std::holds_alternative(card))
207 | os << "JOKER";
208 | else
209 | os << std::get(card);
210 | return os;
211 | }
212 |
213 | //Listing 5.32 Higher lower game with Jokers too
214 | void higher_lower_with_jokers()
215 | {
216 | auto deck = create_extended_deck();
217 | shuffle_deck(deck);
218 |
219 | size_t index = 0;
220 | while (index + 1 < deck.size())
221 | {
222 | std::cout << deck[index]
223 | << ": Next card higher (h) or lower (l)?\n>";
224 | char c;
225 | std::cin >> c;
226 | bool ok = is_guess_correct(c, deck[index], deck[index + 1]);
227 | if (!ok)
228 | {
229 | std::cout << "Next card was " << deck[index + 1] << '\n';
230 | break;
231 | }
232 | ++index;
233 | }
234 | std::cout << "You got " << index << " correct\n";
235 | }
236 | }
237 |
--------------------------------------------------------------------------------
/Chapter5/playing_cards.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | namespace cards
11 | {
12 | //Listing 5.4
13 | enum class Suit {
14 | Hearts,
15 | Diamonds,
16 | Clubs,
17 | Spades
18 | };
19 |
20 | //Listing 5.5 and 5.8, just called Card in the text
21 | struct CardVersion1
22 | {
23 | int value{};
24 | Suit suit{};
25 | };
26 |
27 | std::ostream& operator<<(std::ostream& os, const CardVersion1& card);
28 |
29 | //Listing 5.7 A type for a face value
30 | class FaceValue
31 | {
32 | public:
33 | explicit FaceValue(int value) : value_(value)
34 | {
35 | if (value_ < 1 || value_ > 13)
36 | {
37 | throw std::invalid_argument("Face value invalid");
38 | }
39 | }
40 | int value() const
41 | {
42 | return value_;
43 | }
44 | auto operator<=>(const FaceValue&) const = default;//Added in Listing 5.21 to provide less than
45 | private:
46 | int value_;
47 | };
48 |
49 | //Listing 5.10 A card class
50 | class Card
51 | {
52 | public:
53 | Card() = default;
54 | Card(FaceValue value, Suit suit) :
55 | value_(value),
56 | suit_(suit)
57 | {
58 | }
59 | FaceValue value() const { return value_; }
60 | Suit suit() const { return suit_; }
61 |
62 | //Less than considered in listing, 5.20
63 | //bool operator<(const Card&) const
64 | //{
65 | // return value < other.value&& suit < other.suit;
66 | //}
67 |
68 | // Added in Listing 5.21 to provide less than, and more besides
69 | auto operator<=>(const Card&) const = default;//means aces low
70 | private:
71 | FaceValue value_{1};
72 | Suit suit_{};
73 | };
74 |
75 |
76 | std::ostream& operator<<(std::ostream& os, const Card& card); // Listing 5.10
77 |
78 | // various other functions, defined in the source file and declared here
79 | Suit& operator++(Suit& suit);
80 | std::string to_string(const Suit & suit);
81 | std::string to_string(const FaceValue & value);
82 |
83 | std::array create_deck();
84 | void shuffle_deck(std::array& deck);
85 |
86 | bool is_guess_correct(char guess, const Card& current, const Card& next);
87 | void higher_lower();
88 |
89 | //Listing 5.26 A joker
90 | struct Joker
91 | {
92 | };
93 |
94 | std::array, 54> create_extended_deck();
95 | void shuffle_deck(std::array, 54>& deck);
96 | bool is_guess_correct(char c,
97 | const std::variant& current,
98 | const std::variant& next);
99 | std::ostream& operator<<(std::ostream& os, const std::variant& card);
100 | void higher_lower_with_jokers();
101 | }
102 |
--------------------------------------------------------------------------------
/Chapter6/Chapter6.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | Win32Proj
24 | {2707b232-4d22-487e-80eb-4e5bd325aa2a}
25 | Chapter61
26 | 10.0
27 | Chapter6
28 |
29 |
30 |
31 | Application
32 | true
33 | v143
34 | Unicode
35 |
36 |
37 | Application
38 | false
39 | v143
40 | true
41 | Unicode
42 |
43 |
44 | Application
45 | true
46 | v143
47 | Unicode
48 |
49 |
50 | Application
51 | false
52 | v143
53 | true
54 | Unicode
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | Level3
77 | true
78 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
79 | true
80 | /std:c++latest %(AdditionalOptions)
81 |
82 |
83 | Console
84 | true
85 |
86 |
87 |
88 |
89 | Level3
90 | true
91 | true
92 | true
93 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
94 | true
95 |
96 |
97 | Console
98 | true
99 | true
100 | true
101 |
102 |
103 |
104 |
105 | Level3
106 | true
107 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
108 | true
109 |
110 |
111 | Console
112 | true
113 |
114 |
115 |
116 |
117 | Level3
118 | true
119 | true
120 | true
121 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
122 | true
123 |
124 |
125 | Console
126 | true
127 | true
128 | true
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
--------------------------------------------------------------------------------
/Chapter6/Race.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "Race.h"
6 |
7 | // Listing 6.5 Draw each blob's current position
8 | void Race::draw_blobs(const std::vector& blobs)
9 | {
10 | const int bag_height = 3;
11 | const int race_height = 8;
12 | for (int y = race_height; y >= 0; --y)
13 | {
14 | std::string output = y >= bag_height ? " " : "| ";
15 | for (const auto& blob : blobs)
16 | {
17 | if (blob.total_steps() >= y)
18 | {
19 | output += "* ";
20 | }
21 | else
22 | {
23 | output += " ";
24 | }
25 | }
26 | output += y >= bag_height ? ' ' : '|';
27 | std::cout << output << '\n';
28 | }
29 | const int edges = 3;
30 | std::cout << std::string(blobs.size() * 2 + edges, '-') << '\n';
31 | }
32 |
33 | // Listing 6.7 Move all the blobs
34 | void Race::move_blobs(std::vector& blobs)
35 | {
36 | for (auto& blob : blobs)
37 | {
38 | blob.step();
39 | }
40 | }
41 |
42 | // Listing 6.8 A somewhat predictable race
43 | void Race::race(std::vector& blobs)
44 | {
45 | using namespace std::chrono;
46 | const int max = 3;
47 | std::cout << "\x1B[2J\x1B[H";
48 | for (int i = 0; i < max; ++i)
49 | {
50 | draw_blobs(blobs);
51 | move_blobs(blobs);
52 | std::this_thread::sleep_for(1000ms);
53 | std::cout << "\x1B[2J\x1B[H";
54 | }
55 | draw_blobs(blobs);
56 | }
57 |
58 | // Listing 6.15 A less predictable race
59 | void Race::race(std::vector>& blobs)
60 | {
61 | using namespace std::chrono;
62 | const int max = 3;
63 | std::cout << "\x1B[2J\x1B[H";
64 | for (int i = 0; i < max; ++i)
65 | {
66 | draw_blobs(blobs);
67 | move_blobs(blobs);
68 | std::this_thread::sleep_for(1000ms);
69 | std::cout << "\x1B[2J\x1B[H";
70 | }
71 | draw_blobs(blobs);
72 | }
73 |
74 | // Listing 6.16 Move all the blobs
75 | void Race::move_blobs(std::vector>& blobs)
76 | {
77 | for (auto& blob : blobs)
78 | {
79 | blob->step();
80 | }
81 | }
82 |
83 | // Listing 6.17 Draw each blob's current position
84 | void Race::draw_blobs(const std::vector>& blobs)
85 | {
86 | const int bag_height = 3;
87 | for (int y = 8; y >= 0; --y)
88 | {
89 | std::string output = y > 2 ? " " : "| ";
90 | for (const auto& blob : blobs)
91 | {
92 | if (blob->total_steps() >= y)
93 | output += "* ";
94 | else
95 | output += " ";
96 | }
97 | output += y >= bag_height ? ' ' : '|';
98 | std::cout << output << '\n';
99 | }
100 | std::cout << std::string(blobs.size() * 2 + 3, '-') << '\n';
101 | }
102 |
--------------------------------------------------------------------------------
/Chapter6/Race.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | namespace Race
8 | {
9 | // Listing 6.2 A base class
10 | class Blob
11 | {
12 | public:
13 | virtual ~Blob() = default;
14 |
15 | Blob() = default;
16 | Blob(Blob const&) = delete;
17 | Blob& operator=(Blob const&) = delete;
18 |
19 | virtual void step() = 0;
20 | virtual int total_steps() const = 0;
21 | };
22 |
23 | // Listing 6.3 A Blob taking constant sized steps
24 | // we noted in further considerations we could mark this as final
25 | class StepperBlob final : public Blob
26 | {
27 | int y = 0;
28 | public:
29 | void step() override
30 | {
31 | y += 2;
32 | }
33 | int total_steps() const override
34 | {
35 | return y;
36 | }
37 | };
38 |
39 | // Listing 6.11 A general purpose random blob
40 | // We started with temmplate-head
41 | // template
42 | // then consdiered using the concept std::invocable<>
43 | // for the generator in the text
44 | template T, typename U>
45 | class RandomBlob : public Blob
46 | {
47 | int y = 0;
48 | T generator;
49 | U distribution;
50 | public:
51 | RandomBlob(T gen, U dis)
52 | : generator(gen), distribution(dis)
53 | {
54 |
55 | }
56 | void step() override
57 | {
58 | y += static_cast(distribution(generator));
59 | }
60 | int total_steps() const override { return y; }
61 | };
62 |
63 | void move_blobs(std::vector& blobs);
64 | void draw_blobs(const std::vector& blobs);
65 | void race(std::vector& blobs);
66 |
67 | void race(std::vector>& blob);
68 | void move_blobs(std::vector>& blobs);
69 | void draw_blobs(const std::vector>& blob);
70 | }
--------------------------------------------------------------------------------
/Chapter6/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include "Race.h"
9 |
10 | void check_properties()
11 | {
12 | // Listing 6.4 Check steps move a blob forward
13 | Race::StepperBlob blob;
14 | blob.step();
15 | assert(blob.total_steps() == 2);
16 |
17 | // Listing 6.10 Type traits to check for special member functions
18 | static_assert(!std::is_constructible::value); // 0 for ABC
19 | // alternatively use _v instead of ::value
20 | static_assert(!std::is_constructible_v); // 0 for ABC
21 | // or is_default_constructible_v
22 | static_assert(!std::is_default_constructible_v); // 0 for ABC
23 | static_assert( std::is_destructible_v);
24 | static_assert(!std::is_copy_constructible_v);
25 | static_assert(!std::is_copy_assignable_v);
26 | static_assert(!std::is_move_constructible_v);
27 | static_assert(!std::is_move_assignable_v);
28 | static_assert( std::has_virtual_destructor_v);
29 |
30 | std::random_device rd;
31 | Race::RandomBlob rnd_blob{
32 | std::default_random_engine{ rd() },
33 | std::uniform_int_distribution{ 0, 4 }
34 | };
35 | rnd_blob.step();
36 | assert(rnd_blob.total_steps() >= 0);
37 |
38 | Race::RandomBlob another_rnd_blob{
39 | std::default_random_engine{ rd() },
40 | std::poisson_distribution{ 2 }
41 | };
42 | another_rnd_blob.step();
43 | assert(another_rnd_blob.total_steps() >= 0);
44 |
45 | // Listing 6.12 Testing with random generators and distributions
46 | Race::RandomBlob random_blob([]() { return 0; }, [](auto gen) { return gen(); });
47 | random_blob.step();
48 | assert(random_blob.total_steps() == 0);
49 | }
50 |
51 | // Listing 6.8 A warm up race
52 | void race_steppers()
53 | {
54 | std::vector blobs(4);
55 | std::random_device rd;
56 | const int max = 3;
57 | for (int i = 0; i < max; ++i)
58 | {
59 | Race::draw_blobs(blobs);
60 | Race::move_blobs(blobs);
61 | }
62 | }
63 |
64 | // Listing 6.18 Create blobs for a proper race
65 | std::vector> create_blobs(int number)
66 | {
67 | using namespace Race;
68 | std::vector> blobs;
69 | std::random_device rd;
70 | for (int i = 0; i < number/2; ++i)
71 | {
72 | blobs.emplace_back(std::make_unique());
73 | blobs.emplace_back(std::make_unique>>
75 | (
76 | std::default_random_engine{ rd() },
77 | std::uniform_int_distribution{ 0, 4 }
78 | )
79 | );
80 | }
81 | return blobs;
82 | }
83 |
84 | int main()
85 | {
86 | check_properties();
87 |
88 | // Running both races together might be confusing, so
89 | // choose a type of race; either 6.9 (just steppers) or 6.18 (various types)
90 |
91 | // Listing 6.9 A warm up race
92 | // // Uncomment and comment out 2nd race, if you want
93 | //std::vector blobs(4);
94 | //Race::race(blobs);
95 |
96 | // Listing 6.19 A proper race
97 | auto blobs = create_blobs(8);
98 | Race::race(blobs);
99 | }
100 |
--------------------------------------------------------------------------------
/Chapter7/Chapter7.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | Win32Proj
24 | {a37213e0-cc6c-40d3-b66c-6fa879df9508}
25 | Chapter7
26 | 10.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v143
33 | Unicode
34 |
35 |
36 | Application
37 | false
38 | v143
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v143
46 | Unicode
47 |
48 |
49 | Application
50 | false
51 | v143
52 | true
53 | Unicode
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | Level3
76 | true
77 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
78 | true
79 | /std:c++latest %(AdditionalOptions)
80 |
81 |
82 | Console
83 | true
84 |
85 |
86 |
87 |
88 | Level3
89 | true
90 | true
91 | true
92 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
93 | true
94 |
95 |
96 | Console
97 | true
98 | true
99 | true
100 |
101 |
102 |
103 |
104 | Level3
105 | true
106 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
107 | true
108 |
109 |
110 | Console
111 | true
112 |
113 |
114 |
115 |
116 | Level3
117 | true
118 | true
119 | true
120 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
121 | true
122 |
123 |
124 | Console
125 | true
126 | true
127 | true
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
--------------------------------------------------------------------------------
/Chapter7/Smash.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #include "Smash.h"
7 |
8 | // Listing 7.9 Transform a string to lower case
9 | // Based on https://en.cppreference.com/w/cpp/string/byte/tolower
10 | std::string str_tolower(std::string s) {
11 | std::transform(s.begin(), s.end(), s.begin(),
12 | [](unsigned char c) { return std::tolower(c); }
13 | );
14 | return s;
15 | }
16 |
17 | // Listing 7.10 Load a file into a multimap
18 | std::multimap smashing::load_dictionary(const std::string& filename)
19 | {
20 | std::multimap dictionary;
21 | std::ifstream infile{ filename };
22 | if (infile)
23 | {
24 | std::string line;
25 | while (std::getline(infile, line))
26 | {
27 | size_t position = line.find(',');
28 | if (position != std::string::npos)
29 | {
30 | std::string key{ line.substr(0, position) };
31 | std::string value{ line.substr(position + 1) };
32 | key = str_tolower(key);
33 | //dictionary.insert({ key, value }); or
34 | dictionary.emplace(key, value);
35 | }
36 | else
37 | {
38 | std::cout << "***Invalid line\n" << line << "\nin " << filename << "***\n\n";
39 | }
40 | }
41 | }
42 | else
43 | {
44 | // report error - TODO could throw instead
45 | std::cout << "Failed to open " << filename << '\n';
46 | }
47 | return dictionary;
48 | }
49 |
50 | // Listing 7.8 Find an overlapping word more efficiently
51 | std::pair smashing::find_overlapping_word(std::string word,
52 | const std::map& dictionary)
53 | {
54 | size_t offset = 1;
55 | while (offset < word.size())
56 | {
57 | auto stem = word.substr(offset);
58 | auto [lb, ub] = dictionary.equal_range(stem);
59 | if (lb != dictionary.end() &&
60 | stem == lb->first.substr(0, stem.size()))
61 | {
62 | return { lb->first, offset };
63 | }
64 | ++offset;
65 | }
66 | return { "", -1 };
67 | }
68 |
69 | // Could use
70 | //#include
71 | //#include
72 |
73 | // Listing 7.6 Simple answer smash game
74 | void smashing::simple_answer_smash(
75 | const std::map& keywords,
76 | const std::map& dictionary)
77 | {
78 | for (const auto& [word, definition] : keywords)
79 | {
80 | auto [second_word, offset] = find_overlapping_word(word, dictionary);
81 | if (offset == -1)
82 | {
83 | std::cout << "Not match for " << word << '\n';
84 | continue;
85 | }
86 | std::string second_definition = dictionary.at(second_word);
87 | std::cout << definition << "\nAND\n" << second_definition << '\n';
88 |
89 | std::string answer = word.substr(0, offset) + second_word;
90 | // Or more efficiently,
91 | //std::string answer = std::format("{}{}", std::string_view(word).substr(0, offset), second_word);
92 |
93 | std::string response;
94 | std::getline(std::cin, response);
95 | if (response == answer)
96 | {
97 | std::cout << "CORRECT!!!!!!!!!\n";
98 | }
99 | else
100 | {
101 | std::cout << answer << '\n';
102 | }
103 | std::cout << word << ' ' << second_word << "\n\n\n";
104 | }
105 | }
106 |
107 | // Listing 7.14 Better answer smash game
108 | void smashing::answer_smash(
109 | const std::multimap& keywords,
110 | const std::multimap& dictionary)
111 | {
112 | std::mt19937 gen{ std::random_device{}() };
113 | auto select_one = [&gen](auto lb, auto ub, auto dest) {
114 | std::sample(lb, ub, dest, 1, gen);
115 | };
116 | const int count = 5;
117 | std::vector> first_words;
118 | std::ranges::sample(keywords, std::back_inserter(first_words), count, gen);
119 | for (const auto& [word, definition] : first_words)
120 | {
121 | auto [second_word, second_definition, offset] = select_overlapping_word_from_dictionary(word, dictionary, select_one);
122 | if (second_word == "")
123 | {
124 | continue;
125 | }
126 | std::cout << definition << "\nAND\n" << second_definition << '\n';
127 | std::string answer = word.substr(0, offset) + second_word;
128 | std::string response;
129 | std::getline(std::cin, response);
130 | if (str_tolower(response) == answer)
131 | {
132 | std::cout << "CORRECT!!!!!!!!!\n";
133 | }
134 | else
135 | {
136 | std::cout << answer << '\n';
137 | }
138 | std::cout << word << ' ' << second_word << "\n\n\n";
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/Chapter7/Smash.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include