2021-12-03 09:36:46 -06:00
|
|
|
import { collectArray, inputLines, measureDuration } from "./common.ts";
|
|
|
|
const input = await collectArray(await inputLines("3"));
|
|
|
|
|
|
|
|
type SubmarineCommand = ["forward", number] | ["up", number] | ["down", number];
|
|
|
|
|
2021-12-03 11:47:18 -06:00
|
|
|
type Counters = [zeroCount: number, oneCount: number][];
|
|
|
|
|
2021-12-03 09:36:46 -06:00
|
|
|
const ASCII_ZERO = "0".charCodeAt(0);
|
2021-12-03 11:47:18 -06:00
|
|
|
|
|
|
|
function countBits(
|
|
|
|
input: string[],
|
|
|
|
width?: number,
|
|
|
|
windowWidth?: number,
|
|
|
|
): Counters {
|
|
|
|
if (!width) width = input[0].length;
|
|
|
|
if (!windowWidth) windowWidth = width;
|
|
|
|
const counter: Counters = Array.from(Array(width), (_) => [0, 0]);
|
|
|
|
for (const l of input) {
|
|
|
|
for (let i = width - windowWidth; i < width; i++) {
|
|
|
|
const val = l.charCodeAt(i) - ASCII_ZERO;
|
|
|
|
counter[i][val]++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return counter;
|
|
|
|
}
|
|
|
|
|
2021-12-03 09:36:46 -06:00
|
|
|
export function part1(input: string[]): number {
|
2021-12-03 11:47:18 -06:00
|
|
|
const width = input[0].length;
|
|
|
|
const counter = countBits(input);
|
|
|
|
const ones = [...Array(width).keys()].reduce((acc, i) =>
|
|
|
|
acc += (counter[i][1] >= counter[i][0]) ? (1 << i) : 0
|
|
|
|
);
|
|
|
|
// xor with a mask the same size as the width to get the zeroes value
|
|
|
|
console.log("oz:", ones);
|
|
|
|
return ones * (ones ^ (Math.pow(2, width) - 1));
|
|
|
|
}
|
|
|
|
|
|
|
|
await measureDuration(() => console.log("Part 1", part1(input)));
|
|
|
|
|
|
|
|
export function part2(input: string[]): number {
|
|
|
|
// I hate this.
|
2021-12-03 09:36:46 -06:00
|
|
|
const width = input[0].length;
|
|
|
|
const counter = Array.from(Array(width), (_) => [0, 0]);
|
|
|
|
for (const l of input) {
|
|
|
|
for (let i = 0; i < width; i++) {
|
|
|
|
const val = l.charCodeAt(i) - ASCII_ZERO;
|
|
|
|
counter[i][val]++;
|
|
|
|
}
|
|
|
|
}
|
2021-12-03 11:47:18 -06:00
|
|
|
let oxyGenRating = null;
|
|
|
|
let coScrubRating = null;
|
|
|
|
let oxyGenCandidates = input.slice(0);
|
|
|
|
let coScrubCandidates = input.slice(0);
|
2021-12-03 09:36:46 -06:00
|
|
|
for (let i = 0; i < width; i++) {
|
2021-12-03 11:47:18 -06:00
|
|
|
const newOxyGenCandidates: string[] = [];
|
|
|
|
const newCoScrubCandidates: string[] = [];
|
|
|
|
// console.log(counter[i]);
|
|
|
|
const moreCommon = (counter[i][1] > counter[i][0] ? 1 : 0).toString();
|
|
|
|
// console.log(i, width, moreCommon);
|
|
|
|
if (!oxyGenRating) {
|
|
|
|
for (const binnum of oxyGenCandidates) {
|
|
|
|
if (binnum[i] == moreCommon) newOxyGenCandidates.push(binnum);
|
|
|
|
}
|
|
|
|
if (newOxyGenCandidates.length == 1) {
|
|
|
|
oxyGenRating = parseInt(newOxyGenCandidates[0], 2);
|
|
|
|
/*
|
|
|
|
console.log(
|
|
|
|
"Oxygen Generator Rating:",
|
|
|
|
oxyGenRating,
|
|
|
|
oxyGenCandidates,
|
|
|
|
newOxyGenCandidates,
|
|
|
|
);
|
|
|
|
*/
|
|
|
|
} else oxyGenCandidates = newOxyGenCandidates;
|
|
|
|
// console.log(oxyGenCandidates);
|
|
|
|
}
|
|
|
|
if (!coScrubRating) {
|
|
|
|
for (const binnum of coScrubCandidates) {
|
|
|
|
if (binnum[i] != moreCommon) newCoScrubCandidates.push(binnum);
|
|
|
|
}
|
|
|
|
if (newCoScrubCandidates.length == 1) {
|
|
|
|
coScrubRating = parseInt(newCoScrubCandidates[0], 2);
|
|
|
|
/*
|
|
|
|
console.log(
|
|
|
|
"CO2 Scrubber Rating:",
|
|
|
|
coScrubRating,
|
|
|
|
coScrubCandidates,
|
|
|
|
newCoScrubCandidates,
|
|
|
|
);
|
|
|
|
*/
|
|
|
|
} else coScrubCandidates = newCoScrubCandidates;
|
|
|
|
// console.log(coScrubCandidates);
|
|
|
|
}
|
2021-12-03 09:36:46 -06:00
|
|
|
}
|
2021-12-03 11:47:18 -06:00
|
|
|
return (oxyGenRating || 0) * (coScrubRating || 0);
|
2021-12-03 09:36:46 -06:00
|
|
|
}
|
|
|
|
|
2021-12-03 11:47:18 -06:00
|
|
|
// await measureDuration(() => console.log("Part 2", part2(input)));
|