This commit is contained in:
zv0n 2022-12-03 18:16:33 +01:00
parent 7e5b3cf6cf
commit 571d2a9530
3 changed files with 176 additions and 0 deletions

22
21/CMakeLists.txt Normal file
View File

@ -0,0 +1,22 @@
cmake_minimum_required(VERSION 3.10)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
enable_language(CXX)
project(AoC21)
if(APPLE)
include_directories(/usr/local/include)
link_directories(/usr/local/lib)
endif()
if(WIN32)
add_executable(${CMAKE_PROJECT_NAME} WIN32)
else()
add_executable(${CMAKE_PROJECT_NAME})
endif()
target_sources(${CMAKE_PROJECT_NAME}
PRIVATE main.cpp
)

2
21/input Normal file
View File

@ -0,0 +1,2 @@
Player 1 starting position: 7
Player 2 starting position: 1

152
21/main.cpp Normal file
View File

@ -0,0 +1,152 @@
#include <fstream>
#include <iostream>
#include <sstream>
#include <vector>
#include <array>
#include <unordered_map>
std::pair<int, int> getStartingPositions(const std::string &file_name) {
std::ifstream file(file_name);
std::pair<int, int> result;
std::string str;
std::string tmp = "";
std::getline(file, str);
std::stringstream ss(str);
for(int i = 0; i < 4; i++) {
ss >> tmp;
}
ss >> result.first;
std::getline(file, str);
ss = std::stringstream(str);
for(int i = 0; i < 4; i++) {
ss >> tmp;
}
ss >> result.second;
return result;
}
int getDeterministicDieRolls(int &current_state) {
int result = 0;
for(int i = 0; i < 3; i++) {
if(current_state == 100) {
current_state = 1;
} else {
current_state++;
}
result += current_state;
}
return result;
}
void playerAddDieRolls(std::pair<short, uint64_t> &player, int die_roll) {
player.first += die_roll;
player.first %= 10;
if(player.first == 0) {
player.first = 10;
}
player.second += player.first;
}
int part1(const std::pair<int, int> &starting_positions) {
std::pair<short, uint64_t> player_1;
player_1.first = starting_positions.first; // position
player_1.second = 0; // score
std::pair<short, uint64_t> player_2;
player_2.first = starting_positions.second; // position
player_2.second = 0; // score
int die = 100;
int die_rolls = 0;
while(player_2.second < 1000) {
playerAddDieRolls(player_1, getDeterministicDieRolls(die));
die_rolls += 3;
if(player_1.second >= 1000) {
break;
}
playerAddDieRolls(player_2, getDeterministicDieRolls(die));
die_rolls += 3;
}
int loser_score = player_1.second < player_2.second ? player_1.second : player_2.second;
return loser_score * die_rolls;
}
int getScore(int pos, int roll) {
auto score = pos + roll;
score %= 10;
if(score == 0) {
score = 10;
}
return score;
}
uint64_t part2(const std::pair<int, int> &starting_positions) {
uint64_t player_cache[21][21][10][10][2]; // [score_p1][score_p2][position_p1][position_p2] = number of wins
for(int i = 0; i < 10; i++) {
for(int j = 0; j < 10; j++) {
for(int k = 0; k < 21; k++) {
player_cache[20][k][i][j][0] = 27; // player 1 always goes first, so with score 20 they can't lose, 3*3*3 possible dice rolls
player_cache[20][k][i][j][1] = 0;
}
}
}
for(int a = 0; a <= 19; a++) {
for(int b = 0; b < 21; b++) {
for(int c = 0; c < 10; c++) {
for(int d = 0; d < 10; d++) {
player_cache[a][b][c][d][0] = 0;
player_cache[a][b][c][d][1] = 0;
}
}
}
}
for(int score_1 = 19; score_1 >= 0; score_1--) {
for(int score_2 = 20; score_2 >= 0; score_2--) {
for(int pos_1 = 1; pos_1 <= 10; pos_1++) {
for(int pos_2 = 1; pos_2 <= 10; pos_2++) {
for(int dice_1_1 = 1; dice_1_1 <= 3; dice_1_1++) {
for(int dice_1_2 = 1; dice_1_2 <= 3; dice_1_2++) {
for(int dice_1_3 = 1; dice_1_3 <= 3; dice_1_3++) {
auto next_pos_1 = getScore(pos_1, dice_1_1 + dice_1_2 + dice_1_3);
auto next_score_1 = score_1 + next_pos_1;
if(next_score_1 >= 21) {
player_cache[score_1][score_2][pos_1 - 1][pos_2 - 1][0] += 1;
continue;
}
for(int dice_2_1 = 1; dice_2_1 <= 3; dice_2_1++) {
for(int dice_2_2 = 1; dice_2_2 <= 3; dice_2_2++) {
for(int dice_2_3 = 1; dice_2_3 <= 3; dice_2_3++) {
auto next_pos_2 = getScore(pos_2, dice_2_1 + dice_2_2 + dice_2_3);
auto next_score_2 = score_2 + next_pos_2;
if(next_score_1 < 21 && next_score_2 < 21) {
player_cache[score_1][score_2][pos_1 - 1][pos_2 - 1][0] += player_cache[next_score_1][next_score_2][next_pos_1 - 1][next_pos_2 - 1][0];
player_cache[score_1][score_2][pos_1 - 1][pos_2 - 1][1] += player_cache[next_score_1][next_score_2][next_pos_1 - 1][next_pos_2 - 1][1];
} else if(next_score_1 < 21 && next_score_2 >= 21) {
player_cache[score_1][score_2][pos_1 - 1][pos_2 - 1][1] += 1;
}
}
}
}
}
}
}
}
}
}
}
auto player_1_wins = player_cache[0][0][starting_positions.first - 1][starting_positions.second - 1][0];
auto player_2_wins = player_cache[0][0][starting_positions.first - 1][starting_positions.second - 1][1];
return player_1_wins > player_2_wins ? player_1_wins : player_2_wins;
}
int main(int argc, char **argv) {
if (argc < 2) {
std::cerr << "You must provide input file!" << std::endl;
return 1;
}
auto starting_positions = getStartingPositions(argv[1]);
std::cout << "Result with deterministic die is \033[91;1m" << part1(starting_positions)
<< "\033[0m." << std::endl;
std::cout << "Result with quantum die is \033[91;1m" << part2(starting_positions)
<< "\033[0m." << std::endl;
return 0;
}