#include "aoc.h" namespace aoc2022 { std::vector maps; std::vector tmaps; std::vector routes; struct person { int x; int y; facing f; }; static int absolute_x(int x, const monkey_map& r) { return r.start + x; } typedef int (*yf)(int, const std::vector&); int prev_y(int y, const std::vector& ms) { return y == 0 ? ms.size() - 1 : y - 1; } int next_y(int y, const std::vector& ms) { return y == (int)ms.size() - 1 ? 0 : y + 1; } int find_next(int x, int y, const std::vector& ms, yf f) { auto ax = absolute_x(x, ms[y]); while (true) { y = f(y, ms); const monkey_map& r = ms[y]; if (ax >= r.start && ax < r.start + (int)r.line.length) { return y; } } } void mark(int x, int y, char c) { auto& r = tmaps[y]; *(r.p + x) = c; } void go_up(int s, person* p, const std::vector& ms) { if (s > 0) { int ax = absolute_x(p->x, ms[p->y]); // mark(ax, p->y, '^'); int y = find_next(p->x, p->y, ms, prev_y); const monkey_map& r = ms[y]; if (*(r.line.line + ax - r.start) == '.') { p->y = y; p->x = ax - r.start; go_up(s - 1, p, ms); } } } void go_down(int s, person* p, const std::vector& ms) { if (s > 0) { int ax = absolute_x(p->x, ms[p->y]); // mark(ax, p->y, 'v'); int y = find_next(p->x, p->y, ms, next_y); const monkey_map& r = ms[y]; if (*(r.line.line + ax - r.start) == '.') { p->y = y; p->x = ax - r.start; go_down(s - 1, p, ms); } } } void go_left(int s, person* p, const std::vector& ms) { if (s > 0) { const monkey_map& m = ms[p->y]; // mark(m.start + p->x, p->y, '<'); int x = p->x - 1 >= 0 ? p->x - 1 : m.line.length - 1; char c = *(m.line.line + x); if (c == '.') { p->x = x; go_left(s - 1, p, ms); } } } void go_right(int s, person* p, const std::vector& ms) { if (s > 0) { const monkey_map& m = ms[p->y]; // mark(m.start + p->x, p->y, '>'); int x = p->x + 1 < (int)m.line.length ? p->x + 1 : 0; char c = *(m.line.line + x); if (c == '.') { p->x = x; go_right(s - 1, p, ms); } } } void travel(person* p, const std::vector& ms, const route& r) { // char fs[] = {'>', 'v', '<', '^'}; if (r.is_step == false) { // printf("%c", fs[r.ins.f]); p->f = r.ins.f; } else { // printf("%d\n", r.ins.steps); switch (p->f) { case up: go_up(r.ins.steps, p, ms); break; case down: go_down(r.ins.steps, p, ms); break; case left: go_left(r.ins.steps, p, ms); break; case right: go_right(r.ins.steps, p, ms); break; } } } char cube_get(person* p, cube_map* cm) { int x = cm->x + p->x; int y = cm->y + p->y; auto& r = maps[y]; return *(r.line.line + x - r.start); } // p->x [0, cube_map::size) // p->y [0, cube_map::size) person wrap_up(person* p, cube_map** pcm, cube_map* cm, facing f) { person p0{p->x, p->y, f}; switch (f) { case right: p0.y = p->x; p0.x = 0; break; case down: p0.y = 0; p0.x = cube_map::size - 1 - p->x; break; case left: p0.y = cube_map::size - 1 - p->x; p0.x = cube_map::size - 1; break; case up: p0.y = cube_map::size - 1; p0.x = p->x; break; } return p0; } person wrap_down(person* p, cube_map** pcm, cube_map* cm, facing f) { person p0{p->x, p->y, f}; switch (f) { case right: p0.y = cube_map::size - 1 - p->x; p0.x = 0; break; case down: p0.y = 0; p0.x = p->x; break; case left: p0.y = p->x; p0.x = cube_map::size - 1; break; case up: p0.y = cube_map::size - 1; p0.x = cube_map::size - 1 - p->x; break; } return p0; } person wrap_left(person* p, cube_map** pcm, cube_map* cm, facing f) { person p0{p->x, p->y, f}; switch (f) { case right:p0.y = cube_map::size - 1 - p->y; p0.x = 0; break; case down: p0.y = 0; p0.x = p->y; break; case left: p0.y = p->y; p0.x = cube_map::size - 1; break; case up: p0.y = cube_map::size - 1; p0.x = cube_map::size - 1 - p->y; break; } return p0; } person wrap_right(person* p, cube_map** pcm, cube_map* cm, facing f) { person p0{p->x, p->y, f}; switch (f) { case right: p0.y = p->y; p0.x = 0; break; case down: p0.y = 0; p0.x = cube_map::size - 1 - p->y; break; case left: p0.y = cube_map::size - 1 - p->y; p0.x = cube_map::size - 1; break; case up: p0.y = cube_map::size - 1; p0.x = p->y; break; } return p0; } person wrap(person* p, cube_map** pcm, cube_map* cm, facing f) { switch(p->f) { case right: return wrap_right(p, pcm, cm, f); case down: return wrap_down(p, pcm, cm, f); case left: return wrap_left(p, pcm, cm, f); case up: return wrap_up(p, pcm, cm, f); } return *p; } void cube_up(int s, person* p, cube_map** pcm); void cube_down(int s, person* p, cube_map** pcm); void cube_left(int s, person* p, cube_map** pcm); void cube_right(int s, person* p, cube_map** pcm); void cube_up(int s, person* p, cube_map** pcm) { if (s > 0) { // mark((*pcm)->x + p->x, (*pcm)->y + p->y, '^'); if (p->y > 0) { person p0{p->x, p->y - 1, p->f}; if (cube_get(&p0, *pcm) == '.') { p->y -= 1; cube_up(s - 1, p, pcm); } } else { // wrap to up cube_map* cm = (*pcm)->sides[facing::up].m; facing f = (*pcm)->sides[facing::up].f; person p0 = wrap(p, pcm, cm, f); // char fs[] = {'>', 'v', '<', '^'}; // printf("wrap up p0[%d, %d, %c]\n", p0.x, p0.y, fs[p0.f]); if (cube_get(&p0, cm) == '.') { *p = p0; *pcm = cm; switch(p->f) { case right: cube_right(s - 1, p, pcm); break; case down: cube_down(s - 1, p, pcm); break; case left: cube_left(s - 1, p, pcm); break; case up: cube_up(s - 1, p, pcm); break; } } } } } void cube_down(int s, person* p, cube_map** pcm) { if (s > 0) { // mark((*pcm)->x + p->x, (*pcm)->y + p->y, 'v'); if (p->y < cube_map::size - 1) { person p0{p->x, p->y + 1, p->f}; if (cube_get(&p0, *pcm) == '.') { p->y += 1; cube_down(s - 1, p, pcm); } } else { // wrap to down cube_map* cm = (*pcm)->sides[facing::down].m; facing f = (*pcm)->sides[facing::down].f; person p0 = wrap(p, pcm, cm, f); // char fs[] = {'>', 'v', '<', '^'}; // printf("wrap down p0[%d, %d, %c]\n", p0.x, p0.y, fs[p0.f]); if (cube_get(&p0, cm) == '.') { *p = p0; *pcm = cm; switch(p->f) { case right: cube_right(s - 1, p, pcm); break; case down: cube_down(s - 1, p, pcm); break; case left: cube_left(s - 1, p, pcm); break; case up: cube_up(s - 1, p, pcm); break; } } } } } void cube_left(int s, person* p, cube_map** pcm) { if (s > 0) { // mark((*pcm)->x + p->x, (*pcm)->y + p->y, '<'); if (p->x > 0) { person p0{p->x - 1, p->y, p->f}; if (cube_get(&p0, *pcm) == '.') { p->x -= 1; cube_left(s - 1, p, pcm); } } else { // wrap to left cube_map* cm = (*pcm)->sides[facing::left].m; facing f = (*pcm)->sides[facing::left].f; person p0 = wrap(p, pcm, cm, f); // char fs[] = {'>', 'v', '<', '^'}; // printf("wrap left p0[%d, %d, %c]\n", p0.x, p0.y, fs[p0.f]); if (cube_get(&p0, cm) == '.') { *p = p0; *pcm = cm; switch(p->f) { case right: cube_right(s - 1, p, pcm); break; case down: cube_down(s - 1, p, pcm); break; case left: cube_left(s - 1, p, pcm); break; case up: cube_up(s - 1, p, pcm); break; } } } } } void cube_right(int s, person* p, cube_map** pcm) { if (s > 0) { // mark((*pcm)->x + p->x, (*pcm)->y + p->y, '>'); if (p->x < cube_map::size - 1) { person p0{p->x + 1, p->y, p->f}; if (cube_get(&p0, *pcm) == '.') { p->x += 1; cube_right(s - 1, p, pcm); } } else { // wrap to right cube_map* cm = (*pcm)->sides[facing::right].m; facing f = (*pcm)->sides[facing::right].f; person p0 = wrap(p, pcm, cm, f); // char fs[] = {'>', 'v', '<', '^'}; // printf("wrap right p0[%d, %d, %c]\n", p0.x, p0.y, fs[p0.f]); if (cube_get(&p0, cm) == '.') { *p = p0; *pcm = cm; switch(p->f) { case right: cube_right(s - 1, p, pcm); break; case down: cube_down(s - 1, p, pcm); break; case left: cube_left(s - 1, p, pcm); break; case up: cube_up(s - 1, p, pcm); break; } } } } } facing wrap_facing(facing f, char lr) { switch(f) { case right: return lr == 'L' ? up : down; case down: return lr == 'L' ? right : left; case left: return lr == 'L' ? down : up; case up: return lr == 'L' ? left : right; } return f; } void travel_cube(person* p, cube_map** pcm, const route& r) { // char fs[] = {'>', 'v', '<', '^'}; if (r.is_step == false) { // printf("%c", fs[r.ins.f]); p->f = wrap_facing(p->f, r.lr); } else { // printf("%d\n", r.ins.steps); switch (p->f) { case up: cube_up(r.ins.steps, p, pcm); break; case down: cube_down(r.ins.steps, p, pcm); break; case left: cube_left(r.ins.steps, p, pcm); break; case right: cube_right(r.ins.steps, p, pcm); break; } } } void cube_sample(cube_map cubs[6]) { // R2L // D3U 1 R6L // L4R cubs[0].x = 2 * cube_map::size; cubs[0].y = 0; cubs[0].sides[facing::up].m = &cubs[1]; cubs[0].sides[facing::up].f = facing::down; cubs[0].sides[facing::left].m = &cubs[2]; cubs[0].sides[facing::left].f = facing::down; cubs[0].sides[facing::right].m = &cubs[5]; cubs[0].sides[facing::right].f = facing::left; cubs[0].sides[facing::down].m = &cubs[3]; cubs[0].sides[facing::down].f = facing::down; // R1L // U6D 2 L3R // R5L cubs[1].x = 0; cubs[1].y = cube_map::size; cubs[1].sides[facing::up].m = &cubs[0]; cubs[1].sides[facing::up].f = facing::down; cubs[1].sides[facing::left].m = &cubs[5]; cubs[1].sides[facing::left].f = facing::up; cubs[1].sides[facing::right].m = &cubs[2]; cubs[1].sides[facing::right].f = facing::right; cubs[1].sides[facing::down].m = &cubs[4]; cubs[1].sides[facing::down].f = facing::up; // U1D // L2R 3 L4R // D5U cubs[2].x = cube_map::size; cubs[2].y = cube_map::size; cubs[2].sides[facing::up].m = &cubs[0]; cubs[2].sides[facing::up].f = facing::right; cubs[2].sides[facing::left].m = &cubs[1]; cubs[2].sides[facing::left].f = facing::left; cubs[2].sides[facing::right].m = &cubs[3]; cubs[2].sides[facing::right].f = facing::right; cubs[2].sides[facing::down].m = &cubs[4]; cubs[2].sides[facing::down].f = facing::right; // L1R // L3R 4 U6D // L5R cubs[3].x = 2 * cube_map::size; cubs[3].y = cube_map::size; cubs[3].sides[facing::up].m = &cubs[0]; cubs[3].sides[facing::up].f = facing::up; cubs[3].sides[facing::left].m = &cubs[2]; cubs[3].sides[facing::left].f = facing::down; cubs[3].sides[facing::right].m = &cubs[5]; cubs[3].sides[facing::right].f = facing::down; cubs[3].sides[facing::down].m = &cubs[4]; cubs[3].sides[facing::down].f = facing::down; // L4R // U3D 5 L6R // R2L cubs[4].x = 2 * cube_map::size; cubs[4].y = 2 * cube_map::size; cubs[4].sides[facing::up].m = &cubs[3]; cubs[4].sides[facing::up].f = facing::up; cubs[4].sides[facing::left].m = &cubs[2]; cubs[4].sides[facing::left].f = facing::up; cubs[4].sides[facing::right].m = &cubs[5]; cubs[4].sides[facing::right].f = facing::right; cubs[4].sides[facing::down].m = &cubs[1]; cubs[4].sides[facing::down].f = facing::up; // D4U // L5R 6 R1L // D2U cubs[5].x = 3 * cube_map::size; cubs[5].y = 2 * cube_map::size; cubs[5].sides[facing::up].m = &cubs[3]; cubs[5].sides[facing::up].f = facing::left; cubs[5].sides[facing::left].m = &cubs[4]; cubs[5].sides[facing::left].f = facing::left; cubs[5].sides[facing::right].m = &cubs[0]; cubs[5].sides[facing::right].f = facing::left; cubs[5].sides[facing::down].m = &cubs[1]; cubs[5].sides[facing::down].f = facing::right; } void cube_input(cube_map cubs[6]) { // U6D // R4L 1 L2R // L3R cubs[0].x = cube_map::size; cubs[0].y = 0; cubs[0].sides[facing::up].m = &cubs[5]; cubs[0].sides[facing::up].f = facing::right; cubs[0].sides[facing::left].m = &cubs[3]; cubs[0].sides[facing::left].f = facing::right; cubs[0].sides[facing::right].m = &cubs[1]; cubs[0].sides[facing::right].f = facing::right; cubs[0].sides[facing::down].m = &cubs[2]; cubs[0].sides[facing::down].f = facing::down; // L6R // L1R 2 R5L // U3D cubs[1].x = 2 * cube_map::size; cubs[1].y = 0; cubs[1].sides[facing::up].m = &cubs[5]; cubs[1].sides[facing::up].f = facing::up; cubs[1].sides[facing::left].m = &cubs[0]; cubs[1].sides[facing::left].f = facing::left; cubs[1].sides[facing::right].m = &cubs[4]; cubs[1].sides[facing::right].f = facing::left; cubs[1].sides[facing::down].m = &cubs[2]; cubs[1].sides[facing::down].f = facing::left; // L1R // D4U 3 D2U // L5R cubs[2].x = cube_map::size; cubs[2].y = cube_map::size; cubs[2].sides[facing::up].m = &cubs[0]; cubs[2].sides[facing::up].f = facing::up; cubs[2].sides[facing::left].m = &cubs[3]; cubs[2].sides[facing::left].f = facing::down; cubs[2].sides[facing::right].m = &cubs[1]; cubs[2].sides[facing::right].f = facing::up; cubs[2].sides[facing::down].m = &cubs[4]; cubs[2].sides[facing::down].f = facing::down; // U3D // R1L 4 L5R // L6R cubs[3].x = 0; cubs[3].y = 2 * cube_map::size; cubs[3].sides[facing::up].m = &cubs[2]; cubs[3].sides[facing::up].f = facing::right; cubs[3].sides[facing::left].m = &cubs[0]; cubs[3].sides[facing::left].f = facing::right; cubs[3].sides[facing::right].m = &cubs[4]; cubs[3].sides[facing::right].f = facing::right; cubs[3].sides[facing::down].m = &cubs[5]; cubs[3].sides[facing::down].f = facing::down; // L3R // L4R 5 R2L // U6D cubs[4].x = cube_map::size; cubs[4].y = 2 * cube_map::size; cubs[4].sides[facing::up].m = &cubs[2]; cubs[4].sides[facing::up].f = facing::up; cubs[4].sides[facing::left].m = &cubs[3]; cubs[4].sides[facing::left].f = facing::left; cubs[4].sides[facing::right].m = &cubs[1]; cubs[4].sides[facing::right].f = facing::left; cubs[4].sides[facing::down].m = &cubs[5]; cubs[4].sides[facing::down].f = facing::left; // L4R // D1U 6 D5U // L2R cubs[5].x = 0; cubs[5].y = 3 * cube_map::size; cubs[5].sides[facing::up].m = &cubs[3]; cubs[5].sides[facing::up].f = facing::up; cubs[5].sides[facing::left].m = &cubs[0]; cubs[5].sides[facing::left].f = facing::down; cubs[5].sides[facing::right].m = &cubs[4]; cubs[5].sides[facing::right].f = facing::up; cubs[5].sides[facing::down].m = &cubs[1]; cubs[5].sides[facing::down].f = facing::down; } std::pair day22(line_view file) { per_line(file, [](line_view lv) { const char* p = lv.line; if (*p == ' ' || *p == '.' || *p == '#') { maps.emplace_back(p); } if (*p >= '0' && *p <= '9') { facing f = right; while (*p != '\n') { routes.emplace_back(&p, &f); } } return true; }); for (auto& m : maps) { tmaps.emplace_back(m); } cube_map cubs[6]; // cube_sample(cubs); cube_input(cubs); // facing f = right; // for(auto& r: routes) { // r.print(&f); // } // printf("\n"); person p{0, 0, right}; for (auto& r : routes) { travel(&p, maps, r); } const monkey_map& r = maps[p.y]; int64_t n1 = (p.y + 1) * 1000 + 4 * (r.start + p.x + 1) + (int)p.f; person pc{0, 0, right}; cube_map* cm = &cubs[0]; for (auto& r : routes) { travel_cube(&pc, &cm, r); } int64_t n2 = (cm->y + pc.y + 1) * 1000 + 4 * (cm->x + pc.x + 1) + (int)pc.f; // char fs[] = {'>', 'v', '<', '^'}; // printf("person is at x[%d %d] y[%d %d] facing[%c]\n", cm->x, pc.x, cm->y, pc.y, fs[pc.f]); // for(auto&tm : tmaps) { // tm.print(); // } return {n1, n2}; } } // namespace aoc2022