HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Simon Says / Four tiles game, with C++ and SDL

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
sdlwithfoursimontilesgamesaysand

Problem

My take on the Prebash Challenge, "Simon Says" game, in less than 300 lines of C++ (plus the header file), using SDL for window management and drawing.

simon_says.hpp:

#ifndef CR_SIMON_SAYS_HPP
#define CR_SIMON_SAYS_HPP

#include "SDL.h"
#include 
#include 

// --------------------------------------------------------

// "cr" stands for Code-Review, not Coding-Rampage ;)
namespace cr
{

class SimonSaysGame
{
public:

    SimonSaysGame() = default;
    ~SimonSaysGame();

    SimonSaysGame(const SimonSaysGame &) = delete;
    SimonSaysGame & operator = (const SimonSaysGame &) = delete;

    bool initSDL();
    void runGameLoop();

private:

    // IDs of the four colored squares of "Simon Says".
    enum class ColorIndex
    {
        Green, Red, Yellow, Blue,

        // Number of enum entries / invalid dummy:
        Count, Invalid = Count
    };

    // Internal helpers:
    void checkAppEvents();
    void checkFailCondition();
    void renderGameBoard();
    void newRandomColors();
    void drawColoredSquare(ColorIndex colorIdx, bool halfTone);

    // Random colors drawn for the current turn.
    std::vector colorsThisTurn;

    // User input this turn.
    std::vector userInputColors;
    ColorIndex lastUserColor = ColorIndex::Invalid;

    // Number of colors the player will have to remember next time.
    // Start of with an easy 2 colors.
    unsigned int numColorsNextTurn = 2;

    // Number of colors we still draw before ending
    // the display part of the current turn.
    unsigned int numColorsLeftToDisplay = 0;

    // Pseudo-random engine:
    std::mt19937 randGenerator{ std::random_device()() };
    std::uniform_int_distribution randDist{ 0, static_cast(ColorIndex::Count) - 1 };

    // Misc helper data:
    SDL_Window   * window   = nullptr;
    SDL_Renderer * renderer = nullptr;
    bool           lostGame = false;
    bool           isDone   = false;
};

} // namespace cr {}

#endif // CR_SIMON_SAYS_HPP


simon_says.cpp:

```
#include "si

Solution

Since this is a small project, it doesn't matter much, but if you use SDL with modern C++, don't hesitate to create this kind of custom deleters for SDL objects to use with std::unique_ptr:

struct renderer_delete
{
    void operator()(SDL_Renderer* renderer) const
    {
        if (renderer != nullptr)
        {
            SDL_DestroyRenderer(renderer);
        }
    }
};

using renderer_ptr = std::unique_ptr;


Note that I am not sure whether the nullptr is needed or not, I coudn't find anything about it in less than 10 minutes. You can also create an equivalent deleter/pointer pair for SDL_Window and replace the raw pointers for window and renderer in SimonSaysGame by instances of windows_ptr and renderer_ptr.

Here, using function objects instead of function pointers for the custom deleter of std::unique_ptr has two advantages (besides all the benefits of automatic destruction thanks to RAII):

-
A function pointer type does not tell which function has to be used while renderer_delete knows it has to use SDL_DestroyRenderer. With an std::unique_ptr, you would have to give SDL_DestroyRenderer at construction.

-
If the implementation of std::unique_ptr allows empty base class optimization, then using an empty function object (which can be derived from) will result in a lighter std::unique_ptr. Since function pointers cannot be derived from, the empty base class optimization does not work with them.

To sum up: you write ten lines of code, then you get an automatic destruction of an SDL object with std::unique_ptr without any overhead, be it memory or performance overhead. That's awesome.

Code Snippets

struct renderer_delete
{
    void operator()(SDL_Renderer* renderer) const
    {
        if (renderer != nullptr)
        {
            SDL_DestroyRenderer(renderer);
        }
    }
};

using renderer_ptr = std::unique_ptr<SDL_Renderer, renderer_delete>;

Context

StackExchange Code Review Q#71734, answer score: 8

Revisions (0)

No revisions yet.