I made a simple 8 puzzle which is 3x3 grids unsorted. The user has to move only one number at any direction, which is next to an empty tile. If the user sorted numbers, he/she wins the game, otherwise he/she needs to restart the game.The game seems to work fine, but I would like to know how I can improve it further.#include <iostream>#include <cassert>#include <random>#include <algorithm>#include <array>#include <map>#include <numeric>#include <conio.h>#define _USE_MATH_DEFINES#include <cmath>#ifndef M_PI#define M_PI 3.141592653589793238462643383f#endif namespace{    enum KeyType    {        KUp = 72,        KRight = 77,        KLeft = 75,        KDown = 80    };    enum  Direction    {        Up,        Down,        Left,        Right,        DirectionCount    };    std::mt19937 randomEngine()    {        std::array<std::mt19937::result_type, std::mt19937::state_size> seed_data;        thread_local std::random_device source;        std::generate(std::begin(seed_data), std::end(seed_data), std::ref(source));        std::seed_seq seeds(std::begin(seed_data), std::end(seed_data));        thread_local std::mt19937 seeded_engine(seeds);        return seeded_engine;    }    float radian(Direction direction)    {        constexpr static std::array<float, Direction::DirectionCount> Radians        {            M_PI,       // Up            0,          // Down            -M_PI / 2,  // Left            M_PI / 2    // Right        };        return Radians[direction];    }}struct Vector{    Vector(unsigned int x, unsigned int y)         :x(x)        , y(y)    {}    unsigned int x, y;};class Puzzle{private:    constexpr static auto MaxTiles = 9u;    constexpr static auto Columns = 3u;    using Pair = std::pair<Vector, unsigned int>;    using TileHolder = std::array<char, MaxTiles>;public:    Puzzle()    {        std::iota(mTiles.begin(), mTiles.end(), '1');        mTiles.back() = ' ';        thread_local auto random = randomEngine();        std::shuffle(mTiles.begin(), mTiles.end(), random);    }    void update(Direction direction)    {        const auto& coord = getEmptyTileCoordinates();        auto x = static_cast<unsigned int>(coord.first.x - std::sin(radian(direction)));        auto y = static_cast<unsigned int>(coord.first.y - std::cos(radian(direction)));        if (x < 0u || x >= 3u || y < 0u || y >= 3u) return;        std::swap(mTiles[y * Columns + x], mTiles[coord.second]);    }    bool isSorted() const    {        return std::is_sorted(mTiles.begin(), mTiles.end() - 1);    }private:    Pair getEmptyTileCoordinates() const    {        auto found = std::find(mTiles.cbegin(), mTiles.cend(), ' ');        assert(found != mTiles.cend());        auto index = std::distance(mTiles.cbegin(), found);        auto coord = Vector(index % Columns, index / Columns);        return{ coord, index };    }    void draw(std::ostream& stream) const    {        for (const auto& tile : mTiles)        {            auto index = &tile - &*(mTiles.begin());            stream << tile << ((index % Columns == Columns - 1) ? '\n' : ' ');        }    }    friend std::ostream& operator<<(std::ostream& stream, const Puzzle& puzzle)    {        puzzle.draw(stream);        return stream;    }private:    TileHolder mTiles;};class Game {    using KeysMap = std::map<int, Direction>;public:    Game()    {        mKeyBinding.emplace(KeyType::KUp, Direction::Up);        mKeyBinding.emplace(KeyType::KDown, Direction::Down);        mKeyBinding.emplace(KeyType::KLeft, Direction::Left);        mKeyBinding.emplace(KeyType::KRight, Direction::Right);    }    void gameLoop()    {        display();        while (!mPuzzle.isSorted())        {            if (_kbhit())            {                userInput();                display();            }        }        result();    }private:    void userInput()    {        auto found = mKeyBinding.find(_getch());        if (found != mKeyBinding.end())            mPuzzle.update(found->second);    }    void display()    {        system(cls);        std::cout << mPuzzle;    }    void result()    {        std::cout << yey: it sorted!;        std::cin.ignore();    }    Puzzle mPuzzle;    KeysMap mKeyBinding;};int main(){    Game game;    game.gameLoop();}
Simple 8 Puzzle - ASCII
c++;c++11;game;sliding tile puzzle
I'll start with update.Since getEmptyTileCoordinates() returns a Pair, you can store that in coord instead of using a reference:auto coord(getEmptyTileCoordinates());For the direction offsets, you can just have arrays that store the x and y offsets for a particular direction rather than doing the math with floats.// in local namespaceconst int x_offset[] = {0, 0, -1, +1};  // Up, Down, Left, Rightconst int y_offset[] = {-1, +1, 0, 0};// in updateunsigned x = coord.first.x + x_offset[direction];unsigned y = coord.first.y + y_offset[direction];That would allow you to get rid of your radian function.  And since x and y are unsigned, they'll never be less than zero and you don't need to check them for that (although the compiler will know this and likely will optimize away those comparisons).drawYou're doing a lot of work in draw to determine when to use a newline instead of a space.  This can be simplified by using a counter.void draw(std::ostream& stream) const{    int column = 0;    for (const auto& tile : mTiles)    {        column = (column + 1) % Columns;        stream << tile << (column == 0 ? '\n' : ' ');    }}