Skip to content

Commit

Permalink
Adventofcode (#28)
Browse files Browse the repository at this point in the history
2021

* Add seven segment satisfiability decoding in Python

using backtracking, mappings (frozenset to use sets as keys), and
sets (initialized as strings) intersections.

* Add a few more from 2021
  • Loading branch information
iglesias authored Jul 23, 2024
1 parent 6cdd2ba commit 5a02d57
Show file tree
Hide file tree
Showing 11 changed files with 564 additions and 33 deletions.
59 changes: 59 additions & 0 deletions adventofcode/2021/day/03/binary_diagnostic.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#include <iostream>
#include <set>
#include <string>
#include <string_view>
#include <vector>

int bin2dec(std::string_view bin) {
int base{1};
int ans{0};
for (ssize_t i = bin.size() - 1; i >= 0; i--) {
ans += (bin[i] - '0')*base;
base *= 2;
}
return ans;
}

std::string part_two(std::multiset<std::string> set, bool opt);

int main() {
std::string line;
std::vector<size_t> ones_count;
std::multiset<std::string> set;
while (std::getline(std::cin, line)) {
if (not ones_count.size())
ones_count = std::vector<size_t>(line.length(), 0);
size_t i{0};
for (const char c : line) ones_count[i++] += c == '1';
set.insert(line);
}
std::string gamma_rate, epsilon_rate;
for (const size_t count : ones_count) {
gamma_rate.append( count > set.size() / 2 ? "1" : "0");
epsilon_rate.append(count > set.size() / 2 ? "0" : "1");
}
std::cout << "Part one: " << bin2dec(gamma_rate) * bin2dec(epsilon_rate) << '\n';

const int o2_generator_rating = bin2dec(part_two(set, false));
const int co2_scrubber_rating = bin2dec(part_two(set, true));
std::cout << "Part two: " << o2_generator_rating * co2_scrubber_rating << '\n';
}

std::string part_two(std::multiset<std::string> set, bool opt) {
for (size_t i{0}; set.size() > 1; ++i) {
size_t ones_count{0};
for (const std::string& item : set) ones_count += item.at(i) == '1';
const size_t n = set.size();
if (not n % 2 and ones_count == n / 2) ones_count = n;
auto it = set.begin();
while (it != set.end())
if (ones_count > n / 2) {
if (it->at(i) == "01"[opt]) it = set.erase(it);
else it++;
} else {
if (it->at(i) == "10"[opt]) it = set.erase(it);
else it++;
}
}
return *set.begin();
}
69 changes: 69 additions & 0 deletions adventofcode/2021/day/04/giant_squid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import numpy as np

class Board:
def __init__(self, board_lines: [str]):
assert len(board_lines) == 5
self.board = np.zeros((5,5), dtype=int)
for row in range(5):
for col in range(5):
self.board[row, col] = int(board_lines[row][col])
self.marked = np.zeros((5,5), dtype=bool)

def draw(self, number: int) -> bool:
for row in range(5):
for col in range(5):
if self.board[row, col] == number:
self.marked[row, col] = True
return self.check_bingo(row, col)

def check_bingo(self, row, col) -> bool:
if all(self.marked[row]):
return True
if all(self.marked[:,col]):
return True
return False

def sum_unmarked(self):
return np.sum(self.board[~self.marked])

def read_input() -> ([int], [Board]):
line = input()
numbers = map(int, line.split(','))
empty_line = input()
assert empty_line == ""
try_line = input()
boards = []
while len(try_line):
board_lines = [try_line.split()]
for i in range(4):
line = input()
board_lines.append(line.split())
boards.append(Board(board_lines))
try:
empty_line = input()
except EOFError:
break
else:
assert empty_line == ""
try_line = input()
return numbers, boards

boards_finished = set()

def draw(number: int, boards: [Board]):
for i, board in enumerate(boards):
if board.draw(number):
if not len(boards_finished):
print('Part one:', board.sum_unmarked() * number)
if i in boards_finished:
continue
else:
boards_finished.add(i)
if len(boards_finished) == len(boards):
print('Part two:', board.sum_unmarked() * number)
return

if __name__ == "__main__":
numbers, boards = read_input()
for number in numbers:
r = draw(number, boards)
30 changes: 30 additions & 0 deletions adventofcode/2021/day/06/lanternfish.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>

int main(int argc, char **argv) {
const size_t num_days = [&](){
try {
const size_t num_days = argc > 1 ? std::stoi(argv[1]) : 18;
return num_days;
} catch (...) {
std::cerr << "Usage: ./lanternfish [num_days] with num_days a positive integer\n";
std::exit(1);
}
}();
std::vector<size_t> fishes(9);
std::iota(fishes.begin(), fishes.end(), 0);
constexpr size_t reset_days{6};
constexpr size_t spawn_days{8};
std::array<uint64_t, spawn_days + 1> hishes{}; // histogram of fishes' internal timers
for (const int fish : fishes) hishes[fish]++;
for (size_t day = 1; day <= num_days; day++) {
uint64_t backup = hishes[0];
//for (size_t i = 0; i < hishes.size() - 1; i++) hishes[i] = hishes[i + 1];
std::rotate(hishes.begin(), hishes.begin() + 1, hishes.end());
hishes[reset_days] += backup;
hishes[spawn_days] = backup;
}
std::cout << std::accumulate(hishes.cbegin(), hishes.cend(), 0ull) << "\n";
}
75 changes: 75 additions & 0 deletions adventofcode/2021/day/08/seven_segment_search.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
lens_mapping = {2: {1}, 3: {7}, 4: {4}, 5: {2, 3, 5}, 6: {0, 6, 9}, 7: {8}}
segments = [{0, 1, 2, 3, 4, 5}, {1, 2}, {0, 1, 3, 4, 6}, {0, 1, 2, 3, 6},
{1, 2, 5, 6}, {0, 2, 3, 5, 6}, {0, 2, 3, 4, 5, 6}, {0, 1, 2},
{0, 1, 2, 3, 4, 5, 6}, {0, 1, 2, 3, 5, 6}]
segments_to_digit = {}
for digit, segment in enumerate(segments):
segments_to_digit[frozenset(segment)] = digit

def decode(output_values, x):
xi = 0
solved = set()
while any([len(item) > 1 for item in x]):
if len(x[xi]) == 1 and xi not in solved:
y = x[xi].pop()
solved.add(y)
x[xi].add(y)
else:
assert len(x[xi]) > 1
x[xi] = set.difference(x[xi], solved)
assert len(x[xi]) >= 1
xi = (xi + 1) % len(x)
# output mapping obtained with the signal patterns:
letter_to_segment = {}
for j, xj in enumerate(x):
letter_to_segment[xj.pop()] = j
# used together with the output values to obtain the answer:
ans = 0
for output_value in output_values:
# build segments on with this output_value
segments_on = set()
for c in output_value:
segments_on.add(letter_to_segment[c])
ans *= 10
ans += segments_to_digit[frozenset(segments_on)]
return ans

# backtracking
def decode_segments(signal_patterns, i, x, used_digits):
if i == len(signal_patterns):
return x
for digit in lens_mapping[len(signal_patterns[i])]:
if digit in used_digits:
continue
# FIXME try to avoid x.copy()
y = x.copy()
stop = False
for segment in segments[digit]:
if len(set(signal_patterns[i]) & set(y[segment])) == 0:
stop = True
y[segment] = set(signal_patterns[i]) & set(y[segment])
if not stop:
used_digits.add(digit)
r = decode_segments(signal_patterns, i + 1, y, used_digits)
if r is not None:
return r
used_digits.remove(digit)
return None

if __name__ == "__main__":
part_one = 0
part_two = 0
for line in open(0).readlines():
head, tail = line.split('|')
output_values = tail.strip().split()
for output_value in output_values:
n = len(output_value)
part_one += n == 2 or n == 4 or n == 3 or n == 7
signal_patterns = head.split()
signal_patterns.sort(key=lambda s: len(s))
signal_patterns = [''.join(sorted(signal_pattern)) for signal_pattern in signal_patterns]
x = decode_segments(signal_patterns, 0, 7*['abcdefg'], set())
part_two += decode(output_values, x)

print('Part one:', part_one)
print('Part two:', part_two)
59 changes: 59 additions & 0 deletions adventofcode/2021/day/09/smoke_basin.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#include <algorithm>
#include <array>
#include <iostream>
#include <queue>
#include <string>
#include <unordered_set>
#include <vector>

struct pair_hash {
template <class T1, class T2>
std::size_t operator () (const std::pair<T1,T2> &p) const {
auto h1 = std::hash<T1>{}(p.first);
auto h2 = std::hash<T2>{}(p.second);
return h1 ^ h2;
}
};

int main() {
int R{0}, C;
std::vector<std::string> v;
std::string line;
while (std::getline(std::cin, line)) {
v.push_back(line);
C = static_cast<int>(line.length());
R++;
}
int part_one{0};
constexpr std::array<std::array<int, 2>, 4> deltas = {-1, 0, 1, 0, 0, -1, 0, 1};
std::vector<size_t> basins_sizes;
for (int i = 0; i < R; i++) for (int j = 0; j < C; j++) {
bool found = false;
for (const auto& delta : deltas)
if (i + delta[0] >= 0 and i + delta[0] < R and j + delta[1] >= 0 and j + delta[1] < C)
if (v[i + delta[0]][j + delta[1]] - '0' <= v[i][j] - '0') found = true;
if (found) continue;
part_one += v[i][j] - '0' + 1;
std::unordered_set<std::pair<int, int>, pair_hash> Qed;
std::queue<std::pair<int, int>> Q;
Q.emplace(i, j);
Qed.emplace(i, j);
while (not Q.empty()) {
const auto [r, c] = Q.front();
Q.pop();
for (const auto& delta : deltas)
if (r + delta[0] >= 0 and r + delta[0] < R and c + delta[1] >= 0 and c + delta[1] < C)
if (v[r + delta[0]][c + delta[1]] != '9' and
not Qed.contains(std::make_pair(r + delta[0], c + delta[1]))) {
Q.emplace(r + delta[0], c + delta[1]);
Qed.emplace(r + delta[0], c + delta[1]);
}
}
basins_sizes.push_back(Qed.size());
}
std::cout << part_one << '\n';
std::ranges::sort(basins_sizes);
std::cout << basins_sizes.at(basins_sizes.size() - 1) *
basins_sizes.at(basins_sizes.size() - 2) *
basins_sizes.at(basins_sizes.size() - 3) << '\n';
}
65 changes: 65 additions & 0 deletions adventofcode/2021/day/10/syntax_scoring.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include <iostream>
#include <stack>
#include <string>
#include <vector>

int score(char c) {
switch (c) {
case ')':
return 3;
case ']':
return 57;
case '}':
return 1197;
default:
return 25137;
}
}

bool match(char c, char d) {
if (c == ')')
return d == '(';
else if (c == ']')
return d == '[';
else if (c == '}')
return d == '{';
else
return d == '<';
}

int main() {
std::string line;
int part_one{0};
std::vector<uint64_t> autocomplete_scores;
while (std::getline(std::cin, line)) {
std::stack<char> S;
for (const char c : line)
if (c == '(' or c == '[' or c == '{' or c == '<') {
S.push(c);
} else {
if (match(c, S.top())) {
S.pop();
} else {
part_one += score(c);
while (!S.empty()) S.pop();
break;
}
}
if (!S.empty()) autocomplete_scores.push_back(0);
while (not S.empty()) {
autocomplete_scores[autocomplete_scores.size() - 1] *= 5;
if (S.top() == '(')
autocomplete_scores[autocomplete_scores.size() - 1] += 1;
else if (S.top() == '[')
autocomplete_scores[autocomplete_scores.size() - 1] += 2;
else if (S.top() == '{')
autocomplete_scores[autocomplete_scores.size() - 1] += 3;
else if (S.top() == '<')
autocomplete_scores[autocomplete_scores.size() - 1] += 4;
S.pop();
}
}
std::cout << part_one << '\n';
std::nth_element(autocomplete_scores.begin(), autocomplete_scores.begin() + autocomplete_scores.size() / 2, autocomplete_scores.end());
std::cout << autocomplete_scores[autocomplete_scores.size() / 2] << '\n';
}
Loading

0 comments on commit 5a02d57

Please sign in to comment.