Calculate the sum of invalid IDs (not included in the first section of the puzzle input) in nearby tickets. What's the sum (= ticket scanning error rate)?
const input = `
class: 1-3 or 5-7
row: 6-11 or 33-44
seat: 13-40 or 45-50
your ticket:
7,1,14
nearby tickets:
7,3,47
40,4,50
55,2,20
38,6,12
`.trim()
const sections = input.split('\n\n')
const validIds = sections[0]
.split('\n')
.reduce((ranges, line) => {
const [, value] = line.split(': ')
ranges.push(...value.split(' or '))
return ranges
}, [])
.reduce((ids, range) => {
const [min, max] = range.split('-').map((str) => +str)
ids.push(...Array.from({ length: max - min + 1 }, (_, i) => i + min))
return ids
}, [])
const idsInNearbyTickets = sections[2]
.split('\n')
.slice(1) // Skip header
.reduce((ids, ticketFields) => {
ids.push(...ticketFields.split(',').map((str) => +str))
return ids
}, [])
const ticketScanningErrorRate = idsInNearbyTickets
.filter((id) => !validIds.includes(id))
.reduce((sum, id) => sum + id)
console.log(ticketScanningErrorRate)
Discard nearby tickets that contain invalid IDs. Use the remaining valid tickets to determine which field is which. Then look for the six fields on
your ticket
that start with the worddeparture
. What's the result of multiplying those six values together?
A lazy-ass solution:
const sections = input.split('\n\n')
const fields = sections[0].split('\n').reduce((fields, line) => {
const [name, ranges] = line.split(': ')
const ids = ranges.split(' or ').reduce((ids, range) => {
const [min, max] = range.split('-').map((str) => +str)
ids.push(...Array.from({ length: max - min + 1 }, (_, i) => i + min))
return ids
}, [])
fields[name] = ids
return fields
}, {})
const validIds = Object.values(fields).reduce((validIds, ids) => {
validIds.push(...ids)
return validIds
}, [])
const yourTicket = sections[1]
.split('\n')[1] // Skip header
.split(',')
.map(Number)
const nearbyTickets = sections[2]
.split('\n')
.slice(1) // Skip header
.map((ticketFields) => ticketFields.split(',').map(Number))
const validNearbyTickets = nearbyTickets.filter((ids) =>
ids.every((id) => validIds.includes(id))
)
const idsInTickets = validNearbyTickets.reduce(
(ranges, ticket) => {
ticket.forEach((id, i) => ranges[i].push(id))
return ranges
},
yourTicket.map((id) => [id])
)
const possibleFieldIndexes = idsInTickets
.map((fieldIds) =>
Object.entries(fields)
.filter(([, ids]) => fieldIds.every((id) => ids.includes(id)))
.map(([name]) => name)
)
.reduce((acc, name, i) => {
acc[i] = name
return acc
}, {})
const fieldIndexes = assignFieldIndexes(
{},
Object.entries(possibleFieldIndexes)
)
const result = Object.entries(fieldIndexes)
.filter(([name]) => name.startsWith('departure'))
.map(([, index]) => index)
.reduce((acc, index) => acc * yourTicket[index], 1)
console.log(result)
function assignFieldIndexes(acc, entries) {
if (entries.length === 0) return acc
const index = entries.findIndex(([, fieldNames]) => fieldNames.length === 1)
const [fieldIndex, fieldNames] = entries[index]
const fieldName = fieldNames[0]
acc[fieldName] = fieldIndex
const newEntries = entries
.map(([i, names]) => [i, names.filter((name) => name !== fieldName)])
.filter(([, names]) => names.length !== 0)
return assignFieldIndexes(acc, newEntries)
}
Put console.log()
s after the intermediate variables
to see how the flow of the code works.
I'm too lazy to explain it
(plus I already forgot and can't bother trying to understand my own code 😂).
Nothing. 🍭