#pragma once
#include "world.hpp"
#include "common.hpp"
#include <vector>


class Prng {
    private:
        uint32_t seed;
    public:
        Prng(uint32_t);
        uint32_t get();
        uint32_t get(uint32_t, uint32_t); // min/max wrapper for convenience
        void reset(uint32_t);
};


class Maze: public Layout {
    private:
        typedef struct {
            unsigned x, y;
        } coord_t;

        bool choose_nb(unsigned, unsigned);
        bool choose_nb(const coord_t&, coord_t&, Prng*);

    public:
        Maze(unsigned, unsigned, unsigned, unsigned, Prng*, const Layout* = NULL);
};


class Sokoban: public Layout {
    private:
        typedef enum { FLOOR, WALL, PLAYER, GOAL, BOX, GOALBOX, } pos_t;
        Sokoban(unsigned, unsigned, const pos_t*, const Layout*);

    public:
        static Sokoban* getInst(Prng*, const Layout*);
        bool is_done() const;
};


class GameWorld: public Layout {
    private:
        typedef struct {
            unsigned x, y;
        } coord_t;

        unsigned choose_nb(const coord_t&, coord_t&);
        void grow(const tile_t&, unsigned, unsigned);
        Prng rnd;

        GameWorld(uint32_t, unsigned, unsigned, unsigned, unsigned, std::vector<Layout*>&);

    public:
        static void gen(uint32_t, unsigned, unsigned, unsigned, unsigned, std::vector<Layout*>&);
        bool autoroute() const { return true; }
};