Skip to content

Instantly share code, notes, and snippets.

@doeixd
Created December 4, 2023 13:11
Show Gist options
  • Save doeixd/b5ab68857bc183a441b841cd768053f4 to your computer and use it in GitHub Desktop.
Save doeixd/b5ab68857bc183a441b841cd768053f4 to your computer and use it in GitHub Desktop.
day3.mjs
let isTest = Deno.args.join('').match(/test\d?/)?.[0]
if (isTest && !/\d/.test(isTest.split('').at(-1))) isTest += '1'
let file = await Deno.readTextFile(`./${isTest || `input`}`)
file = file.trim('').split('\n')
let valid_parts_acc = 0
let gear_acc = 0
let part_number_map = {}
let gears = []
for (let line_idx in file) {
line_idx = +line_idx
part_number_map[line_idx] ||= {}
let line = file[line_idx]
let part_numbers = []
for (let char_idx in line) {
char_idx = +char_idx
let char = line[char_idx]
let char_is_digit = /\d/.test(char)
let prev_char_is_digit = /\d/.test(line[char_idx - 1])
let is_start_of_part_number = char_is_digit && !prev_char_is_digit
let is_tail_of_part_number = char_is_digit && prev_char_is_digit
if (is_start_of_part_number) part_numbers.push({ digits: [char], start: char_idx })
if (is_tail_of_part_number) part_numbers.at(-1).digits.push(char)
let is_gear = char == '*'
if (is_gear) gears.push({ char_idx, line_idx })
}
for (let part_number of part_numbers) {
for (let i = part_number.start; i < (part_number.digits.length + part_number.start); i++) {
part_number_map[line_idx][i] = part_number
}
let box_lines = make_get_box(line_idx)(part_number.start, part_number.digits.length)
let has_special = /[^\d\.]/
let part_number_int = parseInt(part_number.digits.join(''))
let is_vaild_part_number = box_lines
.map(l => has_special.test(l))
.some(l => l)
if (is_vaild_part_number) valid_parts_acc += part_number_int
}
}
for (let gear of gears) {
let box_lines = make_get_box(gear.line_idx)(gear.char_idx, 1, true).flat()
let adjecent_parts = new Set()
for (let { box_line_idx, box_char_idx } of box_lines) {
let part = part_number_map?.[box_line_idx]?.[box_char_idx]
part && adjecent_parts.add(part)
}
if (adjecent_parts.size !== 2) continue;
adjecent_parts = Array.from(adjecent_parts).map(l => parseInt(l.digits.join('')))
let ratio = (adjecent_parts[0]) * (adjecent_parts[1])
gear_acc += ratio
}
console.log(valid_parts_acc)
console.log()
console.log(gear_acc)
function make_get_box(line_idx) {
let previous_line = file?.[line_idx - 1] || ''
let line = file[line_idx]
let next_line = file?.[line_idx + 1] || ''
return function get_box(start, len = 1, just_indexes = false) {
let box_start = start == 0 ? 0 : start - 1
let number_end = len + start
let box_end = (number_end) == line.length ? line.length : (number_end) + 1
let lines = [previous_line, line, next_line]
.map(l => l.slice(box_start, box_end))
if (just_indexes) {
return lines.map((box_chars, box_line_idx) => {
let sub = box_line_idx == 0 ? 1 : box_line_idx == 1 ? 0 : -1
let real_line_idx = Math.min(Math.max(line_idx - sub, 0), file.length - 1)
let box_chars_idx = Array.from(box_chars).map((_box_char, box_char_idx) => {
return box_char_idx + box_start
})
return box_chars_idx.map(box_char_idx => {
return { box_line_idx: real_line_idx, box_char_idx }
})
})
}
return lines
}
}
@doeixd
Copy link
Author

doeixd commented Dec 4, 2023

day4

let isTest = Deno.args.join('').match(/test\d?/)?.[0]
if (isTest && !/\d/.test(isTest.split('').at(-1))) isTest += '1'

let file = await Deno.readTextFile(`./${isTest || `input`}`)
file = file.trim('').split('\n')

let total_points = 0
let total_cards = file.length

let cache = new Map()
let winnings_cache = new Map()

for (let line_idx in file) {
  let card_number = +line_idx + 1

  let card = get_card(card_number)
  total_points += card.number_of_points

  total_cards += card.get_winnings()
}

console.log({ total_points })
console.log({ total_cards })

// ----------------------------------------

function get_card(card_number) {
  if (cache.has(card_number)) return cache.get(card_number)

  let num = Math.max(parseInt(card_number) - 1, 0)
  let line = file?.[num]
  if (!line) return undefined

  let [_card, numbers] = line.trim().split(':')
  let [winning_numbers, our_numbers] = numbers.trim().split('|')

  let process = (nums) =>
    new Set(
      nums
        .trim()
        .split(/\s+/)
        .map((n) => +n)
    )
  winning_numbers = process(winning_numbers)
  our_numbers = process(our_numbers)

  let number_of_matches = get_number_of_matches({ our_numbers, winning_numbers })
  let number_of_points = Math.floor(2 ** (number_of_matches - 1))

  let result = {
    card_number,
    our_numbers,
    winning_numbers,
    number_of_matches,
    number_of_points,
    get_winnings() {
      let cards_won = get_cards(card_number, number_of_matches)

      let winnings = cards_won.length

      for (let card_won of cards_won) {
        let this_winnings = winnings_cache.has(card_won.card_number) ? winnings_cache.get(card_won.card_number) : card_won.get_winnings()
        winnings_cache.set(card_won.card_number, this_winnings)

        winnings += this_winnings
      }

      return winnings
    },
  }

  cache.set(card_number, result)

  return result
}

function get_cards(start, qty) {
  let cards = []

  let i = 1
  while (i <= qty) {
    let card = get_card(i + start)
    card && cards.push(card)
    i += 1
  }

  return cards
}

function get_number_of_matches({ winning_numbers, our_numbers }) {
  let number_of_matches = 0

  for (let our_number of our_numbers) {
    if (winning_numbers.has(our_number)) number_of_matches += 1
  }

  return number_of_matches
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment