Alle Projekte

Advent of Code 2024

TypeScript

Not trying to win any medal in terms of conciseness or efficiency. Just trying to produce straightforward, readable code.

Day 1: Trebuchet?!

My Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const input =
`fivepqxlpninevh2xxsnsgg63pbvdnqptmg
eight8zlctbmsixhrvbpjb84nnmlcqkzrsix
hkxqfrqmsixfplbkpkdfzzszjxmdjtdkjlprrvr3gghlrqckqtbng`;
//.....(not pasting the whole input here)

let sum: number = 0;
const isNumberRegex = /^\d+$/;

for(const line of input.split("\n")) {
    let digitsInLine: string[] = [];

    for(const char of line) {
        if(isNumberRegex.test(char)) {
            digitsInLine.push(char);
        }
    }

    const resultNumber = (digitsInLine[0] ?? "") + (digitsInLine[digitsInLine.length - 1] ?? "");
    sum += parseInt(resultNumber) ?? 0;
}

console.log("Sum of all results:", sum);

Result: 53651




Day 2: Cube Conundrum

My Code:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
const inputGames =
`Game 1: 5 red, 1 green, 2 blue; 2 green, 8 blue, 6 red; 8 red, 3 blue, 2 green; 6 red, 1 green, 19 blue; 1 red, 17 blue
Game 2: 4 red, 5 green, 2 blue; 7 red, 14 green, 3 blue; 2 green, 5 blue, 11 red; 10 blue, 3 green; 9 green, 6 blue, 13 red; 7 red, 5 green, 9 blue
Game 3: 9 green, 18 blue, 1 red; 6 red, 10 blue, 5 green; 4 blue, 4 red, 15 green`;
//.....(not pasting the whole input here)

const inputCubesNumberInSack = new Map<CubeColor, number>([
  ["red", 12],
  ["green", 13],
  ["blue", 14],
]);

console.log(getSumOfPossibleGameIds());
console.log(getSumPowerOfMinimumRequiredCubeSets());

type CubeColor = "red" | "green" | "blue";

type Game = {
  id: number;
  rounds: Map<CubeColor, number>[];
  isPossible: boolean;
  powLowestPossibleCubeNums: number;
};

/** Riddle #1 */
function getSumOfPossibleGameIds(): number {
  let sumIdsOfPossibleGames = 0;

  for (const gameLine of inputGames.split("\n")) {
    const game = parseGame(gameLine);

    if (game.isPossible) {
      sumIdsOfPossibleGames += game.id;
    }
  }
  return sumIdsOfPossibleGames;
}

/** Riddle #2 */
function getSumPowerOfMinimumRequiredCubeSets(): number {
  let sumPowerOfMinimumRequiredCubeSets = 0;

  for (const gameLine of inputGames.split("\n")) {
    const game = parseGame(gameLine);
      sumPowerOfMinimumRequiredCubeSets += game.powLowestPossibleCubeNums;
    }
  return sumPowerOfMinimumRequiredCubeSets;
}

/** parses a string of the form "Game 1: 5 red, 1 green, 2 blue; 2 green, 8 blue, 6 red" to a Game object */
function parseGame(gameLine: string): Game {
  const sections = gameLine.split(": ");
  const gameId = parseInt(sections[0].split("Game ")[1]);
  const rounds = sections[1].split(";"); //i.e. ["1 blue, 4 green, 1 red", ...]

  const gameRounds = rounds.map((cubeColorStrings) =>
    parseGameRound(cubeColorStrings)
  );

  return {
    id: gameId,
    rounds: gameRounds,
    isPossible: isGamePossible(gameRounds),
    powLowestPossibleCubeNums: powerLowestPossibleCubeNums(gameRounds)
  };
}

/** parses a string of the form "1 blue, 4 green, 1 red" to a Map<CubeColor, number> */
function parseGameRound(cubeColorStrings: string): Map<CubeColor, number> {
  const gameRound = new Map<CubeColor, number>();

  cubeColorStrings = cubeColorStrings.trim();

  for (const gameRoundString of cubeColorStrings.split(",")) {
    const parts = gameRoundString.trim().split(" ");

    const cubeNumber = parseInt(parts[0].trim()) ?? 0;
    const cubeColor = parts[1].trim();

    gameRound.set(cubeColor as CubeColor, cubeNumber);
  }

  return gameRound;
}

function isGamePossible(gameRounds: Map<CubeColor, number>[]): boolean {
  for (const round of gameRounds) {
    const isRoundPossible =
      (round.get("red") ?? 0) <= inputCubesNumberInSack.get("red")! &&
      (round.get("green") ?? 0) <= inputCubesNumberInSack.get("green")! &&
      (round.get("blue") ?? 0) <= inputCubesNumberInSack.get("blue")!;

    if (!isRoundPossible) return false;
  }
  return true;
}

function powerLowestPossibleCubeNums(gameRounds: Map<CubeColor, number>[]) {

    let highestNumRed = 0;
    let highestNumGreen = 0;
    let highestNumBlue = 0;

    for (const round of gameRounds) {
        highestNumRed = Math.max(round.get("red") ?? 0, highestNumRed)
        highestNumGreen = Math.max(round.get("green") ?? 0, highestNumGreen)
        highestNumBlue = Math.max(round.get("blue") ?? 0, highestNumBlue)
    }

    return highestNumRed * highestNumGreen * highestNumBlue; 
}

Result #1: 2617

Result #2: 59795




Day 3: Gear Ratios

My Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
const input = 
`........440...............418..643.....438......740.261......................................727...........................870..............
...............338.............-........*.......*.......34&.$........@.....&742................................353..26.......*...188...238..
..................*369.....334.......624..749....533........690...894...........466......../....&......294....................1.............`;
//.....(not pasting the whole input here)

const lines = input.split("\n");
const lineWidth = lines[0].length;

console.log(getSumPartNumbers());

function getSumPartNumbers(): number {
  let sumPartNumbers = 0;
  
  for (let i = 0; i < lines.length; i++) {
    const line = lines[i];
    const matches = matchNumbersInLine(line);
    
    for(const match of matches) {
      const partNumber = match[0];
      const isAdjacent = isAdjacentToSymbol(i, match.index!, match[0].length);
    
      if(isAdjacent) sumPartNumbers += parseInt(match[0])
    }
  }

  return sumPartNumbers;
}

function matchNumbersInLine(line: string): RegExpMatchArray[] {
  const regexNumbers = /\d+/g;
  return [...line.matchAll(regexNumbers)];
} 

function isAdjacentToSymbol(lineNr: number, colStart: number, numberWidth: number): boolean {

  //adjacent to symbol west
  if( isSymbol(colStart > 0 && lines[lineNr][colStart - 1])  ) return true;
  
  //adjacent to symbol east
  if( isSymbol(colStart + numberWidth < lineWidth &&lines[lineNr][colStart + numberWidth])) return true;
  
  //adjacent to symbol north
  if(lineNr > 0) {
    const lineNorth = lines[lineNr - 1].substring(colStart-1, colStart + numberWidth + 1);
    for(const char of lineNorth) {
      if (isSymbol(char)) return true;
    }
  }
  
  //adjacent to symbol south
  if(lineNr < lines.length - 2) {
    const lineSouth = lines[lineNr + 1].substring(colStart-1, colStart + numberWidth + 1);
    for(const char of lineSouth) {
      if (isSymbol(char)) return true;
    }
  }

  return false;
}

function isSymbol(char: string | false): boolean {
  if(!char) return false;
  return !".123456789".includes(char[0])
}

Result: 532331




Day 4: Scratchcards

My Code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
const input = 
`Card   1: 17 15  5 75 36 13 16 66 92 39 | 13 92 16  5 87 78 15 94 21 48 30 62 70 41  3 39 22 17 77 58 75 52 83 34 24
Card   2: 72 64 18  5 58 94 25 59 75 51 | 34 17 48 75 25  8  2 94 64 29 33 92 73 12 51 38 27  4  1 60 31 85 59 18  5
Card   3: 71 16 97  6 68 38 82 93 33 24 | 31 75  7 99 10 70 79 61  5 80  1 33 58 30 22 48 73 72 50 16 56  4 98 43  3`;
//.....(not pasting the whole input here)

const lines = input.split("\n");

const points = lines.reduce((sum, line) => sum + cardValue(lineToCard(line)), 0);

console.log("Total points:", points)

type Card = {
  winningNumbers: string[],
  yourNumbers: string[],
}

function parseCard(line: string): Card {
  const numbers = line.split(": ")[1].split(" | ");

  return {
    winningNumbers: numbers[0].split(" ").filter(_ => _ != ""),
    yourNumbers: numbers[1].split(" ").filter(_ => _ != ""),
  }
}

function cardValue(card: Card): number {
  let winningNumbers = 0;

  for (const yourNumber of card.yourNumbers) {
    if(card.winningNumbers.includes(yourNumber)) {
      winningNumbers++;
    }
  }

  return winningNumbers == 0 ? 0 : Math.pow(2, (winningNumbers-1));
}

Result: 21558