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

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;
}
}
}