You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
178 lines
4.6 KiB
Zig
178 lines
4.6 KiB
Zig
11 months ago
|
const std = @import("std");
|
||
|
|
||
|
pub fn main() !void {
|
||
|
const content = @embedFile("data.txt");
|
||
|
|
||
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||
|
const allocator = gpa.allocator();
|
||
|
|
||
|
var grid = std.ArrayList(std.ArrayList(u8)).init(allocator);
|
||
|
defer grid.deinit();
|
||
|
|
||
|
var grid2 = std.ArrayList(std.ArrayList(u8)).init(allocator);
|
||
|
defer grid2.deinit();
|
||
|
|
||
|
var lines = std.mem.split(u8, content, "\n");
|
||
|
|
||
|
while (lines.next()) |line| {
|
||
|
if (line.len < 1) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
var lineArrayList = std.ArrayList(u8).init(allocator);
|
||
|
var lineArrayList2 = std.ArrayList(u8).init(allocator);
|
||
|
|
||
|
for (line) |char| {
|
||
|
try lineArrayList.append(char);
|
||
|
try lineArrayList2.append(char);
|
||
|
}
|
||
|
|
||
|
try grid.append(lineArrayList);
|
||
|
try grid2.append(lineArrayList2);
|
||
|
}
|
||
|
|
||
|
var map = std.StringHashMap(usize).init(allocator);
|
||
|
defer map.deinit();
|
||
|
|
||
|
transpose(&grid);
|
||
|
try tiltWest(&grid);
|
||
|
transpose(&grid);
|
||
|
|
||
|
var part1 = calculateLoad(grid);
|
||
|
|
||
|
std.debug.print("part 1: {d}\n", .{part1});
|
||
|
|
||
|
var prev: usize = 0;
|
||
|
var loop: usize = 0;
|
||
|
|
||
|
const MAX = 1_000_000_000;
|
||
|
for (0..MAX) |i| {
|
||
|
// see if this grid arrangement is in our map
|
||
|
const key = try getKey(&grid2);
|
||
|
const hashed = map.get(key);
|
||
|
|
||
|
// if it is, we've found a loop
|
||
|
if (hashed) |val| {
|
||
|
prev = val;
|
||
|
loop = i;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
try cycle(&grid2);
|
||
|
|
||
|
// add the new grid arrangement to the map
|
||
|
try map.put(key, i);
|
||
|
}
|
||
|
|
||
|
// figure out where in the loop we should stop
|
||
|
const stop = (MAX - prev) % (loop - prev);
|
||
|
|
||
|
// cycle that many more times
|
||
|
for (0..stop) |_| {
|
||
|
try cycle(&grid2);
|
||
|
}
|
||
|
var part2 = calculateLoad(grid2);
|
||
|
|
||
|
std.debug.print("part 2: {d}\n", .{part2});
|
||
|
}
|
||
|
|
||
|
fn getKey(grid: *std.ArrayList(std.ArrayList(u8))) ![]u8 {
|
||
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||
|
const allocator = gpa.allocator();
|
||
|
|
||
|
var str = std.ArrayList(u8).init(allocator);
|
||
|
for (grid.items) |row| {
|
||
|
try str.appendSlice(row.items);
|
||
|
}
|
||
|
return str.items;
|
||
|
}
|
||
|
|
||
|
fn cycle(grid: *std.ArrayList(std.ArrayList(u8))) !void {
|
||
|
transpose(grid); // to tilt north, transpose so north is left
|
||
|
try tiltWest(grid);
|
||
|
|
||
|
transpose(grid); // to tilt west, transpose again
|
||
|
|
||
|
try tiltWest(grid);
|
||
|
// at this point, grid is back to normal
|
||
|
flipY(grid); // to tilt south, flip (south is up) then transpose (south is left)
|
||
|
transpose(grid);
|
||
|
|
||
|
try tiltWest(grid);
|
||
|
// at this point, south is left, west is up. we want east left
|
||
|
transpose(grid); // south is up, west is left
|
||
|
flipY(grid); // grid is back to normal
|
||
|
flipX(grid);
|
||
|
try tiltWest(grid);
|
||
|
flipX(grid);
|
||
|
}
|
||
|
|
||
|
fn calculateLoad(grid: std.ArrayList(std.ArrayList(u8))) usize {
|
||
|
var load: usize = 0;
|
||
|
for (grid.items, 0..) |row, rowNum| {
|
||
|
var rowMultiplier = grid.items.len - rowNum;
|
||
|
for (row.items) |cell| {
|
||
|
if (cell == 'O') {
|
||
|
load += rowMultiplier;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return load;
|
||
|
}
|
||
|
|
||
|
fn tiltWest(grid: *std.ArrayList(std.ArrayList(u8))) !void {
|
||
|
for (grid.items) |row| {
|
||
|
for (row.items, 0..) |cell, i| {
|
||
|
if (cell == 'O' and i != 0 and row.items[i - 1] == '.') {
|
||
|
var j = i;
|
||
|
while (j > 0) {
|
||
|
row.items[j - 1] = 'O';
|
||
|
row.items[j] = '.';
|
||
|
j -= 1;
|
||
|
if (j < 1 or row.items[j - 1] != '.') {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// assumes square grid
|
||
|
fn transpose(grid: *std.ArrayList(std.ArrayList(u8))) void {
|
||
|
const length = grid.items.len;
|
||
|
|
||
|
for (0..length - 1) |i| {
|
||
|
for (i + 1..length) |j| {
|
||
|
const temp = grid.items[i].items[j];
|
||
|
grid.items[i].items[j] = grid.items[j].items[i];
|
||
|
grid.items[j].items[i] = temp;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// flip a grid upside down
|
||
|
fn flipY(grid: *std.ArrayList(std.ArrayList(u8))) void {
|
||
|
const height = grid.items.len;
|
||
|
|
||
|
for (0..height / 2) |r| {
|
||
|
const temp = grid.items[r];
|
||
|
grid.items[r] = grid.items[height - r - 1];
|
||
|
grid.items[height - r - 1] = temp;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// flip a grid left to right
|
||
|
fn flipX(grid: *std.ArrayList(std.ArrayList(u8))) void {
|
||
|
const length = grid.items.len;
|
||
|
|
||
|
for (0..length) |r| {
|
||
|
for (0..length / 2) |c| {
|
||
|
const temp = grid.items[r].items[c];
|
||
|
grid.items[r].items[c] = grid.items[r].items[length - c - 1];
|
||
|
grid.items[r].items[length - c - 1] = temp;
|
||
|
}
|
||
|
}
|
||
|
}
|