#include <unordered_map>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <utility>
using std::pair;
using std::unordered_map;
using std::string;
using std::vector;
const char code_path[20] = "sub_1.txt"; //code file
const char grid_path[20] = "grid_1.txt"; //grid file
const uint32_t gridN = 256; // grid size
bool print_grid = true; //print final grid
char code[1048571];
struct error {
error() {}
error(uint32_t a, uint32_t b, string c) : error_no(a), line(b), str(c) {}
uint32_t error_no, line;
string str;
};
const uint32_t maxpeb = 15;
uint8_t grid[gridN][gridN], grid_init[gridN][gridN];
uint32_t lines, tline;
unordered_map<string, uint32_t> tag; //tag, line
vector<pair<uint32_t, string>> totag; //line, tag
vector<pair<uint32_t, uint32_t>> program; //mode, (toline)
// 0: left, 1: right, 2: move, 3: get, 4: put, 5: halt, 6: jump, 7: border, 8: pebble
void initialize() {
freopen(grid_path, "r", stdin);
memset(grid, 0x00, gridN * gridN);
uint32_t x, y, t;
while (~scanf("%u%u%u", &x, &y, &t)) {
if (x >= gridN || x >= gridN || t > maxpeb) throw error(0, 0, ""); //invalid input
grid[x][y] = t;
}
memcpy(grid_init, grid, gridN * gridN);
lines = tline = 0;
FILE* pFile = fopen(code_path, "r");
size_t p = fread(code, 1, 1048571, pFile);
code[p] = 0;
}
inline bool isg(char p) {
return (p >= 'A' && p <= 'Z' || p >= 'a' && p <= 'z' || p >= '0' && p <= '9' || p == '_');
}
void compile_line(char* p, char* end) {
tline++;
string str[2];
bool flag = false;
int8_t cr = 0;
while (p != end) {
if (isg(*p)) {
if (cr == 2 || flag) throw error(1, tline, ""); //word after tag or two words
str[cr] += *p;
if (str[cr].size() > 128) throw error(2, tline, ""); //too long
}
else if (*p == ' ') {
if (str[cr].size()) cr++;
}
else if (*p == '#' || *p == '\n' || *p == '\r' || *p == '\0') {
if (str[cr].size()) cr++;
break;
}
else if (*p == ':') {
if (!str[cr].size()) throw error(3, tline, ""); //empty tag
cr++, flag = true;
}
else throw error(4, tline, string(1, *p)); //invalid character
p++;
}
if (flag) {
if (tag.count(str[0])) throw error(5, tline, str[0]); //same-name tag
tag[str[0]] = lines--;
}
else if (str[0] == "left" && !str[1].size()) program.push_back(pair<uint32_t, uint32_t>(0, 0));
else if (str[0] == "right" && !str[1].size()) program.push_back(pair<uint32_t, uint32_t>(1, 0));
else if (str[0] == "move" && !str[1].size()) program.push_back(pair<uint32_t, uint32_t>(2, 0));
else if (str[0] == "get" && !str[1].size()) program.push_back(pair<uint32_t, uint32_t>(3, 0));
else if (str[0] == "put" && !str[1].size()) program.push_back(pair<uint32_t, uint32_t>(4, 0));
else if (str[0] == "halt" && !str[1].size()) program.push_back(pair<uint32_t, uint32_t>(5, 0));
else if (str[0] == "jump" && str[1].size()) {
program.push_back(pair<uint32_t, uint32_t>(6, 0));
totag.push_back(pair<uint32_t, string>(lines, str[1]));
}
else if (str[0] == "border" && str[1].size()) {
program.push_back(pair<uint32_t, uint32_t>(7, 0));
totag.push_back(pair<uint32_t, string>(lines, str[1]));
}
else if (str[0] == "pebble" && str[1].size()) {
program.push_back(pair<uint32_t, uint32_t>(8, 0));
totag.push_back(pair<uint32_t, string>(lines, str[1]));
}
else if (!str[0].size()) lines--;
else throw error(6, tline, str[0] + ' ' + str[1]); //invalid command
lines++;
}
void compile(char* p) {
char *prev = p, *now = p;
while (*now) {
if (*now == '\n') {
compile_line(prev, now + 1);
prev = now + 1;
}
now++;
}
compile_line(prev, now + 1);
unordered_map<string, uint32_t>::iterator it;
for (auto& i : totag) {
if ((it = tag.find(i.second)) != tag.end()) program[i.first].second = it->second;
else throw error(7, 0, i.second); //undefined tag
}
}
uint32_t tx, ty, dir;
uint32_t nowline;
uint32_t steps;
const int32_t dy[4] = {0, -1, 0, 1}; //left++
const int32_t dx[4] = {-1, 0, 1, 0};
inline bool face_border() {
return (!ty && dir == 1 || !tx && !dir || ty == gridN - 1 && dir == 3 || tx == gridN - 1 && dir == 2);
}
void execute() {
nowline = steps = tx = ty = dir = 0;
bool cont = true;
while (cont && nowline < lines) {
steps++;
switch (program[nowline].first) {
case 0: dir = (dir + 1) & 3; break;
case 1: dir = (dir + 3) & 3; break;
case 2: if (!face_border()) tx += dx[dir], ty += dy[dir]; break;
case 3: if (grid[tx][ty]) grid[tx][ty]--; break;
case 4: if (grid[tx][ty] != 15) grid[tx][ty]++; break;
case 5: cont = false; break;
case 6: nowline = program[nowline].second - 1; break;
case 7: if (face_border()) nowline = program[nowline].second - 1; break;
case 8: if (grid[tx][ty]) nowline = program[nowline].second - 1;
}
nowline++;
}
}
int main()
{
try {
initialize();
compile(code);
printf("Compiled. Commands: %u.\n", lines);
execute();
printf("Executed. Final position: (%u, %u). Steps: %u.\n", tx, ty, steps);
if (print_grid) {
for (uint32_t i = 0; i < gridN; i++) {
for (uint32_t j = 0; j < gridN; j++) printf("%hhd ", grid[i][j]);
putchar('\n');
}
}
}
catch (error e) {
puts("Complication error.");
switch (e.error_no) {
case 0: puts("Invalid grid input."); break;
case 1: printf("Line %u: Text after tag or too many arguments.", e.line); break;
case 2: printf("Line %u: Identifier is too long.", e.line); break;
case 3: printf("Line %u: Empty tag.", e.line); break;
case 4: printf("Line %u: Invalid character \'%s\'.", e.line, e.str.c_str()); break;
case 5: printf("Line %u: Redefinition of tag \'%s\'.", e.line, e.str.c_str()); break;
case 6: printf("Line %u: Invalid command \'%s\'.", e.line, e.str.c_str()); break;
case 7: printf("Undefined tag \'%s\'.", e.str.c_str());
}
}
}