171 lines
3.9 KiB
C++
171 lines
3.9 KiB
C++
#include "Folder.h"
|
|
#include "SplitStr.h"
|
|
|
|
#include <algorithm>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <stack>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
void DebugOutput(File *file)
|
|
{
|
|
static int indent = -1;
|
|
++indent;
|
|
for(auto i = 0; i < indent; ++i)
|
|
std::cout << " ";
|
|
|
|
Folder *folder = dynamic_cast<Folder*>(file);
|
|
if(folder)
|
|
{
|
|
std::cout << "Contents of folder: " << folder->Filename()
|
|
<< ", size: " << folder->Size()
|
|
<< std::endl;
|
|
for(File *file : folder->Files())
|
|
DebugOutput(file);
|
|
}
|
|
else
|
|
std::cout << "- " << file->Filename()
|
|
<< ", size: " << file->Size()
|
|
<< std::endl;
|
|
--indent;
|
|
}
|
|
|
|
unsigned long PartOne(File *file, unsigned long &grand_total)
|
|
{
|
|
unsigned long rtn = 0;
|
|
Folder *folder = dynamic_cast<Folder*>(file);
|
|
if(folder)
|
|
{
|
|
for(File *file : folder->Files())
|
|
rtn += PartOne(file, grand_total);
|
|
if(rtn <= 100000)
|
|
{
|
|
grand_total += rtn;
|
|
std::cout << "Folder \"" << folder->Filename() << "\" has a size of " << rtn
|
|
<< std::endl;
|
|
}
|
|
}
|
|
else
|
|
rtn += file->Size();
|
|
return rtn;
|
|
}
|
|
|
|
void PartTwo(File *file, unsigned long at_least, File *&smallest)
|
|
{
|
|
Folder *folder = dynamic_cast<Folder*>(file);
|
|
if(folder)
|
|
{
|
|
if(folder->Size() >= at_least && folder->Size() < smallest->Size())
|
|
{
|
|
std::cout << "New smallest size of " << folder->Size() << " by folder \""
|
|
<< folder->Filename() << "\"." << std::endl;
|
|
smallest = file;
|
|
}
|
|
|
|
for(File *file : folder->Files())
|
|
PartTwo(file, at_least, smallest);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void Parse(Folder &root)
|
|
{
|
|
std::ifstream ifs("data.txt");
|
|
if(!ifs.is_open())
|
|
{
|
|
std::cerr << "Missing data.txt." << std::endl;
|
|
exit(-1);
|
|
}
|
|
|
|
std::stack<Folder*> dir_stack;
|
|
dir_stack.push(&root);
|
|
|
|
// Step 1: Parse:
|
|
for(std::string line; std::getline(ifs, line); )
|
|
{
|
|
if(line == "")
|
|
continue;
|
|
|
|
if(line.starts_with("$ ls"))
|
|
continue;
|
|
else if(line.starts_with("$ cd"))
|
|
{
|
|
auto to = line.substr(5);
|
|
if(to == "/")
|
|
{
|
|
while(dir_stack.size() > 1)
|
|
dir_stack.pop();
|
|
}
|
|
else if(to == "..")
|
|
{
|
|
if(dir_stack.size() > 1)
|
|
dir_stack.pop();
|
|
}
|
|
else
|
|
{
|
|
auto existing = std::find_if(dir_stack.top()->Files().begin(),
|
|
dir_stack.top()->Files().end(),
|
|
[&to](const File *f){
|
|
return f->Filename() == to;
|
|
});
|
|
if(existing != dir_stack.top()->Files().end()) // found!
|
|
{
|
|
// Check to see if it's a folder, first:
|
|
Folder *folder = dynamic_cast<Folder*>(*existing);
|
|
if(folder)
|
|
dir_stack.push(folder);
|
|
else
|
|
{
|
|
std::cerr << (*existing)->Filename() << " is a file, not a folder."
|
|
<< std::endl;
|
|
exit(-3);
|
|
}
|
|
}
|
|
else
|
|
std::cerr << "could not navigate to \"" << to << "\" from \""
|
|
<< dir_stack.top()->Filename() << "\"." << std::endl;
|
|
}
|
|
}
|
|
else if(line.starts_with("dir "))
|
|
{
|
|
dir_stack.top()->AddFolder(line.substr(4));
|
|
}
|
|
else
|
|
{
|
|
auto values = SplitStr(line, " ");
|
|
dir_stack.top()->AddFile(values[1], std::atol(values[0].c_str()));
|
|
}
|
|
}
|
|
}
|
|
|
|
int main()
|
|
{
|
|
Folder root("/");
|
|
Parse(root);
|
|
|
|
// Step 1.5: Debug output:
|
|
DebugOutput(&root);
|
|
|
|
unsigned long grand_total = 0;
|
|
PartOne(&root, grand_total);
|
|
|
|
std::cout << "Grand Total (part 1): " << grand_total << std::endl;
|
|
|
|
const unsigned long max_space = 70000000;
|
|
const unsigned long space_needed = 30000000;
|
|
const unsigned long currently_used = root.Size();
|
|
const unsigned long currently_unused = max_space - currently_used;
|
|
const unsigned long amt_to_remove = space_needed - currently_unused;
|
|
|
|
File *file_to_remove = &root;
|
|
PartTwo(&root, amt_to_remove, file_to_remove);
|
|
|
|
std::cout << "Remove \"" << file_to_remove->Filename() << "\" to free up "
|
|
<< file_to_remove->Size() << " which is the smallest amount >= "
|
|
<< amt_to_remove << " (part 2)." << std::endl;
|
|
|
|
return 0;
|
|
}
|