Day7
This commit is contained in:
242
day7/dir.c
Normal file
242
day7/dir.c
Normal file
@@ -0,0 +1,242 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define BUFFER_SIZE 64
|
||||
#define MAX_FILES 32
|
||||
#define MAX_CHILDREN 16
|
||||
#define THRESHOLD 100000
|
||||
// at most
|
||||
#define RULE <=
|
||||
#define TOTAL_SIZE 70000000
|
||||
#define SPACE_NEEDED 30000000
|
||||
|
||||
typedef enum commands {
|
||||
CD,
|
||||
LS
|
||||
} COMMAND;
|
||||
|
||||
typedef struct fnode {
|
||||
char name[BUFFER_SIZE];
|
||||
unsigned long size;
|
||||
} FNODE;
|
||||
|
||||
typedef struct dir {
|
||||
char name[BUFFER_SIZE];
|
||||
FNODE files[MAX_FILES];
|
||||
int files_num;
|
||||
struct dir *parent;
|
||||
struct dir *children[MAX_CHILDREN];
|
||||
int children_num;
|
||||
int cached;
|
||||
unsigned long cached_size;
|
||||
} DIR;
|
||||
|
||||
COMMAND map_cmd(char *);
|
||||
DIR* createDir(char*, DIR*);
|
||||
void cp(char*, char*);
|
||||
DIR* findDirName(DIR*, char*);
|
||||
FNODE* findFileName(DIR*, char*);
|
||||
int cmp(char*, char*);
|
||||
void release(DIR*);
|
||||
unsigned long dirsize(DIR*);
|
||||
void gotta_catch_em_all(DIR*);
|
||||
void omelette_du_fromage(DIR*, DIR**, unsigned long);
|
||||
|
||||
unsigned long sum;
|
||||
|
||||
int main() {
|
||||
char linebuf[BUFFER_SIZE], buf[BUFFER_SIZE], *p, c;
|
||||
memset(linebuf, 0, BUFFER_SIZE);
|
||||
p = linebuf;
|
||||
COMMAND cmd;
|
||||
DIR *currentDir = NULL, *rootDir = NULL, *target;
|
||||
FNODE *tmpf;
|
||||
unsigned long fsize;
|
||||
|
||||
while ((c = getchar()) != EOF) {
|
||||
*p++ = c;
|
||||
if (c == '\n') {
|
||||
if (linebuf[0] == '$') {
|
||||
// command
|
||||
memset(buf, 0 , BUFFER_SIZE);
|
||||
sscanf(linebuf, "$ %s", buf);
|
||||
cmd = map_cmd(buf);
|
||||
if (cmd == CD) {
|
||||
memset(buf, 0 , BUFFER_SIZE);
|
||||
sscanf(linebuf + 4, "%s", buf);
|
||||
if (buf[0] == '/' && buf[1] == 0) {
|
||||
// Root
|
||||
if (rootDir == NULL)
|
||||
rootDir = createDir(buf, NULL);
|
||||
currentDir = rootDir;
|
||||
} else if (buf[0] == '.' && buf[1] == '.' && buf[2] == 0) {
|
||||
currentDir = currentDir->parent;
|
||||
} else {
|
||||
target = findDirName(currentDir, buf);
|
||||
if (target == NULL) {
|
||||
target = createDir(buf, currentDir);
|
||||
}
|
||||
|
||||
currentDir = target;
|
||||
}
|
||||
} else if (cmd == LS) {
|
||||
// Nothing to do
|
||||
}
|
||||
}
|
||||
|
||||
memset(buf, 0 , BUFFER_SIZE);
|
||||
if (sscanf(linebuf, "%lu %s", &fsize, buf)) {
|
||||
// File
|
||||
tmpf = findFileName(currentDir, buf);
|
||||
if (tmpf == NULL) {
|
||||
cp(buf, currentDir->files[currentDir->files_num].name);
|
||||
currentDir->files[currentDir->files_num].size = fsize;
|
||||
currentDir->files_num++;
|
||||
}
|
||||
} else {
|
||||
// Dir
|
||||
sscanf(linebuf, "dir %s", buf);
|
||||
target = findDirName(currentDir, buf);
|
||||
if (target == NULL) {
|
||||
target = createDir(buf, currentDir);
|
||||
}
|
||||
}
|
||||
|
||||
memset(linebuf, 0, BUFFER_SIZE);
|
||||
p = linebuf;
|
||||
}
|
||||
}
|
||||
|
||||
// First part
|
||||
gotta_catch_em_all(rootDir);
|
||||
printf("%lu\n", sum);
|
||||
|
||||
// Second part
|
||||
DIR *bestMatch = rootDir;
|
||||
unsigned long free_space = TOTAL_SIZE - dirsize(rootDir);
|
||||
printf("\nFREE SPACE: %lu\n", free_space);
|
||||
omelette_du_fromage(rootDir, &bestMatch, free_space);
|
||||
printf("TO DELETE: %s, %lu\n", bestMatch->name, dirsize(bestMatch));
|
||||
|
||||
currentDir = NULL;
|
||||
// "Aki malloc-ot mond, mondjon free-t is"
|
||||
release(rootDir);
|
||||
free(rootDir);
|
||||
}
|
||||
|
||||
COMMAND map_cmd(char *buf) {
|
||||
if (buf[0] == 'c' && buf[1] == 'd') {
|
||||
return CD;
|
||||
} else if (buf[0] == 'l' && buf[1] == 's') {
|
||||
return LS;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
DIR* createDir(char* name, DIR* parent) {
|
||||
DIR* newDir = (DIR*)malloc(sizeof(DIR));
|
||||
memset(newDir->files, 0, MAX_FILES*sizeof(FNODE));
|
||||
memset(newDir->children, 0, MAX_CHILDREN*sizeof(DIR*));
|
||||
newDir->files_num = 0;
|
||||
newDir->children_num = 0;
|
||||
newDir->parent = parent;
|
||||
newDir->cached = 0;
|
||||
if (parent != NULL) {
|
||||
parent->children[parent->children_num] = newDir;
|
||||
parent->children_num++;
|
||||
}
|
||||
cp(name, newDir->name);
|
||||
|
||||
return newDir;
|
||||
}
|
||||
|
||||
void cp(char *p , char *q){
|
||||
while((*q++ = *p++) != 0) {}
|
||||
}
|
||||
|
||||
DIR* findDirName(DIR* dir, char *name) {
|
||||
for (int i = 0; i < dir->children_num; i++) {
|
||||
if (cmp(dir->children[i]->name, name)) {
|
||||
return dir->children[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int cmp(char *p, char *q) {
|
||||
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||
if (p[i] != q[i]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void release(DIR* dir) {
|
||||
for (int i = 0; i < dir->children_num; i++) {
|
||||
release(dir->children[i]);
|
||||
free(dir->children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
FNODE* findFileName(DIR* dir, char* name) {
|
||||
for (int i = 0; i < dir->files_num; i++) {
|
||||
if (cmp(dir->files[i].name, name)) {
|
||||
return &dir->files[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned long dirsize(DIR* dir) {
|
||||
if (dir->cached) {
|
||||
return dir->cached_size;
|
||||
}
|
||||
|
||||
unsigned long mysize = 0;
|
||||
|
||||
// Files here
|
||||
for (int i = 0; i < dir->files_num; i++) {
|
||||
mysize += dir->files[i].size;
|
||||
}
|
||||
|
||||
// Files in subdirectories
|
||||
for (int i = 0; i < dir->children_num; i++) {
|
||||
mysize += dirsize(dir->children[i]);
|
||||
}
|
||||
|
||||
dir->cached = 1;
|
||||
dir->cached_size = mysize;
|
||||
|
||||
return mysize;
|
||||
}
|
||||
|
||||
// I know this is shit, each directory should have a size cache
|
||||
// so if we already know its size we don't recurse it again
|
||||
// But I don't care at this point
|
||||
void gotta_catch_em_all(DIR* dir) {
|
||||
unsigned long schlong = dirsize(dir);
|
||||
if (schlong RULE THRESHOLD) {
|
||||
sum += schlong;
|
||||
}
|
||||
|
||||
for (int i = 0; i < dir->children_num; i++) {
|
||||
gotta_catch_em_all(dir->children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void omelette_du_fromage(DIR* dir, DIR** bestMatch, unsigned long freeSpace) {
|
||||
unsigned long current = freeSpace + dirsize(dir);
|
||||
if (current > SPACE_NEEDED && current < (freeSpace + dirsize(*bestMatch))) {
|
||||
*bestMatch = dir;
|
||||
}
|
||||
|
||||
for (int i = 0; i < dir->children_num; i++) {
|
||||
omelette_du_fromage(dir->children[i], bestMatch, freeSpace);
|
||||
}
|
||||
}
|
||||
1052
day7/input.txt
Normal file
1052
day7/input.txt
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user