advent_of_code/2022/11/main.cpp
2022-12-11 10:25:28 +01:00

183 lines
5.7 KiB
C++

#include <fstream>
#include <functional>
#include <iostream>
#include <sstream>
#include <vector>
class Monkey {
public:
Monkey( std::function<uint64_t( uint64_t )> worry_increase_function,
uint64_t divisor,
const std::deque<uint64_t> &items,
const std::pair<uint64_t, uint64_t> &target_monkeys )
: worry_increase( worry_increase_function ), divisor( divisor ),
items( items ), target_monkeys( target_monkeys ) {}
// {target_monkey, worry_level}
std::pair<uint64_t, uint64_t> performTurn(bool managable) {
inspected_items++;
auto worry = items.front();
items.pop_front();
worry = worry_increase( worry );
if(managable) {
worry /= 3;
}
worry = worry % common_divisor;
if ( worry % divisor == 0 ) {
return { target_monkeys.first, worry };
}
return { target_monkeys.second, worry };
}
void addWorry( uint64_t worry ) {
items.push_back( worry );
}
bool hasItems() {
return !items.empty();
}
const std::deque<uint64_t> &getItems() {
return items;
}
uint64_t getInspectedItems() {
return inspected_items;
}
void setCommonDivisor(uint64_t divisor) {
common_divisor = divisor;
}
private:
std::function<uint64_t( uint64_t )> worry_increase;
uint64_t divisor;
uint64_t common_divisor;
std::deque<uint64_t> items;
const std::pair<uint64_t, uint64_t> target_monkeys;
uint64_t inspected_items = 0;
};
std::vector<Monkey> getMonkeys( std::ifstream &file ) {
std::vector<Monkey> ret{};
std::string tmp;
std::string str;
std::function<uint64_t( uint64_t )> worry_increase;
uint64_t divisor;
uint64_t common_divisor = 1;
std::deque<uint64_t> items;
std::pair<uint64_t, uint64_t> target_monkeys;
while ( std::getline( file, str ) ) {
if ( str.empty() ) {
ret.emplace_back(worry_increase, divisor, items, target_monkeys);
items.clear();
}
std::stringstream ss( str );
ss >> tmp;
if(tmp == "Starting") {
ss >> tmp;
int tmp_i = 0;
ss >> tmp_i;
items.push_back(tmp_i);
while(ss.peek() == ',') {
ss >> tmp;
ss >> tmp_i;
items.push_back(tmp_i);
}
} else if(tmp == "Operation:") {
ss >> tmp; // new
ss >> tmp; // =
ss >> tmp; // old
char op = 0;
uint64_t parameter = 0;
ss >> op;
ss.get();
if(ss.peek() == 'o') {
if(op == '+') {
worry_increase = [](uint64_t old) {return old + old;};
} else {
worry_increase = [](uint64_t old) {return old * old;};
}
} else {
ss >> parameter;
if(op == '+') {
worry_increase = [parameter](uint64_t old) {return old + parameter;};
} else {
worry_increase = [parameter](uint64_t old) {return old * parameter;};
}
}
} else if(tmp == "Test:") {
ss >> tmp; // divisible
ss >> tmp; // by
ss >> divisor;
common_divisor *= divisor;
} else if(tmp == "If") {
std::string bool_val;
ss >> bool_val;
ss >> tmp; // throw
ss >> tmp; // to
ss >> tmp; // monkey
int monkey_index = 0;
ss >> monkey_index;
if(bool_val == "true:") {
target_monkeys.first = monkey_index;
} else {
target_monkeys.second = monkey_index;
}
}
}
ret.emplace_back(worry_increase, divisor, items, target_monkeys);
for(auto &monkey : ret) {
monkey.setCommonDivisor(common_divisor);
}
return ret;
}
uint64_t part1(const std::vector<Monkey> &input) {
auto monkeys = input;
for(int i = 0; i < 20; i++) {
for(auto &monkey : monkeys) {
while(monkey.hasItems()) {
auto monkey_throw = monkey.performTurn(true);
monkeys[monkey_throw.first].addWorry(monkey_throw.second);
}
}
}
std::vector<uint64_t> inspected_items{};
for(auto &monkey : monkeys) {
inspected_items.push_back(monkey.getInspectedItems());
}
std::sort(inspected_items.begin(), inspected_items.end());
return inspected_items[inspected_items.size() - 1] * inspected_items[inspected_items.size() - 2];
}
uint64_t part2(const std::vector<Monkey> &input) {
auto monkeys = input;
for(int i = 1; i <= 10000; i++) {
for(auto &monkey : monkeys) {
while(monkey.hasItems()) {
auto monkey_throw = monkey.performTurn(false);
monkeys[monkey_throw.first].addWorry(monkey_throw.second);
}
}
}
std::vector<uint64_t> inspected_items{};
size_t i = 0;
for(auto &monkey : monkeys) {
inspected_items.push_back(monkey.getInspectedItems());
i++;
}
std::sort(inspected_items.begin(), inspected_items.end());
return inspected_items[inspected_items.size() - 1] * inspected_items[inspected_items.size() - 2];
}
int main() {
std::ifstream input_file( "input" );
auto monkeys = getMonkeys( input_file );
std::cout << "Monkey business after 20 rounds when you don't worry is \033[91;1m" << part1(monkeys) << "\033[0m."
<< std::endl;
std::cout << "Monkey business after 10000 rounds when you worry a lot is \033[91;1m" << part2(monkeys) << "\033[0m."
<< std::endl;
}