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(), ::tolower);
58
59 // Try to match different patterns
60 std::map<std::string, std::string> params;
61
62 // Pattern 1: "Place tile X at position (Y, Z)"
63 if (MatchesPlaceTilePattern(command, &params)) {
64 // Actions: Select tile, place tile
65 actions.push_back(AIAction(AIActionType::kSelectTile, params));
66 actions.push_back(AIAction(AIActionType::kPlaceTile, params));
67 actions.push_back(AIAction(AIActionType::kSaveTile, {}));
68 return actions;
69 }
70
71 // Pattern 2: "Select tile X"
72 if (MatchesSelectTilePattern(command, &params)) {
73 actions.push_back(AIAction(AIActionType::kSelectTile, params));
74 return actions;
75 }
76
77 // Pattern 3: "Open overworld editor"
78 if (MatchesOpenEditorPattern(command, &params)) {
79 actions.push_back(AIAction(AIActionType::kOpenEditor, params));
80 return actions;
81 }
82
83 // Pattern 4: Simple button clicks
84 if (absl::StrContains(cmd_lower, "click") || absl::StrContains(cmd_lower, "press")) {
85 std::regex button_pattern(R"((save|load|export|import|open)\s+(\w+))", std::regex::icase);
86 std::smatch match;
87 if (std::regex_search(command, match, button_pattern)) {
88 params["button"] = match[1].str() + " " + match[2].str();
89 actions.push_back(AIAction(AIActionType::kClickButton, params));
90 return actions;
91 }
92 }
93
94 return absl::InvalidArgumentError(
95 absl::StrCat("Could not parse AI command: ", command));
96}
97
98std::string AIActionParser::ActionToString(const AIAction& action) {
99 switch (action.type) {
101 auto it = action.parameters.find("editor");
102 if (it != action.parameters.end()) {
103 return absl::StrCat("Open ", it->second, " editor");
104 }
105 return "Open editor";
106 }
107
109 auto it = action.parameters.find("tile_id");
110 if (it != action.parameters.end()) {
111 return absl::StrCat("Select tile ", it->second);
112 }
113 return "Select tile";
114 }
115
117 auto x_it = action.parameters.find("x");
118 auto y_it = action.parameters.find("y");
119 if (x_it != action.parameters.end() && y_it != action.parameters.end()) {
120 return absl::StrCat("Place tile at position (", x_it->second, ", ", y_it->second, ")");
121 }
122 return "Place tile";
123 }
124
126 return "Save changes to ROM";
127
129 return "Verify tile placement";
130
132 auto it = action.parameters.find("button");
133 if (it != action.parameters.end()) {
134 return absl::StrCat("Click ", it->second, " button");
135 }
136 return "Click button";
137 }
138
140 return "Wait";
141
143 return "Take screenshot";
144
146 return "Invalid action";
147 }
148
149 return "Unknown action";
150}
151
153 const std::string& command,
154 std::map<std::string, std::string>* params) {
155 std::string cmd_lower = command;
156 std::transform(cmd_lower.begin(), cmd_lower.end(), cmd_lower.begin(), ::tolower);
157
158 if (!absl::StrContains(cmd_lower, "place") &&
159 !absl::StrContains(cmd_lower, "put") &&
160 !absl::StrContains(cmd_lower, "set")) {
161 return false;
162 }
163
164 if (!absl::StrContains(cmd_lower, "tile")) {
165 return false;
166 }
167
168 // Extract tile ID
169 std::regex tile_pattern(R"(tile\s+(?:id\s+)?(0x[0-9a-fA-F]+|\d+))", std::regex::icase);
170 std::smatch match;
171
172 if (std::regex_search(command, match, tile_pattern)) {
173 try {
174 int tile_id = ParseHexOrDecimal(match[1].str());
175 (*params)["tile_id"] = std::to_string(tile_id);
176 } catch (...) {
177 return false;
178 }
179 } else {
180 return false;
181 }
182
183 // Extract coordinates
184 int x, y;
185 if (ExtractCoordinates(command, &x, &y)) {
186 (*params)["x"] = std::to_string(x);
187 (*params)["y"] = std::to_string(y);
188 } else {
189 return false;
190 }
191
192 // Extract map ID if specified
193 std::regex map_pattern(R"((?:map|overworld)\s+(?:id\s+)?(\d+))", std::regex::icase);
194 if (std::regex_search(command, match, map_pattern)) {
195 (*params)["map_id"] = match[1].str();
196 } else {
197 (*params)["map_id"] = "0"; // Default to map 0
198 }
199
200 return true;
201}
202
204 const std::string& command,
205 std::map<std::string, std::string>* params) {
206 std::string cmd_lower = command;
207 std::transform(cmd_lower.begin(), cmd_lower.end(), cmd_lower.begin(), ::tolower);
208
209 if (!absl::StrContains(cmd_lower, "select") &&
210 !absl::StrContains(cmd_lower, "choose") &&
211 !absl::StrContains(cmd_lower, "pick")) {
212 return false;
213 }
214
215 if (!absl::StrContains(cmd_lower, "tile")) {
216 return false;
217 }
218
219 // Extract tile ID
220 std::regex tile_pattern(R"(tile\s+(?:id\s+)?(0x[0-9a-fA-F]+|\d+))", std::regex::icase);
221 std::smatch match;
222
223 if (std::regex_search(command, match, tile_pattern)) {
224 try {
225 int tile_id = ParseHexOrDecimal(match[1].str());
226 (*params)["tile_id"] = std::to_string(tile_id);
227 return true;
228 } catch (...) {
229 return false;
230 }
231 }
232
233 return false;
234}
235
237 const std::string& command,
238 std::map<std::string, std::string>* params) {
239 std::string cmd_lower = command;
240 std::transform(cmd_lower.begin(), cmd_lower.end(), cmd_lower.begin(), ::tolower);
241
242 if (!absl::StrContains(cmd_lower, "open") &&
243 !absl::StrContains(cmd_lower, "launch") &&
244 !absl::StrContains(cmd_lower, "start")) {
245 return false;
246 }
247
248 if (absl::StrContains(cmd_lower, "overworld")) {
249 (*params)["editor"] = "overworld";
250 return true;
251 }
252
253 if (absl::StrContains(cmd_lower, "dungeon")) {
254 (*params)["editor"] = "dungeon";
255 return true;
256 }
257
258 if (absl::StrContains(cmd_lower, "sprite")) {
259 (*params)["editor"] = "sprite";
260 return true;
261 }
262
263 if (absl::StrContains(cmd_lower, "tile16") || absl::StrContains(cmd_lower, "tile 16")) {
264 (*params)["editor"] = "tile16";
265 return true;
266 }
267
268 return false;
269}
270
271} // namespace ai
272} // namespace cli
273} // 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)
Main namespace for the application.
Definition controller.cc:20
Represents a single action to be performed in the GUI.
std::map< std::string, std::string > parameters