yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
ai_action_parser.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <regex>
5
6#include "absl/strings/match.h"
7#include "absl/strings/numbers.h"
8#include "absl/strings/str_cat.h"
9#include "absl/strings/str_split.h"
10#include "absl/strings/string_view.h"
11#include "absl/strings/strip.h"
12
13namespace yaze {
14namespace cli {
15namespace ai {
16
17namespace {
18
19// Helper to convert hex string to int
20int ParseHexOrDecimal(const std::string& str) {
21 if (absl::StartsWith(str, "0x") || absl::StartsWith(str, "0X")) {
22 return std::stoi(str, nullptr, 16);
23 }
24 return std::stoi(str);
25}
26
27// Helper to extract coordinates like "(5, 7)" or "5,7" or "x=5 y=7"
28bool ExtractCoordinates(const std::string& text, int* x, int* y) {
29 // Pattern: (X, Y) or X,Y or x=X y=Y
30 std::regex coord_pattern(R"(\‍(?(\d+)\s*,\s*(\d+)\)?)");
31 std::smatch match;
32
33 if (std::regex_search(text, match, coord_pattern) && match.size() >= 3) {
34 *x = std::stoi(match[1].str());
35 *y = std::stoi(match[2].str());
36 return true;
37 }
38
39 // Try x=X y=Y format
40 std::regex xy_pattern(R"(x\s*=\s*(\d+).*y\s*=\s*(\d+))", std::regex::icase);
41 if (std::regex_search(text, match, xy_pattern) && match.size() >= 3) {
42 *x = std::stoi(match[1].str());
43 *y = std::stoi(match[2].str());
44 return true;
45 }
46
47 return false;
48}
49
50} // namespace
51
52absl::StatusOr<std::vector<AIAction>> AIActionParser::ParseCommand(
53 const std::string& command) {
54 std::vector<AIAction> actions;
55
56 std::string cmd_lower = command;
57 std::transform(cmd_lower.begin(), cmd_lower.end(), cmd_lower.begin(),
58 ::tolower);
59
60 // Try to match different patterns
61 std::map<std::string, std::string> params;
62
63 // Pattern 1: "Place tile X at position (Y, Z)"
64 if (MatchesPlaceTilePattern(command, &params)) {
65 // Actions: Select tile, place tile
66 actions.push_back(AIAction(AIActionType::kSelectTile, params));
67 actions.push_back(AIAction(AIActionType::kPlaceTile, params));
68 actions.push_back(AIAction(AIActionType::kSaveTile, {}));
69 return actions;
70 }
71
72 // Pattern 2: "Select tile X"
73 if (MatchesSelectTilePattern(command, &params)) {
74 actions.push_back(AIAction(AIActionType::kSelectTile, params));
75 return actions;
76 }
77
78 // Pattern 3: "Open overworld editor"
79 if (MatchesOpenEditorPattern(command, &params)) {
80 actions.push_back(AIAction(AIActionType::kOpenEditor, params));
81 return actions;
82 }
83
84 // Pattern 4: Simple button clicks
85 if (absl::StrContains(cmd_lower, "click") ||
86 absl::StrContains(cmd_lower, "press")) {
87 std::regex button_pattern(R"((save|load|export|import|open)\s+(\w+))",
88 std::regex::icase);
89 std::smatch match;
90 if (std::regex_search(command, match, button_pattern)) {
91 params["button"] = match[1].str() + " " + match[2].str();
92 actions.push_back(AIAction(AIActionType::kClickButton, params));
93 return actions;
94 }
95 }
96
97 return absl::InvalidArgumentError(
98 absl::StrCat("Could not parse AI command: ", command));
99}
100
101std::string AIActionParser::ActionToString(const AIAction& action) {
102 switch (action.type) {
104 auto it = action.parameters.find("editor");
105 if (it != action.parameters.end()) {
106 return absl::StrCat("Open ", it->second, " editor");
107 }
108 return "Open editor";
109 }
110
112 auto it = action.parameters.find("tile_id");
113 if (it != action.parameters.end()) {
114 return absl::StrCat("Select tile ", it->second);
115 }
116 return "Select tile";
117 }
118
120 auto x_it = action.parameters.find("x");
121 auto y_it = action.parameters.find("y");
122 if (x_it != action.parameters.end() && y_it != action.parameters.end()) {
123 return absl::StrCat("Place tile at position (", x_it->second, ", ",
124 y_it->second, ")");
125 }
126 return "Place tile";
127 }
128
130 return "Save changes to ROM";
131
133 return "Verify tile placement";
134
136 auto it = action.parameters.find("button");
137 if (it != action.parameters.end()) {
138 return absl::StrCat("Click ", it->second, " button");
139 }
140 return "Click button";
141 }
142
144 return "Wait";
145
147 return "Take screenshot";
148
150 return "Invalid action";
151 }
152
153 return "Unknown action";
154}
155
157 const std::string& command, std::map<std::string, std::string>* params) {
158 std::string cmd_lower = command;
159 std::transform(cmd_lower.begin(), cmd_lower.end(), cmd_lower.begin(),
160 ::tolower);
161
162 if (!absl::StrContains(cmd_lower, "place") &&
163 !absl::StrContains(cmd_lower, "put") &&
164 !absl::StrContains(cmd_lower, "set")) {
165 return false;
166 }
167
168 if (!absl::StrContains(cmd_lower, "tile")) {
169 return false;
170 }
171
172 // Extract tile ID
173 std::regex tile_pattern(R"(tile\s+(?:id\s+)?(0x[0-9a-fA-F]+|\d+))",
174 std::regex::icase);
175 std::smatch match;
176
177 if (std::regex_search(command, match, tile_pattern)) {
178 try {
179 int tile_id = ParseHexOrDecimal(match[1].str());
180 (*params)["tile_id"] = std::to_string(tile_id);
181 } catch (...) {
182 return false;
183 }
184 } else {
185 return false;
186 }
187
188 // Extract coordinates
189 int x, y;
190 if (ExtractCoordinates(command, &x, &y)) {
191 (*params)["x"] = std::to_string(x);
192 (*params)["y"] = std::to_string(y);
193 } else {
194 return false;
195 }
196
197 // Extract map ID if specified
198 std::regex map_pattern(R"((?:map|overworld)\s+(?:id\s+)?(\d+))",
199 std::regex::icase);
200 if (std::regex_search(command, match, map_pattern)) {
201 (*params)["map_id"] = match[1].str();
202 } else {
203 (*params)["map_id"] = "0"; // Default to map 0
204 }
205
206 return true;
207}
208
210 const std::string& command, std::map<std::string, std::string>* params) {
211 std::string cmd_lower = command;
212 std::transform(cmd_lower.begin(), cmd_lower.end(), cmd_lower.begin(),
213 ::tolower);
214
215 if (!absl::StrContains(cmd_lower, "select") &&
216 !absl::StrContains(cmd_lower, "choose") &&
217 !absl::StrContains(cmd_lower, "pick")) {
218 return false;
219 }
220
221 if (!absl::StrContains(cmd_lower, "tile")) {
222 return false;
223 }
224
225 // Extract tile ID
226 std::regex tile_pattern(R"(tile\s+(?:id\s+)?(0x[0-9a-fA-F]+|\d+))",
227 std::regex::icase);
228 std::smatch match;
229
230 if (std::regex_search(command, match, tile_pattern)) {
231 try {
232 int tile_id = ParseHexOrDecimal(match[1].str());
233 (*params)["tile_id"] = std::to_string(tile_id);
234 return true;
235 } catch (...) {
236 return false;
237 }
238 }
239
240 return false;
241}
242
244 const std::string& command, std::map<std::string, std::string>* params) {
245 std::string cmd_lower = command;
246 std::transform(cmd_lower.begin(), cmd_lower.end(), cmd_lower.begin(),
247 ::tolower);
248
249 if (!absl::StrContains(cmd_lower, "open") &&
250 !absl::StrContains(cmd_lower, "launch") &&
251 !absl::StrContains(cmd_lower, "start")) {
252 return false;
253 }
254
255 if (absl::StrContains(cmd_lower, "overworld")) {
256 (*params)["editor"] = "overworld";
257 return true;
258 }
259
260 if (absl::StrContains(cmd_lower, "dungeon")) {
261 (*params)["editor"] = "dungeon";
262 return true;
263 }
264
265 if (absl::StrContains(cmd_lower, "sprite")) {
266 (*params)["editor"] = "sprite";
267 return true;
268 }
269
270 if (absl::StrContains(cmd_lower, "tile16") ||
271 absl::StrContains(cmd_lower, "tile 16")) {
272 (*params)["editor"] = "tile16";
273 return true;
274 }
275
276 return false;
277}
278
279} // namespace ai
280} // namespace cli
281} // namespace yaze
static absl::StatusOr< std::vector< AIAction > > ParseCommand(const std::string &command)
static bool MatchesSelectTilePattern(const std::string &command, std::map< std::string, std::string > *params)
static bool MatchesPlaceTilePattern(const std::string &command, std::map< std::string, std::string > *params)
static bool MatchesOpenEditorPattern(const std::string &command, std::map< std::string, std::string > *params)
static std::string ActionToString(const AIAction &action)
bool ExtractCoordinates(const std::string &text, int *x, int *y)
Represents a single action to be performed in the GUI.
std::map< std::string, std::string > parameters