summaryrefslogtreecommitdiffhomepage
path: root/src/path-search.hpp
blob: 5a8a0f9e17d3747479b871cff793b9e438d2f935 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#pragma once
#include "global-coords.hpp"
#include "object-id.hpp"
#include "rotation.hpp"
#include "world.hpp"
#include "compat/function2.fwd.hpp"
#include "path-search-result.hpp"
#include "compat/int-hash.hpp"
#include <bit>
#include <array>
#include <Magnum/Math/Vector2.h>
#include <Magnum/DimensionTraits.h>
#include <tsl/robin_hash.h>

namespace Corrade::Containers {
//template<typename T> class Optional;
//template<typename T, typename U> class Pair;
template<typename T> class ArrayView;
} // namespace Corrade::Containers

namespace floormat {

struct world;
struct object;
struct chunk;

struct path_search_result;

enum class path_search_continue : bool { pass = false, blocked = true };

struct astar
{
    fm_DECLARE_DELETED_COPY_ASSIGNMENT(astar);

    struct position
    {
        global_coords coord;
        Vector2b offset;

        bool operator==(const position&) const = default;
    };
    struct visited
    {
        uint32_t dist = (uint32_t)-1;
        uint32_t prev = (uint32_t)-1;
        global_coords coord;
        Vector2b offset;
        bool expanded = false;
    };
    struct hash_op
    {
        size_t operator()(position coord) const;
    };
    void reserve(size_t capacity)
    {
        nodes.reserve(capacity);
        indexes.reserve(capacity);
        Q.reserve(capacity);
    }
    astar()
    {
        constexpr auto capacity = TILE_COUNT * 16;
        indexes.max_load_factor(.4f);
        reserve(capacity);
    }
    void clear()
    {
        nodes.clear();
        indexes.clear();
        Q.clear();
    }

    std::vector<visited> nodes;
    tsl::robin_map<position, uint32_t, hash_op> indexes;
    std::vector<uint32_t> Q;
};

class path_search final
{
    friend struct path_search_result;

public:
    static constexpr int subdivide_factor = 4;
    static constexpr auto div_size = iTILE_SIZE2 / subdivide_factor;
    static constexpr auto min_size = div_size / 2;

    struct neighbors final
    {
        auto begin() const { return data.data(); }
        auto end() const { return data.data() + size; }

        std::array<global_coords, 5> data;
        uint8_t size = 0;

        operator ArrayView<const global_coords>() const;
    };

    template<typename T> struct bbox { VectorTypeFor<2, T> min, max; };

    using pred = fu2::function_view<path_search_continue(collision_data) const>;

    struct astar astar;

    static const pred& never_continue() noexcept;
    static const pred& always_continue() noexcept;

    // todo add simple bresenham short-circuit
    path_search_result Dijkstra(world& w, Vector2ub own_size, object_id own_id, global_coords from, Vector2b from_offset, global_coords to, Vector2b to_offset, const pred& p = never_continue());
    path_search_result Dijkstra(world& w, const object& obj, global_coords to, Vector2b to_offset, const pred& p = never_continue());

    static bool is_passable_1(chunk& c, Vector2 min, Vector2 max, object_id own_id, const pred& p = never_continue());
    static bool is_passable_(chunk* c0, const std::array<world::neighbor_pair, 8>& neighbors,
                             Vector2 min, Vector2 max, object_id own_id, const pred& p = never_continue());
    static bool is_passable(world& w, chunk_coords_ ch0, Vector2 min, Vector2 max, object_id own_id, const pred& p = never_continue());
    static bool is_passable(world& w, global_coords coord, Vector2b offset, Vector2ub size, object_id own_id, const pred& p = never_continue());
    static bool is_passable(world& w, chunk_coords_ ch0, const bbox<float>& bb, object_id own_id, const pred& p = never_continue());

    // todo move to test/path-search.cpp
    static bbox<float> neighbor_tile_bbox(Vector2i coord, Vector2ub own_size, Vector2ub div, rotation r);
    static neighbors neighbor_tiles(world& w, global_coords coord, Vector2ub size, object_id own_id, const pred& p = never_continue());
};

} // namespace floormat