Monday, 8 July 2024

Learn C++ by Example: Chapter 9

I have been sharing some details about my latest book "Learn C++ by Example", and gave an overview of chapter 8 last time. There are 9 chapters, so this is the final blog about the book's contents.




You can buy my book directly here: http://mng.bz/AdAQ - or just go look at the table of contents. You can also buy it from Amazon: https://amzn.to/4dMJ0aG

The final chapter explains parameter packs and uses the std::visit pattern. Since we're on the last chapter, we also get opportunities to practice variants, std::format and ranges. We used a std::variant back in chapter 5, to hold either a Card or a Joker. Chapter 5 noted a variant's definition:

template <class... Types>
class variant;

We learnt that the dots are called a parameter pack, allowing us to use zero or more template arguments. We used a variant with two types, a Card or a Joker, back then, but we could have more than two types. We used std::holds_alternative<Joker> to detect if a card was actually a Joker. With more than a couple of types, this can get clumsy, so this final chapter shows another approach.

We explore how to write variadic templates, i.e. templates with at least one parameter pack, looking at fold expressions. Jonathan Müller's blog has some great examples if you want more details. The three dots in the template head indicate a parameter pack,  and we use three further dots to unpack the parameters, for example

template<typename... Ts>
auto add(const Ts&... tail)
{
    return (... + tail);
}

allows us to call add(1, 2) or add(1, 2, 3). You need to watch out for left or right association, for some operators. 

The mini-project in this chapter is building a slot machine. We build up three "reels" (vectors) of numbers, rather than more traditional fruits or similar for slot machines. In fact, we use the triangle numbers. If you can't remember what they are, read my book or find a good online resource.  Just think of arranging snooker balls in a triangle and counting how many you have: 1, 3, 6, 10, 15, 21, ...

If you consider the last digit of each triangle number, a pattern emerges, and repeats. The last digit will be 0, 1, 3, 5, 6 or 8 and nothing else. 8s and 3s are less likely than the others. If we set up three reels with these numbers and compare the final digits we can give a payout, as a slot machine would. Two matches gets a small payout, and all three gets more. In fact, we give a higher payout for 8s and 3s since they are less likely. Trying to calculate a fair payout was a challenge, so I spared the readers and used an approximation. 

The first game just lets the reels spin. How do we spin the reels? We shuffle the vectors first, so we don't know what's going to happen initially, but after that the reels want to move forward by a random amount. And yes, "That's a rotate".  (Ólafur Waage's blog "Everything is a rotate" will explain that meme if you've not heard it before).

Because the reels stay in order, we can display the previous and next numbers above and below the current line, and allow a hold or nudge something like a real slot machine. By adding three structs, 

#include <variant>
struct Hold {};
struct Nudge {};
struct Spin {};
using options = std::variant<Hold, Nudge, Spin>;

we can extend the game relatively easily.  One approach is using a struct with an overloaded method for each type:

struct RollMethod
{
    void operator()(Hold)
    void operator()(Nudge)
    void operator()(Spin)
};

This is far better than checking std::holds_alternative, for each type. The chapter goes on to explain the Overload pattern and how to use std::visit. We need a different function for each type, or double dispatch. Have an experiment, and see if you can code this up.

The chapter also briefly mentions C++17's execution policies, mutable lambdas and std::views::zip, as well as giving extra practice with algorithms and std::format

So, some questions for you
  1. Can you find the repeating pattern of the final digits of the triangle numbers? (Write code to generate them, and have a look).
  2. Can you rotate a vector by a random amount? (It seems a few people can't remember how to use std::rotate, so practice).
  3. Can you use std::visit for the three different options, hold, nudge or spin? 
I've now shared an overview of each chapter. Have a play around with the mini-projects and get in touch if you can think of other good learning examples. 

 


 

 



No comments:

Post a Comment