diff options
Diffstat (limited to 'tracker_state.cpp')
-rw-r--r-- | tracker_state.cpp | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/tracker_state.cpp b/tracker_state.cpp new file mode 100644 index 0000000..62e4612 --- /dev/null +++ b/tracker_state.cpp | |||
@@ -0,0 +1,143 @@ | |||
1 | #include "tracker_state.h" | ||
2 | |||
3 | #include <list> | ||
4 | #include <set> | ||
5 | |||
6 | #include "ap_state.h" | ||
7 | #include "game_data.h" | ||
8 | |||
9 | bool IsDoorReachable_Helper(int door_id, const std::set<int>& reachable_rooms); | ||
10 | |||
11 | bool IsPanelReachable_Helper(int panel_id, | ||
12 | const std::set<int>& reachable_rooms) { | ||
13 | const Panel& panel_obj = GetGameData().GetPanel(panel_id); | ||
14 | |||
15 | if (!reachable_rooms.count(panel_obj.room)) { | ||
16 | return false; | ||
17 | } | ||
18 | |||
19 | for (int room_id : panel_obj.required_rooms) { | ||
20 | if (!reachable_rooms.count(room_id)) { | ||
21 | return false; | ||
22 | } | ||
23 | } | ||
24 | |||
25 | for (int door_id : panel_obj.required_doors) { | ||
26 | if (!IsDoorReachable_Helper(door_id, reachable_rooms)) { | ||
27 | return false; | ||
28 | } | ||
29 | } | ||
30 | |||
31 | if (GetAPState().IsColorShuffle()) { | ||
32 | for (LingoColor color : panel_obj.colors) { | ||
33 | if (!GetAPState().HasColorItem(color)) { | ||
34 | return false; | ||
35 | } | ||
36 | } | ||
37 | } | ||
38 | |||
39 | return true; | ||
40 | } | ||
41 | |||
42 | bool IsDoorReachable_Helper(int door_id, const std::set<int>& reachable_rooms) { | ||
43 | const Door& door_obj = GetGameData().GetDoor(door_id); | ||
44 | |||
45 | switch (GetAPState().GetDoorShuffleMode()) { | ||
46 | case DoorShuffleMode::kNone: { | ||
47 | if (!reachable_rooms.count(door_obj.room)) { | ||
48 | return false; | ||
49 | } | ||
50 | |||
51 | for (int panel_id : door_obj.panels) { | ||
52 | if (!IsPanelReachable_Helper(panel_id, reachable_rooms)) { | ||
53 | return false; | ||
54 | } | ||
55 | } | ||
56 | |||
57 | return true; | ||
58 | } | ||
59 | case DoorShuffleMode::kSimple: { | ||
60 | break; | ||
61 | } | ||
62 | case DoorShuffleMode::kComplex: { | ||
63 | break; | ||
64 | } | ||
65 | } | ||
66 | } | ||
67 | |||
68 | void TrackerState::CalculateState() { | ||
69 | reachability_.clear(); | ||
70 | |||
71 | std::set<int> reachable_rooms; | ||
72 | |||
73 | std::list<Exit> flood_boundary; | ||
74 | flood_boundary.push_back( | ||
75 | {.destination_room = GetGameData().GetRoomByName("Menu")}); | ||
76 | |||
77 | bool reachable_changed = true; | ||
78 | while (reachable_changed) { | ||
79 | reachable_changed = false; | ||
80 | |||
81 | std::list<Exit> new_boundary; | ||
82 | for (const Exit& room_exit : flood_boundary) { | ||
83 | if (reachable_rooms.count(room_exit.destination_room)) { | ||
84 | continue; | ||
85 | } | ||
86 | |||
87 | bool valid_transition = false; | ||
88 | if (room_exit.door.has_value()) { | ||
89 | if (IsDoorReachable_Helper(*room_exit.door, reachable_rooms)) { | ||
90 | valid_transition = true; | ||
91 | } else if (GetAPState().GetDoorShuffleMode() == | ||
92 | DoorShuffleMode::kNone) { | ||
93 | new_boundary.push_back(room_exit); | ||
94 | } | ||
95 | } else { | ||
96 | valid_transition = true; | ||
97 | } | ||
98 | |||
99 | if (valid_transition) { | ||
100 | reachable_rooms.insert(room_exit.destination_room); | ||
101 | reachable_changed = true; | ||
102 | |||
103 | const Room& room_obj = | ||
104 | GetGameData().GetRoom(room_exit.destination_room); | ||
105 | for (const Exit& out_edge : room_obj.exits) { | ||
106 | new_boundary.push_back(out_edge); | ||
107 | } | ||
108 | } | ||
109 | } | ||
110 | |||
111 | flood_boundary = new_boundary; | ||
112 | } | ||
113 | |||
114 | for (const MapArea& map_area : GetGameData().GetMapAreas()) { | ||
115 | for (int section_id = 0; section_id < map_area.locations.size(); | ||
116 | section_id++) { | ||
117 | const Location& location_section = map_area.locations.at(section_id); | ||
118 | bool reachable = reachable_rooms.count(location_section.room); | ||
119 | if (reachable) { | ||
120 | for (int panel_id : location_section.panels) { | ||
121 | reachable &= IsPanelReachable_Helper(panel_id, reachable_rooms); | ||
122 | } | ||
123 | } | ||
124 | |||
125 | reachability_[{map_area.id, section_id}] = reachable; | ||
126 | } | ||
127 | } | ||
128 | } | ||
129 | |||
130 | bool TrackerState::IsLocationReachable(int area_id, int section_id) { | ||
131 | std::tuple<int, int> key = {area_id, section_id}; | ||
132 | |||
133 | if (reachability_.count(key)) { | ||
134 | return reachability_.at(key); | ||
135 | } else { | ||
136 | return false; | ||
137 | } | ||
138 | } | ||
139 | |||
140 | TrackerState& GetTrackerState() { | ||
141 | static TrackerState* instance = new TrackerState(); | ||
142 | return *instance; | ||
143 | } | ||