From 571d2a9530db04ae1dbea97dca64b33cc391c866 Mon Sep 17 00:00:00 2001 From: zv0n Date: Sat, 3 Dec 2022 18:16:33 +0100 Subject: [PATCH] 21 --- 21/CMakeLists.txt | 22 +++++++ 21/input | 2 + 21/main.cpp | 152 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+) create mode 100644 21/CMakeLists.txt create mode 100644 21/input create mode 100644 21/main.cpp diff --git a/21/CMakeLists.txt b/21/CMakeLists.txt new file mode 100644 index 0000000..800f48e --- /dev/null +++ b/21/CMakeLists.txt @@ -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 + ) diff --git a/21/input b/21/input new file mode 100644 index 0000000..d4a8966 --- /dev/null +++ b/21/input @@ -0,0 +1,2 @@ +Player 1 starting position: 7 +Player 2 starting position: 1 diff --git a/21/main.cpp b/21/main.cpp new file mode 100644 index 0000000..2b2b28c --- /dev/null +++ b/21/main.cpp @@ -0,0 +1,152 @@ +#include +#include +#include +#include +#include +#include + +std::pair getStartingPositions(const std::string &file_name) { + std::ifstream file(file_name); + std::pair 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 ¤t_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 &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 &starting_positions) { + std::pair player_1; + player_1.first = starting_positions.first; // position + player_1.second = 0; // score + std::pair 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 &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; +}