Skip to content

Commit 7ad134b

Browse files
authored
AoC 2025 Day 12
Unnecessary packer and playing with csignal
1 parent 1803997 commit 7ad134b

1 file changed

Lines changed: 256 additions & 0 deletions

File tree

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
#include <cassert>
2+
#include <chrono>
3+
#include <functional>
4+
#include <future>
5+
#include <iostream>
6+
#include <numeric>
7+
#include <optional>
8+
#include <sstream>
9+
//#include <stdexcept>
10+
#include <thread>
11+
#include <csignal>
12+
13+
void read_presents();
14+
bool solve();
15+
16+
constexpr int P = 3;
17+
18+
constexpr int num_present_shapes = 6;
19+
char all_configurations[num_present_shapes][8][P][P];
20+
21+
void print_present(char p[P][P]) {
22+
std::cout << "\n";
23+
for (int i = 0 ; i < P; i++) {
24+
for (int j = 0; j < P; j++) std::cout << p[i][j];
25+
std::cout << '\n';
26+
}
27+
}
28+
29+
// first row -> last (third) column
30+
// second row -> second column
31+
// third row -> first column
32+
void rotate(char p[P][P], char rotated[P][P]) {
33+
for (int i = 0 ; i < P; i++) for (int j = 0; j < P; j++)
34+
rotated[j][P-i-1] = p[i][j];
35+
}
36+
37+
void flip(char p[P][P], char flipped[P][P]) {
38+
for (int i = 0 ; i < P; i++) for (int j = 0; j < P; j++)
39+
flipped[i][P-j-1] = p[i][j];
40+
}
41+
42+
class Solver {
43+
public:
44+
std::atomic<bool> interrupt{false};
45+
46+
int width;
47+
int length;
48+
std::vector<std::vector<char>> region;
49+
std::array<int, num_present_shapes> presents_left;
50+
char current_present_char = 'A';
51+
bool solve() {
52+
if (interrupt.load(std::memory_order_relaxed)) {
53+
return false; // abort
54+
}
55+
/*
56+
std::cout << '\n';
57+
PRINT(presents_left);
58+
for (int l = 0 ; l < length; l++) {
59+
for (int w = 0; w < width; w++) std::cout << region[l][w];
60+
std::cout << '\n';
61+
}
62+
std::cout << '\n';
63+
*/
64+
for (int const pl : presents_left) assert(pl >= 0);
65+
if (std::accumulate(presents_left.begin(), presents_left.end(), 0) == 0) {
66+
std::cout << '\n';
67+
for (std::vector<char> const& vc : region) {
68+
for (char const c : vc) std::cout << c;
69+
std::cout << '\n';
70+
}
71+
std::cout << '\n';
72+
return true;
73+
}
74+
int p = 0;
75+
for (int const pl : presents_left) {
76+
if (pl != 0) break;
77+
p++;
78+
}
79+
for (int l = 0 ; l < length - P + 1; l++) for (int w = 0; w < width - P + 1; w++) {
80+
if (interrupt.load(std::memory_order_relaxed)) {
81+
return false; // abort
82+
}
83+
if (region[l][w] != '.') continue;
84+
// for every "rotation and flip" of the next _present_
85+
for (int r = 0; r < 8; r++) {
86+
// if the _present_ (possibly rotated and/or flipped) fits at this *cell*
87+
if (interrupt.load(std::memory_order_relaxed)) {
88+
return false; // abort
89+
}
90+
bool occupied = false;
91+
for (int i = 0 ; i < P && !occupied; i++) for (int j = 0; j < P && !occupied; j++) {
92+
if (all_configurations[p][r][i][j] == '#' && region.at(l + i).at(w + j) != '.') {
93+
occupied = true;
94+
break;
95+
}
96+
}
97+
if (interrupt.load(std::memory_order_relaxed)) {
98+
return false; // abort
99+
}
100+
if (occupied) continue;
101+
if (interrupt.load(std::memory_order_relaxed)) {
102+
return false; // abort
103+
}
104+
// paint the grid inserting the present at this *cell*
105+
for (int i = 0 ; i < P; i++) for (int j = 0; j < P; j++) {
106+
if (all_configurations[p][r][i][j] != '#') continue;
107+
assert(region[l + i][w + j] == '.');
108+
//region[l + i][w + j] = '#';
109+
region[l + i][w + j] = current_present_char;
110+
}
111+
// reduce the present count to account for the insertion
112+
assert(presents_left[p] > 0);
113+
if (current_present_char == 'Z') current_present_char = 'A';
114+
else current_present_char++;
115+
assert('A' <= current_present_char && current_present_char <= 'Z');
116+
presents_left[p]--;
117+
// recurse with the updated grid and presents count
118+
if (solve()) return true;
119+
// unpaint grid
120+
if (current_present_char == 'A') current_present_char = 'Z';
121+
else current_present_char--;
122+
assert('A' <= current_present_char && current_present_char <= 'Z');
123+
for (int i = 0 ; i < P; i++) for (int j = 0; j < P; j++) {
124+
if (all_configurations[p][r][i][j] != '#') continue;
125+
assert(region[l + i][w + j] == current_present_char);
126+
region[l + i][w + j] = '.';
127+
}
128+
// undo reduction of count
129+
assert(presents_left[p] >= 0);
130+
presents_left[p]++;
131+
} // for (int r = 0; r < 8; r++)
132+
} // for (int l = 0 ; l < length - P - 1; l++) for (int w = 0; w < width - P - 1; w++)
133+
return false;
134+
}
135+
};
136+
137+
std::optional<bool> try_solve_with_timeout(Solver& solver, int timeout = 10) {
138+
solver.interrupt.store(false);
139+
auto future = std::async(std::launch::async, &Solver::solve, &solver);
140+
if (future.wait_for(std::chrono::milliseconds(timeout)) == std::future_status::timeout) {
141+
solver.interrupt.store(true);
142+
// WAIT until the thread actually finishes!
143+
// Block until unwinding is complete.
144+
future.wait();
145+
return std::nullopt;
146+
}
147+
return future.get();
148+
}
149+
150+
auto const start = std::chrono::high_resolution_clock::now();
151+
152+
int problem_idx = 0;
153+
std::array<Solver, 1000> solvers;
154+
void signal_handler(int signal)
155+
{
156+
if (signal == SIGINT) solvers[problem_idx].interrupt = true;
157+
}
158+
159+
int main() {
160+
std::signal(SIGINT, signal_handler);
161+
read_presents();
162+
std::cout << "presents read!" << std::endl;
163+
for (int shape_idx = 0; shape_idx < num_present_shapes; shape_idx++) {
164+
//print_present(all_configurations[shape_idx][0]);
165+
int next_configuration = 1;
166+
char rotated[P][P];
167+
rotate(all_configurations[shape_idx][0], rotated);
168+
for (int i = 0 ; i < P; i++) for (int j = 0; j < P; j++)
169+
all_configurations[shape_idx][1][i][j] = rotated[i][j];
170+
next_configuration = 2;
171+
//print_present(rotated);
172+
for (int r = 0; r < 2; r++) {
173+
char rotatedn[P][P];
174+
rotate(rotated, rotatedn);
175+
for (int i = 0 ; i < P; i++) for (int j = 0; j < P; j++)
176+
all_configurations[shape_idx][next_configuration][i][j] = rotatedn[i][j];
177+
next_configuration++;
178+
//print_present(rotatedn);
179+
for (int i = 0 ; i < P; i++) for (int j = 0; j < P; j++)
180+
rotated[i][j] = rotatedn[i][j];
181+
}
182+
char flipped_and_then_rotated[P][P];
183+
flip(all_configurations[shape_idx][0], flipped_and_then_rotated);
184+
for (int i = 0 ; i < P; i++) for (int j = 0; j < P; j++)
185+
all_configurations[shape_idx][next_configuration][i][j] = flipped_and_then_rotated[i][j];
186+
next_configuration++;
187+
//print_present(flipped_and_then_rotated);
188+
for (int r = 0; r < 3; r++) {
189+
char flippedrotatedn[P][P];
190+
rotate(flipped_and_then_rotated, flippedrotatedn);
191+
for (int i = 0 ; i < P; i++) for (int j = 0; j < P; j++)
192+
all_configurations[shape_idx][next_configuration][i][j] = flippedrotatedn[i][j];
193+
next_configuration++;
194+
//print_present(flippedrotatedn);
195+
for (int i = 0 ; i < P; i++) for (int j = 0; j < P; j++)
196+
flipped_and_then_rotated[i][j] = flippedrotatedn[i][j];
197+
}
198+
}
199+
std::cout << "all_configurations filled!" << std::endl;
200+
std::string line;
201+
int ans = 0;
202+
std::vector<std::future<std::optional<bool>>> futures;
203+
while(std::getline(std::cin, line)) {
204+
Solver& solver = solvers.at(problem_idx);
205+
//width = 50;//12; //4;
206+
//length = 45;// 5; //4;
207+
solver.width = std::stoi(line.substr(0, line.find('x')));
208+
solver.length = std::stoi(line.substr(line.find('x')+1,line.find(':')-line.find('x')-1));
209+
solver.region = std::vector(solver.length, std::vector(solver.width, '.'));
210+
{
211+
int i = 0;
212+
std::istringstream iss(line.substr(line.find(' ') + 1));
213+
for (std::string token; iss >> token;)
214+
solver.presents_left.at(i++) = std::stoi(token);
215+
}
216+
//presents_left = std::array{0, 0, 0, 0, 2, 0};
217+
//presents_left = std::array{1, 0, 1, 0, 3, 2};
218+
//presents_left = std::array{40, 43, 39, 39, 40, 39};
219+
std::cout << "solve()...";
220+
futures.push_back(std::async(try_solve_with_timeout, std::ref(solver), 100000));
221+
futures.back().wait();
222+
std::this_thread::sleep_for(std::chrono::seconds(2));
223+
problem_idx++;
224+
}
225+
/*
226+
for (auto& future : futures) {
227+
auto maybe_value = future.get();
228+
if (maybe_value.has_value()) ans += maybe_value.value();
229+
}
230+
*/
231+
auto const end = std::chrono::high_resolution_clock::now();
232+
//std::cout << "Part one: " << ans << "\n";
233+
std::cout << std::chrono::duration<double, std::milli>(end - start).count() << " milliseconds\n";
234+
//if (ans != 528) throw std::runtime_error("wrong answer");
235+
}
236+
237+
void read_presents() {
238+
for (int i = 0; i < num_present_shapes; i++) {
239+
std::string line;
240+
std::getline(std::cin, line);
241+
std::stringstream ss(line);
242+
int j;
243+
char colon;
244+
ss >> j >> colon;
245+
assert(j == i);
246+
assert(colon == ':');
247+
std::getline(std::cin, line);
248+
for (int k = 0; k < P; k++) all_configurations[i][0][0][k] = line[k];
249+
std::getline(std::cin, line);
250+
for (int k = 0; k < P; k++) all_configurations[i][0][1][k] = line[k];
251+
std::getline(std::cin, line);
252+
for (int k = 0; k < P; k++) all_configurations[i][0][2][k] = line[k];
253+
std::getline(std::cin, line);
254+
assert(line.empty());
255+
}
256+
}

0 commit comments

Comments
 (0)