#include <cstdlib>
#include <iostream>
#include <vector>

struct Maze
{
    enum Cell
    {
        INVALID,
        EDGE,
        WALL,
        PATH,
    };
    Maze(int w, int h, Cell initial)
    :
        w{w},
        h{h},
        cells(w * h, initial)
    {
        for (auto y = 0; y < h; y += h-1)
        for (auto x = 0; x < w; x += 1)
            cells[w * y + x] = EDGE;
        for (auto y = 0; y < h; y += 1)
        for (auto x = 0; x < w; x += w-1)
            cells[w * y + x] = EDGE;
    }
    Cell & operator ()(int x, int y)
    {
        static auto invalid = INVALID; // Yes, naughty.
        if (0 <= x && x < w && 0 <= y && y < h)
            return cells[w * y + x];
        return invalid;
    }
    void print() const
    {
        for (auto y = 0; y < h; ++y, std::cout << '\n')
        for (auto x = 0; x < w; ++x)
            std::cout << (cells[w * y + x] == PATH ? "  " : "██");
    }
    int w;
    int h;
    std::vector<Cell> cells;
};

Maze hunt_and_kill(int w, int h, unsigned seed)
{
    auto maze = Maze(w, h, Maze::WALL);
    std::srand(seed);
    // Entrance.
    maze(1, 0) = maze(1, 1) = Maze::PATH;
    // Interior.
    auto cx = 1;
    auto cy = 1;
    auto done = false;
    while (!done)
    {
        // Find number of neighbors.
        auto n = 0;
        for (auto ny = -2; ny <= 2; ny += 2)
        for (auto nx = -2; nx <= 2; nx += 2)
            if (!nx != !ny)
            if (maze(cx+nx, cy+ny) == Maze::WALL)
                ++n;
        // If we have neighbors, carve path to random one.
        if (n != 0)
        {
            n = std::rand() % n;
            for (auto ny = -2; ny <= 2; ny += 2)
            for (auto nx = -2; nx <= 2; nx += 2)
                if (!nx != !ny)
                if (maze(cx+nx, cy+ny) == Maze::WALL && n-- == 0)
                {
                    maze(cx+nx/2, cy+ny/2) = maze(cx+nx, cy+ny) = Maze::PATH;
                    cx = cx+nx;
                    cy = cy+ny;
                }
            continue;
        }
        // No neighbors, done unless there's an uncarved cell to restart at.
        done = true;
        for (auto ry = 1; ry < h && done; ry += 2)
        for (auto rx = 1; rx < w && done; rx += 2)
            if (maze(rx, ry) == Maze::WALL)
                for (auto ny = -2; ny <= 2 && done; ny += 2)
                for (auto nx = -2; nx <= 2 && done; nx += 2)
                    if (!nx != !ny)
                    if (maze(rx+nx, ry+ny) == Maze::PATH)
                    {
                        cx = rx+nx;
                        cy = ry+ny;
                        done = false;
                    }
    }
    // Exit.
    w -= (w + 1) % 2;
    maze(w-2, h-2) = maze(w-2, h-1) = Maze::PATH;
    return maze;
}

int main()
{
    auto seed = 0;
    auto maze = hunt_and_kill(80/2, 24-1, seed);
    maze.print();
}