205 lines
5.2 KiB
C
205 lines
5.2 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#define LINE_MAX_LENGTH 256
|
|
#define MAX_ROUNDED_ROCKS 8*1024
|
|
#define MAX_HISTORY_SIZE 2048
|
|
#define abs(a) ((a) > 0 ? (a) : -(a))
|
|
#define CYCLES 1000000000
|
|
|
|
typedef enum tile {
|
|
EMPTY,
|
|
ROUNDED_ROCK,
|
|
CUBE_ROCK,
|
|
} tile_t;
|
|
|
|
typedef struct position {
|
|
int x;
|
|
int y;
|
|
} position_t;
|
|
|
|
void tilt(tile_t map[LINE_MAX_LENGTH][LINE_MAX_LENGTH], int x, int y, int dir[2]);
|
|
|
|
int main() {
|
|
char *p, *buf, c;
|
|
|
|
buf = (char *)malloc(LINE_MAX_LENGTH);
|
|
memset(buf, 0, LINE_MAX_LENGTH);
|
|
p = buf;
|
|
|
|
position_t rocks[MAX_ROUNDED_ROCKS];
|
|
int rocks_num = 0, x = 0, y = 0;
|
|
|
|
tile_t map[LINE_MAX_LENGTH][LINE_MAX_LENGTH];
|
|
|
|
while ((c = getchar()) != EOF) {
|
|
*p++ = c;
|
|
if (c == '\n') {
|
|
x = 0;
|
|
p = buf;
|
|
while (*p != '\n') {
|
|
switch (*p) {
|
|
case '.':
|
|
map[x][y] = EMPTY;
|
|
break;
|
|
case '#':
|
|
map[x][y] = CUBE_ROCK;
|
|
break;
|
|
case 'O':
|
|
map[x][y] = ROUNDED_ROCK;
|
|
rocks[rocks_num].x = x;
|
|
rocks[rocks_num].y = y;
|
|
rocks_num++;
|
|
break;
|
|
}
|
|
p++;
|
|
x++;
|
|
}
|
|
|
|
y++;
|
|
memset(buf, 0, LINE_MAX_LENGTH);
|
|
p = buf;
|
|
}
|
|
}
|
|
|
|
int dir[2] = {0, -1};
|
|
tilt(map, x, y, dir);
|
|
|
|
|
|
int part1 = 0;
|
|
for (int i = 0; i < y; i++) {
|
|
for (int j = 0; j < x; j++) {
|
|
if (map[j][i] == ROUNDED_ROCK) {
|
|
part1 += y - i;
|
|
}
|
|
}
|
|
}
|
|
|
|
printf("%i\n", part1);
|
|
|
|
tile_t ***history = (tile_t***)malloc(MAX_HISTORY_SIZE * sizeof(tile_t**));
|
|
for (int i = 0; i < MAX_HISTORY_SIZE; i++) {
|
|
history[i] = malloc(LINE_MAX_LENGTH * LINE_MAX_LENGTH * sizeof(tile_t));
|
|
}
|
|
int history_num = 0;
|
|
|
|
int offset = 0, period = 0;
|
|
for (int i = 0; i < CYCLES; i++) {
|
|
int found = 0;
|
|
for (int j = 0; j < history_num; j++) {
|
|
if (!memcmp(map, history[j], LINE_MAX_LENGTH * LINE_MAX_LENGTH * sizeof(tile_t))) {
|
|
offset = j;
|
|
period = history_num - j;
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
memcpy(history[history_num], map, LINE_MAX_LENGTH * LINE_MAX_LENGTH * sizeof(tile_t));
|
|
history_num++;
|
|
}
|
|
if (found) {
|
|
break;
|
|
}
|
|
if (i != 0) {
|
|
dir[0] = 0;
|
|
dir[1] = -1;
|
|
tilt(map, x, y, dir);
|
|
}
|
|
dir[0] = -1;
|
|
dir[1] = 0;
|
|
tilt(map, x, y, dir);
|
|
dir[0] = 0;
|
|
dir[1] = 1;
|
|
tilt(map, x, y, dir);
|
|
dir[0] = 1;
|
|
dir[1] = 0;
|
|
tilt(map, x, y, dir);
|
|
}
|
|
|
|
for (int i = 0; i < (CYCLES - history_num) % period; i++) {
|
|
dir[0] = 0;
|
|
dir[1] = -1;
|
|
tilt(map, x, y, dir);
|
|
dir[0] = -1;
|
|
dir[1] = 0;
|
|
tilt(map, x, y, dir);
|
|
dir[0] = 0;
|
|
dir[1] = 1;
|
|
tilt(map, x, y, dir);
|
|
dir[0] = 1;
|
|
dir[1] = 0;
|
|
tilt(map, x, y, dir);
|
|
}
|
|
|
|
int part2 = 0;
|
|
for (int i = 0; i < y; i++) {
|
|
for (int j = 0; j < x; j++) {
|
|
if (map[j][i] == ROUNDED_ROCK) {
|
|
part2 += y - i;
|
|
}
|
|
}
|
|
}
|
|
|
|
printf("%i\n", part2);
|
|
|
|
for (int i = 0; i < MAX_HISTORY_SIZE; i++) {
|
|
free(history[i]);
|
|
}
|
|
free(history);
|
|
free(buf);
|
|
}
|
|
|
|
void tilt(tile_t map[LINE_MAX_LENGTH][LINE_MAX_LENGTH], int x, int y, int dir[2]) {
|
|
position_t start;
|
|
int *iterate, iter_length;
|
|
if (dir[0] == 1) {
|
|
start.x = x - 1;
|
|
start.y = 0;
|
|
iterate = &start.y;
|
|
iter_length = y;
|
|
} else if (dir[0] == -1) {
|
|
start.x = 0;
|
|
start.y = 0;
|
|
iterate = &start.y;
|
|
iter_length = y;
|
|
} else if (dir[1] == 1) {
|
|
start.x = 0;
|
|
start.y = y - 1;
|
|
iterate = &start.x;
|
|
iter_length = x;
|
|
} else if (dir[1] == -1) {
|
|
start.x = 0;
|
|
start.y = 0;
|
|
iterate = &start.x;
|
|
iter_length = x;
|
|
}
|
|
|
|
position_t to_put;
|
|
for (int i = 0; i < iter_length; i++) {
|
|
*iterate = i;
|
|
memcpy(&to_put, &start, sizeof(position_t));
|
|
int *iterate_secondary = iter_length == x ? &to_put.y : &to_put.x, iter_length_secondary = iter_length == x ? y : x;
|
|
for (int j = 0; j < iter_length_secondary; j++) {
|
|
int cx = start.x - dir[0] * j;
|
|
int cy = start.y - dir[1] * j;
|
|
tile_t current_tile = map[cx][cy];
|
|
switch (current_tile) {
|
|
case EMPTY:
|
|
break;
|
|
case ROUNDED_ROCK:
|
|
map[cx][cy] = EMPTY;
|
|
map[to_put.x][to_put.y] = ROUNDED_ROCK;
|
|
to_put.x -= dir[0];
|
|
to_put.y -= dir[1];
|
|
break;
|
|
case CUBE_ROCK:
|
|
to_put.x = cx - dir[0];
|
|
to_put.y = cy - dir[1];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|