Skip to content

tmythicator/advent-of-code

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Advent of Code 2020

Day 1: Report Repair

Part 1

import { readFileSync } from 'fs';
const input: string = readFileSync('./2020/day1/input', 'utf-8');

console.time('Time taken');
let ans: number = 1;
const inpArr: string[] = input.split(/\n/).filter(x => x);

for (let i = 0; i < inpArr.length - 1; i++) {
    for (let j = i + 1; j < inpArr.length; j++) {
        if (Number(inpArr[i]) + Number(inpArr[j]) === 2020) {
            ans *= Number(inpArr[i]) * Number(inpArr[j]);
        }
    }
}
console.timeEnd('Time taken')
console.log(ans)

Part 2

import { readFileSync } from 'fs';
const input: string = readFileSync('./2020/day1/input', 'utf-8');

console.time('Time taken');
let ans: number = 1;
const inpArr: string[] = input.split(/\n/).filter(x => x);

for (let i = 0; i < inpArr.length - 2; i++) {
    for (let j = i + 1; j < inpArr.length - 1; j++) {
        for (let k = j + 1; k < inpArr.length; k++){
            if (Number(inpArr[i]) + Number(inpArr[j]) + Number(inpArr[k]) === 2020) {
                ans *= Number(inpArr[i]) * Number(inpArr[j]) * Number(inpArr[k]);
            }
        }
    }
}

console.timeEnd('Time taken')
console.log(ans)

Day 2: Password Philosophy

Part 1

import { readFileSync } from 'fs';
const input: string = readFileSync('./2020/day2/input', 'utf-8');

console.time('Time taken');
let ans: number = 0;
const inpArr: string[] = input.split(/\n/).filter(x => x);

interface PWPolicy {
    charToMatch: string;
    minOccur: number;
    maxOccur: number;
    pw: string;
}

inpArr.forEach(inpLine => {
    const pwPolicyArr: string[] = inpLine.split(/\s/);
    let pwPolicy: PWPolicy = {charToMatch: String(pwPolicyArr[1]).slice(0, -1),
                              minOccur: parseInt(pwPolicyArr[0].split('-')[0]),
                              maxOccur: parseInt(pwPolicyArr[0].split('-')[1]),
                              pw: String(pwPolicyArr[2])};

    const re = new RegExp(`[${pwPolicy.charToMatch}]`, 'g');

    if (pwPolicy.pw.match(re)?.length >= pwPolicy.minOccur && pwPolicy.pw.match(re)?.length <= pwPolicy.maxOccur) {
        ++ans;
    }
});

console.timeEnd('Time taken')
console.log(ans)

Part 2

import { readFileSync } from 'fs';
const input: string = readFileSync('./2020/day2/input', 'utf-8');

console.time('Time taken');
let ans: number = 0;
const inpArr: string[] = input.split(/\n/).filter(x => x);

interface PWPolicy {
    charToMatch: string;
    firstPos: number;
    secondPos: number;
    pw: string;
}

const verifyCharXOR = (x: string, y: string, compChar: string): boolean => {
    return (x === compChar) ? !(y === compChar) : (y === compChar);
}

inpArr.forEach(inpLine => {
    const pwPolicyArr: string[] = inpLine.split(/\s/);
    let pwPolicy: PWPolicy = {charToMatch: String(pwPolicyArr[1]).slice(0, -1),
                              firstPos: parseInt(pwPolicyArr[0].split('-')[0]),
                              secondPos: parseInt(pwPolicyArr[0].split('-')[1]),
                              pw: String(pwPolicyArr[2])};

    if(verifyCharXOR(pwPolicy.pw.charAt(pwPolicy.firstPos - 1), pwPolicy.pw.charAt(pwPolicy.secondPos - 1), pwPolicy.charToMatch)){
        ++ans;
    }
});

console.timeEnd('Time taken')
console.log(ans)

Day 3: Toboggan Trajectory

Part 1

import { readFileSync } from 'fs';
const input: string = readFileSync('./2020/day3/input', 'utf-8');

console.time('Time taken');
let ans: number = 0;
const inpArr: string[] = input.split(/\n/).filter(x => x);

interface SlopeParams {
    xLength: number;
    yLength: number;
    tree: string;
    openSquare: string;
}

interface TobboganParams {
    xPos: number;
    xMoveSpeed: number;
}

const sParams: SlopeParams = {
    xLength: inpArr[0].length,
    yLength: inpArr.length,
    tree: "#",
    openSquare: "."
};

let tParams: TobboganParams = {
    xMoveSpeed: 3,
    xPos: 0
};

inpArr.forEach(line => {
    if(line.charAt(tParams.xPos) === sParams.tree){
        ++ans;
    }
    tParams.xPos = (tParams.xPos + tParams.xMoveSpeed ) % sParams.xLength;
});

console.timeEnd('Time taken')
console.log(ans)

Part 2

import { readFileSync } from 'fs';
const input: string = readFileSync('./2020/day3/input', 'utf-8');

console.time('Time taken');
let ans: number = 1;
const inpArr: string[] = input.split("\n").filter(x => x);

interface SlopeParams {
    readonly xLength: number;
    readonly yLength: number;
    readonly tree: string;
    readonly openSquare: string;
    readonly slopes: [number, number][];
}

interface TobboganParams {
    numberEncounters: number;
    xPos: number;
    yPos: number;
}

const sParams: SlopeParams = {
    xLength: Number(inpArr[0].length),
    yLength: Number(inpArr.length),
    tree: "#",
    openSquare: ".",
    slopes: [[1, 1], [3, 1], [5, 1], [7, 1], [1, 2]]
};

let tParams: TobboganParams = {
    numberEncounters: 0,
    xPos: 0,
    yPos: 0
};

for(let slope of sParams.slopes){
    while(tParams.yPos < sParams.yLength) {

        if (inpArr[tParams.yPos].charAt(tParams.xPos) === sParams.tree){
            ++tParams.numberEncounters;
        }

        tParams.xPos = (tParams.xPos + slope[0]) % sParams.xLength;
        tParams.yPos += slope[1];
    }
    ans *= tParams.numberEncounters;

    // Refresh
    tParams.numberEncounters = 0;
    tParams.xPos = 0;
    tParams.yPos = 0;
}

console.timeEnd('Time taken')
console.log(ans)

Day 4: Passport Processing

Part 1

import { readFileSync } from 'fs';
const input: string = readFileSync('./2020/day4/input', 'utf-8');

console.time('Time taken');
const inpArr: string[] = input.split(/\n/);

type PassControl = {
    readonly reqFields: string[];
    validCounter: number;
}

type Passport = {
    detectedFields: string[]
};

let pControl: PassControl = {
    reqFields: ["byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"],
    validCounter: 0
}

let pass: Passport = { detectedFields: [] };

inpArr.forEach((line: string) => {
    if (line) {
        const keyVals: string[] = line.split(/\s/)
        keyVals.forEach(kv => {
            let key: string = kv.split(":")[0];
            pass.detectedFields.push(key);
        });

    }
    else {
        if(pControl.reqFields.every(x => {
            return pass.detectedFields.includes(x)
        })) {
            pControl.validCounter++;
        }

        pass = { detectedFields: [] };

    }
});

console.time('Time taken');
console.log(pControl.validCounter)

Part 2

import { readFileSync } from 'fs';
const input: string = readFileSync('./2020/day4/input', 'utf-8');

console.time('Time taken')
const inpArr: string[] = input.split(/\n/);
let pValidCounter: number = 0;

enum ReqFields {
    byr = "byr",
    iyr = "iyr",
    eyr = "eyr",
    hgt = "hgt",
    hcl = "hcl",
    ecl = "ecl",
    pid = "pid",
}

type Passport = {
    detectedFields: string[],
    hasInvalidFields: boolean;
};

let curPass: Passport = { detectedFields: [], hasInvalidFields: false };

const performFieldValidation = (field: string, val: string): boolean => {
    if (field === "cid")
        return true

    const fieldCasted: ReqFields = ReqFields[field as keyof typeof ReqFields];
    let re: RegExp;

    switch (fieldCasted) {
        case ReqFields.byr:
            re = new RegExp('^\\d{4}$');
            return re.test(val) && Number(val) >= 1920 && Number(val) <= 2002

        case ReqFields.iyr:
            re = new RegExp('^\\d{4}$');
            return re.test(val) && Number(val) >= 2010 && Number(val) <= 2020

        case ReqFields.eyr:
            re = new RegExp('^\\d{4}$');
            return re.test(val) && Number(val) >= 2020 && Number(val) <= 2030

        case ReqFields.hgt:
            re = new RegExp('^(\\d+)(cm|in)$');
            let matchRes: RegExpMatchArray = val.match(re);
            if (matchRes) {
                if (matchRes[2] === "cm") {
                    return Number(matchRes[1]) >= 150 && Number(matchRes[1]) <= 193
                } else if (matchRes[2] === "in") {
                    return Number(matchRes[1]) >= 59 && Number(matchRes[1]) <= 76;
                }
            }
            return false;

        case ReqFields.hcl:
            re = new RegExp('^#[0-9a-f]{6}$');
            return re.test(val);

        case ReqFields.ecl:
            re = new RegExp('(amb|blu|brn|gry|grn|hzl|oth)');
            return re.test(val);

        case ReqFields.pid:
            re = new RegExp('^\\d{9}$');
            return re.test(val);

        default:
            return false;
    }
}

inpArr.forEach((line: string) => {
    if (line === "") {
        if (!curPass.hasInvalidFields) {
            pValidCounter++;
            for (let enumVal in ReqFields) {
                if (!curPass.detectedFields.includes(enumVal)) {
                    pValidCounter--;
                    break;
                }
            }
        }
        curPass = { detectedFields: [], hasInvalidFields: false };
    }
    else if (!curPass.hasInvalidFields) {
        const keyVals: string[] = line.split(" ")
        keyVals.forEach(kv => {
            let kvs: string[] = kv.split(/:/);
            if (performFieldValidation(kvs[0], kvs[1])) {
                curPass.detectedFields.push(kvs[0]);
            } else {
                curPass.hasInvalidFields = true;
            }

        });
    }
});

console.timeEnd('Time taken')
console.log(pValidCounter)

Day 5: Binary Boarding

Part 1

import { readFileSync } from 'fs';
const input: string = readFileSync('./2020/day5/input', 'utf-8');

console.time('Time taken');
const seatsBinary: string[] = input.split(/\n/).filter(Boolean).map((seatCode) => {
    return seatCode
        .replaceAll(/[F|L]/g, "0")
        .replaceAll(/[B|R]/g, "1");
}).sort();

const maxSeatBinaryCode: string = seatsBinary[seatsBinary.length - 1];
const row: number = parseInt(maxSeatBinaryCode.slice(0, 7), 2);
const column: number = parseInt(maxSeatBinaryCode.slice(7, 10), 2);

console.timeEnd('Time taken')
console.log(row * 8 + column)

Part 2

import { readFileSync } from 'fs';
const input: string = readFileSync('./2020/day5/input', 'utf-8');

console.time('Time taken');
let ans: number = 0;

const getSeatID = (seatBinary: string) : number => {
    const row: number = parseInt(seatBinary.slice(0, 7), 2);
    const column: number = parseInt(seatBinary.slice(7, 10), 2);

    return row * 8 + column;
}

const seatsBinary: string[] = input.split(/\n/).filter(Boolean).map((seatCode) => {
    return seatCode
        .replaceAll(/[F|L]/g, "0")
        .replaceAll(/[B|R]/g, "1");
}).sort();

let prevSeat: number | null = null;

for(let seat of seatsBinary){
    let curSeat: number = getSeatID(seat);

    if( prevSeat !== null && curSeat - prevSeat === 2) {
        ans = curSeat - 1;
        break;
    }
    else{
        prevSeat = curSeat;
    }
}

console.timeEnd('Time taken')
console.log(ans)

Day 6: Custom Customs

Part 1

import { readFileSync } from 'fs';
const input: string = readFileSync('./2020/day6/input', 'utf-8');

console.time('Time taken')
let sumOfAnswers: number = 0;

input.split(/\n\n/).forEach(x => {
    sumOfAnswers += new Set([...x.replace(/\n/g, "")]).size;
});

console.timeEnd('Time taken')
console.log(sumOfAnswers);

Part 2

import { readFileSync } from 'fs';
const input: string = readFileSync('./2020/day6/input', 'utf-8');

console.time('Time taken')
let sumOfAnswers: number = 0;

input.split(/\n\n/).forEach(grp => {
    const allAnswers = new Set([...grp.replace(/\n/g, "")]);
    allAnswers.forEach(ans => {
        if(grp.split(/\n/).filter(Boolean).every(persAns => persAns.includes(ans))){
            ++sumOfAnswers;
        }
    });
});

console.timeEnd('Time taken')
console.log(sumOfAnswers);

Day 7: Handy Haversacks

Part 1

import { readFileSync } from 'fs';
const input: string = readFileSync('./2020/day7/input', 'utf-8');

console.time('Time taken')

const bagOfInterest: string = "shiny gold";
const re1 = /^([\w\s]+) bags contain /;
const re2 = /(\d+) ([\w\s]+) bag[s]?/;
const re2_g = /(\d+) ([\w\s]+) bag[s]?/g;

type BagContainer = {
    [k: string]: Set<string>;
};

let bagDict: BagContainer = {};
let ans: number = 0;

// Construct bag rules
input.split(/\n/).filter(Boolean).forEach(rule => {
    let myMatches;

    bagDict[rule.match(re1)[1]] = new Set();

    if (re2.test(rule)) {
        while ((myMatches = re2_g.exec(rule)) !== null) {
            bagDict[rule.match(re1)[1]].add(myMatches[2]);
        }
    }
});

const containsShinyGoldBags = (bag: string) => {
    const bagContents: Set<string> = bagDict[bag];

    if (bagContents.has(bagOfInterest)) {
        return true;
    } else {
        for (let containedBag of bagContents.values()) {
            if (containsShinyGoldBags(containedBag)) {
                return true;
            }
        }
    }
    return false;
}

// Seek for appropriate bags and count them
ans = Object.keys(bagDict).filter((x) => {
    return containsShinyGoldBags(x);
}).length;

console.timeEnd('Time taken')
console.log(`Answer: ${ans}`);

Part 2

import { readFileSync } from 'fs';
const input: string = readFileSync('./2020/day7/input', 'utf-8');

console.time('Time taken')

const bagOfInterest: string = "shiny gold";
const re1 = /^([\w\s]+) bags contain /;
const re2 = /(\d+) ([\w\s]+) bag[s]?/;
const re2_g = /(\d+) ([\w\s]+) bag[s]?/g;

type BagInfo = {
    amount: number,
    type: string;
};

type BagContainer = {
    [k: string]: Set<BagInfo>;
};

let bagDict: BagContainer = {};
let ans: number = 0;

// Construct bag rules
input.split(/\n/).filter(Boolean).forEach(rule => {
    let myMatches;

    bagDict[rule.match(re1)[1]] = new Set();

    if (re2.test(rule)) {
        while ((myMatches = re2_g.exec(rule)) !== null) {
            bagDict[rule.match(re1)[1]].add({
                amount: parseInt(myMatches[1]),
                type: myMatches[2]
            });
        }
    }
});

const getBagsNumber = (bag: string): number => {
    const bagContents: Set<BagInfo> = bagDict[bag];
    let bagsNumerTotal: number = 0;

    for (let containedBag of bagContents.values()) {
        bagsNumerTotal += containedBag.amount;
        bagsNumerTotal += getBagsNumber(containedBag.type) * containedBag.amount;
    }

    return bagsNumerTotal;
};

// Count all the bags needed for `bagOfInterest`
ans = getBagsNumber(bagOfInterest);
console.timeEnd('Time taken')
console.log(`Answer: ${ans}`);

Day 8: Handlheld Halting

Part 1

import { readFileSync } from 'fs';
const input: string = readFileSync('./2020/day8/input', 'utf-8');

console.time('Time taken')

enum Opcode {
    acc = "acc",
    jmp = "jmp",
    nop = "nop"
}

const execInstruction = (opcode: string, arg: number): number => {
    const opcodeCasted: Opcode = Opcode[opcode as keyof typeof Opcode];

    switch (opcodeCasted) {
        case Opcode.acc:
            ans += arg;
            return 1;
        case Opcode.jmp:
            return arg;
        case Opcode.nop:
            return 1;
    }
}

let ans: number = 0;
let currInstr: number = 0;
let instrVisited: Set<number> = new Set();
const instrList: string[] = input.split(/\n/).filter(Boolean);

while (!instrVisited.has(currInstr)) {
    const cmd: string[] = instrList[currInstr].split(/\s/);

    instrVisited.add(currInstr);
    currInstr += execInstruction(cmd[0], parseInt(cmd[1]));
}

console.timeEnd('Time taken')
console.log(`Answer: ${ans}`);

Releases

No releases published

Packages

No packages published