Files

391 lines
12 KiB
C
Raw Permalink Normal View History

2022-12-24 20:39:09 +01:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_SIZE 256
#define MAX_MAP_SIZE 1024
#define MAX_BLIZZARDS 4096
#define MAX_BLIZZARDS_HISTORY 4096
#define FIFO_MAX 32*1024*1024
enum direction {
RIGHT,
DOWN,
LEFT,
UP
};
typedef struct blizzard {
int startPos[2];
enum direction dir;
} BLIZZARD;
int moves[5][2] = {
{1,0},
{0,1},
{-1,0},
{0,-1},
{0,0}
};
int dist(int [2], int [2]);
int main() {
char buf[BUFFER_SIZE], *p, c;
memset(buf, 0, BUFFER_SIZE);
p = buf;
int y = 0, x = 0;
int map[MAX_MAP_SIZE][MAX_MAP_SIZE];
int startPos[2], endPos[2];
BLIZZARD blizzards[MAX_BLIZZARDS];
int blizzard_count = 0;
while ((c = getchar()) != EOF) {
*p++ = c;
if (c == '\n') {
p = buf;
while (*p != '\n') {
if (p-buf+1 > x) x = p - buf + 1;
if (*p == '#') {
map[p-buf][y] = 1;
} else if (*p == '.') {
map[p-buf][y] = 0;
if (y == 0) {
startPos[0] = p - buf;
startPos[1] = y;
}
} else {
blizzards[blizzard_count].startPos[0] = p - buf;
blizzards[blizzard_count].startPos[1] = y;
switch (*p) {
case '>':
blizzards[blizzard_count].dir = RIGHT;
break;
case 'v':
blizzards[blizzard_count].dir = DOWN;
break;
case '<':
blizzards[blizzard_count].dir = LEFT;
break;
case '^':
blizzards[blizzard_count].dir = UP;
break;
}
blizzard_count++;
}
p++;
}
y++;
memset(buf, 0, BUFFER_SIZE);
p = buf;
}
}
// Get exit point
for (int i = 0; i < x; i++) {
if (map[i][y-1] == 0) {
endPos[0] = i;
endPos[1] = y - 1;
break;
}
}
int times[3];
int (*fifo)[3], fifo_count;
fifo = (int(*)[3])malloc(FIFO_MAX * sizeof(int[3]));
fifo[0][0] = startPos[0];
fifo[0][1] = startPos[1];
fifo[0][2] = 0;
fifo_count++;
// We will calculate the blizzardmap at each timepoint
int ***blizzardMap = (int***)malloc(MAX_BLIZZARDS_HISTORY * sizeof(int**));
for (int i = 0; i < MAX_BLIZZARDS_HISTORY; i++) {
blizzardMap[i] = (int**)malloc(x * sizeof(int*));
for (int j = 0; j < x; j++) {
blizzardMap[i][j] = (int*)malloc(y * sizeof(int));
memset(blizzardMap[i][j], 0, y * sizeof(int));
}
}
int blizzard_history_count = 0;
for (;;) {
if (fifo_count == 0) {
printf("PROBLEM\n");
break;
}
// Pop next element from FIFO
int currPos[2], currTime;
currPos[0] = fifo[0][0];
currPos[1] = fifo[0][1];
currTime = fifo[0][2];
fifo_count--;
if (currPos[0] == endPos[0] && currPos[1] == endPos[1]) {
times[0] = currTime;
break;
}
// Shift back elements
for (int i = 0; i < fifo_count; i++) {
fifo[i][0] = fifo[i+1][0];
fifo[i][1] = fifo[i+1][1];
fifo[i][2] = fifo[i+1][2];
}
// Calculate each blizzard's position at currTime + 1
if (blizzard_history_count < currTime + 1) {
for (int j = 0; j < blizzard_count; j++) {
int newX, newY;
if (moves[blizzards[j].dir][0] >= 0) {
newX = 1 + ((blizzards[j].startPos[0] + (currTime+1) * (moves[blizzards[j].dir][0]) - 1) % (x-2));
} else {
newX = (x-2) - (((x-2) - blizzards[j].startPos[0] + (currTime+1) * abs(moves[blizzards[j].dir][0])) % (x-2));
}
if (moves[blizzards[j].dir][1] >= 0) {
newY = 1 + ((blizzards[j].startPos[1] + (currTime+1) * (moves[blizzards[j].dir][1]) - 1) % (y-2));
} else {
newY = (y-2) - (((y-2) - blizzards[j].startPos[1] + (currTime+1) * abs(moves[blizzards[j].dir][1])) % (y-2));
}
blizzardMap[currTime+1][newX][newY] = 1;
}
blizzard_history_count++;
}
// Check each direction from position
for (int i = 0; i < 5; i++) {
int xp = currPos[0] + moves[i][0];
int yp = currPos[1] + moves[i][1];
// Hitting a wall or walking off the map is not healthy
if (yp < 0 || map[xp][yp] == 1) {
continue;
}
// We cannot step on a tile where there will be a blizzard
// the next round
if (blizzardMap[currTime+1][xp][yp]) {
continue;
}
// Stepping back to the entry point is pointless
if (xp == startPos[0] && yp == startPos[1] && i != 4) {
continue;
}
// There's no need to check the same position twice in the same round
int inFifo = 0;
for (int j = 0; j < fifo_count; j++) {
if (fifo[j][0] == xp && fifo[j][1] == yp && fifo[j][2] == currTime + 1) {
inFifo = 1;
break;
}
}
if (inFifo) {
continue;
}
fifo[fifo_count][0] = xp;
fifo[fifo_count][1] = yp;
fifo[fifo_count][2] = currTime + 1;
fifo_count++;
}
}
printf("To the end: %i\n", times[0]);
// Reset FIFO
fifo_count = 0;
fifo[0][0] = endPos[0];
fifo[0][1] = endPos[1];
fifo[0][2] = times[0];
fifo_count++;
for (;;) {
if (fifo_count == 0) {
printf("PROBLEM\n");
break;
}
// Pop next element from FIFO
int currPos[2], currTime;
currPos[0] = fifo[0][0];
currPos[1] = fifo[0][1];
currTime = fifo[0][2];
fifo_count--;
if (currPos[0] == startPos[0] && currPos[1] == startPos[1]) {
times[1] = currTime;
break;
}
// Shift back elements
for (int i = 0; i < fifo_count; i++) {
fifo[i][0] = fifo[i+1][0];
fifo[i][1] = fifo[i+1][1];
fifo[i][2] = fifo[i+1][2];
}
// Calculate each blizzard's position at currTime + 1
if (blizzard_history_count < currTime + 1) {
for (int j = 0; j < blizzard_count; j++) {
int newX, newY;
if (moves[blizzards[j].dir][0] >= 0) {
newX = 1 + ((blizzards[j].startPos[0] + (currTime+1) * (moves[blizzards[j].dir][0]) - 1) % (x-2));
} else {
newX = (x-2) - (((x-2) - blizzards[j].startPos[0] + (currTime+1) * abs(moves[blizzards[j].dir][0])) % (x-2));
}
if (moves[blizzards[j].dir][1] >= 0) {
newY = 1 + ((blizzards[j].startPos[1] + (currTime+1) * (moves[blizzards[j].dir][1]) - 1) % (y-2));
} else {
newY = (y-2) - (((y-2) - blizzards[j].startPos[1] + (currTime+1) * abs(moves[blizzards[j].dir][1])) % (y-2));
}
blizzardMap[currTime+1][newX][newY] = 1;
}
blizzard_history_count++;
}
// Check each direction from position
for (int i = 0; i < 5; i++) {
int xp = currPos[0] + moves[i][0];
int yp = currPos[1] + moves[i][1];
// Hitting a wall or walking off the map is not healthy
if (yp == y || map[xp][yp] == 1) {
continue;
}
// We cannot step on a tile where there will be a blizzard
// the next round
if (blizzardMap[currTime+1][xp][yp]) {
continue;
}
// Stepping back to the entry point is pointless
if (xp == endPos[0] && yp == endPos[1] && i != 4) {
continue;
}
// There's no need to check the same position twice in the same round
int inFifo = 0;
for (int j = 0; j < fifo_count; j++) {
if (fifo[j][0] == xp && fifo[j][1] == yp && fifo[j][2] == currTime + 1) {
inFifo = 1;
break;
}
}
if (inFifo) {
continue;
}
fifo[fifo_count][0] = xp;
fifo[fifo_count][1] = yp;
fifo[fifo_count][2] = currTime + 1;
fifo_count++;
}
}
printf("To the start: %i\n", times[1]);
fifo_count = 0;
fifo[0][0] = startPos[0];
fifo[0][1] = startPos[1];
fifo[0][2] = times[1];
fifo_count++;
for (;;) {
if (fifo_count == 0) {
printf("PROBLEM\n");
break;
}
// Pop next element from FIFO
int currPos[2], currTime;
currPos[0] = fifo[0][0];
currPos[1] = fifo[0][1];
currTime = fifo[0][2];
fifo_count--;
if (currPos[0] == endPos[0] && currPos[1] == endPos[1]) {
times[2] = currTime;
break;
}
// Shift back elements
for (int i = 0; i < fifo_count; i++) {
fifo[i][0] = fifo[i+1][0];
fifo[i][1] = fifo[i+1][1];
fifo[i][2] = fifo[i+1][2];
}
// Calculate each blizzard's position at currTime + 1
if (blizzard_history_count < currTime + 1) {
for (int j = 0; j < blizzard_count; j++) {
int newX, newY;
if (moves[blizzards[j].dir][0] >= 0) {
newX = 1 + ((blizzards[j].startPos[0] + (currTime+1) * (moves[blizzards[j].dir][0]) - 1) % (x-2));
} else {
newX = (x-2) - (((x-2) - blizzards[j].startPos[0] + (currTime+1) * abs(moves[blizzards[j].dir][0])) % (x-2));
}
if (moves[blizzards[j].dir][1] >= 0) {
newY = 1 + ((blizzards[j].startPos[1] + (currTime+1) * (moves[blizzards[j].dir][1]) - 1) % (y-2));
} else {
newY = (y-2) - (((y-2) - blizzards[j].startPos[1] + (currTime+1) * abs(moves[blizzards[j].dir][1])) % (y-2));
}
blizzardMap[currTime+1][newX][newY] = 1;
}
blizzard_history_count++;
}
// Check each direction from position
for (int i = 0; i < 5; i++) {
int xp = currPos[0] + moves[i][0];
int yp = currPos[1] + moves[i][1];
// Hitting a wall or walking off the map is not healthy
if (yp < 0 || map[xp][yp] == 1) {
continue;
}
// We cannot step on a tile where there will be a blizzard
// the next round
if (blizzardMap[currTime+1][xp][yp]) {
continue;
}
// Stepping back to the entry point is pointless
if (xp == startPos[0] && yp == startPos[1] && i != 4) {
continue;
}
// There's no need to check the same position twice in the same round
int inFifo = 0;
for (int j = 0; j < fifo_count; j++) {
if (fifo[j][0] == xp && fifo[j][1] == yp && fifo[j][2] == currTime + 1) {
inFifo = 1;
break;
}
}
if (inFifo) {
continue;
}
fifo[fifo_count][0] = xp;
fifo[fifo_count][1] = yp;
fifo[fifo_count][2] = currTime + 1;
fifo_count++;
}
}
printf("Back to the end: %i\n", times[2]);
for (int i = 0; i < MAX_BLIZZARDS_HISTORY; i++) {
for (int j = 0; j < x; j++) {
free(blizzardMap[i][j]);
}
free(blizzardMap[i]);
}
free(blizzardMap);
free(fifo);
}
int dist(int one[2], int two[2]) {
return abs(one[0] - two[0]) + abs(one[1] - two[1]);
}