Kodekalender

Noen som skal prøve seg på kodekalender i år?

Disse pleier å være ganske bra:

Tidligere var det et par artige kalendere fra PST og kode24 også, men har ikke sett noe i år. Flere kalendere dere vet om?

I denne tråden kan vi poste løsninger/hint/annet. Bare pass på å bruke spoiler tags :wink:

(trykk på tannhjulet i knapperaden i editoren, velg “Skjul detaljer”)

Spoiler

Sånn som dette

3 Likes

Om jeg skal eller! Gleder meg :partying_face:

1 Like

PST sin CTF-kalender ble annonsert av twitt3rhai(anbefaler å følge denne da det plutselig dukker opp en CTF i blandt) og kan finnes her https://npst.no/ :slight_smile:

Jeg synes man bør frastå fra å diskutere aktive(dagens) oppgaver for både knowit og NPST siden disse har hatt premier/ansettelser(?) tidligere. AoC har så vidt jeg vet ikke noe premie, så der ødlegger det ikke for andre deltakere at løsninger/hint diskuteres.

2 Likes

Advent of code dag 1:

Kode

Litt brute force i dag. Går kanskje an å få det raskere? Var bare 200 elementer i lista, så prøvde ikke å optimalisere.

const fs = require('fs')

const numbers = fs.readFileSync('./day1.txt', 'utf-8').split('\n').map(n => parseInt(n, 10))

const part1 = () => {
    for(let i = 0; i < numbers.length; i++){
        for(let j = i + 1; j < numbers.length; j++){
            const sum = numbers[i] + numbers[j]
            if(sum === 2020){
                return numbers[i] * numbers[j]
            }
        }
    }
}

const part2 = () => {
    for(let i = 0; i < numbers.length; i++){
        for(let j = i + 1; j < numbers.length; j++){
            for(let k = j + 1; k < numbers.length; k++){
                const sum = numbers[i] + numbers[j] + numbers[k]
                if(sum === 2020){
                    return numbers[i] * numbers[j] * numbers[k]
                }
            }
        }
    }
}

console.log(part1())
console.log(part2())

Enig der! Kan poste dagen etterpå evt. Advent of code er bare en toppliste med de som er raskest, så der rekker du ikke poste noe her før du er ute av lista :stuck_out_tongue:

1 Like

Advent of code dag 2 nå på morgenkvisten :slight_smile: Jeg lo litt av oppgave 2, sånn appropos tråden om teknisk gjeld. Koden min har allerede litt av det

Kode
const fs = require('fs')

const passwords = fs.readFileSync('./day2.txt', 'utf-8')
    .split('\n')
    .map(line => {
        const matches = line.match(/^(\d+)-(\d+) ([a-z]): (.*)$/)
        return {
            policy: {
                letter: matches[3],
                min: parseInt(matches[1]),
                max: parseInt(matches[2])
            },
            pw: matches[4]
        }
    })

const isValidPasswordPart1 = ({ pw, policy }) => {
    const nChars = pw.split('').filter(letter => policy.letter === letter).length
    return policy.min <= nChars && policy.max >= nChars
}

const isValidPasswordPart2 = ({ pw, policy }) => {
    const chars = pw.split('')
    const hasFirst = chars[policy.min - 1] === policy.letter
    const hasSecond = chars[policy.max - 1] === policy.letter
    return hasFirst !== hasSecond // xor
}

const part1 = () => passwords.filter(isValidPasswordPart1).length
const part2 = () => passwords.filter(isValidPasswordPart2).length

console.log(part1())
console.log(part2())


1 Like

AOC dag 3:

Kode

Når jeg leste oppgave 1 tenkte jeg at oppgave 2 kom til å gå ut på å finne den veien med færrest trær. Var en del lettere enn det :slight_smile:

const fs = require('fs')

const matrix = fs.readFileSync('./day3.txt', 'utf-8').split('\n').map(line => line.split(''))
const height = matrix.length
const width = matrix[0].length

const countTrees = (x, y, xInc, yInc) => {
    let trees = 0
    while(y < height){
        if(matrix[y][x] === '#'){
            trees++
        }
        x = (x + xInc) % width
        y += yInc
    }
    return trees
}

const part1 = () => countTrees(0, 0, 3, 1)

const part2 = () => {
    return [
        countTrees(0, 0, 1, 1),
        countTrees(0, 0, 3, 1),
        countTrees(0, 0, 5, 1),
        countTrees(0, 0, 7, 1),
        countTrees(0, 0, 1, 2)
    ].reduce((solution, count) => solution * count)
}

console.log(part1())
console.log(part2())

Knowit dag 2 (i går):

Kode

Når jeg så at n var såpass stor gikk jeg rett for en prime sieve, men med det nice svaret tror jeg det hadde vært like greit å finne primtallene direkte. Kort og grei kode med en sieve heldigvis.

Først prøvde jeg å telle antall presanger som ble kastet, men fant ut at det var mye lettere å telle de som ikke ble kastet, for da slapp man å trekke fra eventuell overflow utover n.

const n = 5433000

const sieve = Array(n).fill(true)
sieve[0] = false
sieve[1] = false
for(let i = 2; i < n; i++){
    for(let j = i*2; j < n; j += i){
        sieve[j] = false
    }
}

const findNearestPrimeLte = x => {
    for(let i = x; i >= 0; i--){
        if(sieve[i]) return i
    }
}

let presentsKept = 0
let i = 0
while(i < n){
    if(i.toString().includes('7')){
        i += findNearestPrimeLte(i) + 1
        continue
    }
    presentsKept++
    i++
}

console.log(presentsKept)
1 Like

AOC dag 4:

Kode

Liten sjekk av regex kunnskaper i dag :slight_smile: Fikk brukt named capture groups, som er en relativt ny feature i javascript:

 const m = val.match(/^(?<height>\d+)(?<unit>cm|in)$/)

Irriterer meg litt over å måtte legge en ekstra sjekk for om m er null eller ikke. Hadde vært sweet å wrappe regex resultat i en maybe monad egentlig, så kunne man gjort en map på resultatet. Feks skulle jeg likt å skrevet:

val.match(/.../).map(({ groups }) => /* do stuff with groups */).value

…eller noe sånt

Løsningen:

const fs = require('fs')

const passports = fs.readFileSync('./day4.txt', 'utf-8').split('\n\n')
    .map(passportText => {
        return passportText.split(/\s/)
            .map(part => part.split(':'))
            .reduce((passport, [key, value]) => {
                passport[key] = value
                return passport
            }, {})
    })

const requiredKeys = ['byr', 'iyr', 'eyr', 'hgt', 'hcl', 'ecl', 'pid']
const hasAllRequiredKeys = passport => {
    const keys = Object.keys(passport)
    return requiredKeys.every(key => keys.includes(key))
}

const validByr = val => /^\d{4}$/.test(val) && val >= 1920 && val <= 2002
const validIyr = val => /^\d{4}$/.test(val) && val >= 2010 && val <= 2020
const validEyr = val => /^\d{4}$/.test(val) && val >= 2020 && val <= 2030

const validHeightCm = (height) => height >= 150 && height <= 193
const validHeightIn = (height) => height >= 59 && height <= 76
const validHgt = val => {
    const m = val.match(/^(?<height>\d+)(?<unit>cm|in)$/)
    if(!m) return false
    return m.groups.unit === 'cm' ? validHeightCm(m.groups.height) : validHeightIn(m.groups.height)
}
const validHcl = val => /^#[0-9a-f]{6}$/.test(val)
const validEcl = val => /^(amb|blu|brn|gry|grn|hzl|oth)$/.test(val)
const validPid = val => /^\d{9}$/.test(val)

const allValid = passport =>
    hasAllRequiredKeys(passport) &&
    validByr(passport.byr) &&
    validIyr(passport.iyr) &&
    validEyr(passport.eyr) &&
    validHgt(passport.hgt) &&
    validHcl(passport.hcl) &&
    validEcl(passport.ecl) &&
    validPid(passport.pid)

const part1 = () => passports.filter(hasAllRequiredKeys).length
const part2 = () => passports.filter(allValid).length

console.log(part1())
console.log(part2())

Knowit dag 3:

Kode

Cluet i denne var å unngå å måtte lage 8 ulike funksjoner for å traversere i ulike retninger. Så det var noen som gikk for diverse transponeringer av matrisen og den slags, men det var ganske enkelt uten også.

const matrix = fs.readFileSync('./dag3.txt', 'utf-8').split('\n').map(line => line.split(''))
const n = matrix.length

const checkWord = (chars, x, y, incX, incY) => {
    for(let i = 0; i < chars.length; i++){
        if(y >= n || y < 0) return false
        if(x >= n || x < 0) return false
        if(chars[i] !== matrix[y][x]){
            return false
        }
        x += incX
        y += incY
    }
    return true
}

const isWordHidden = (word) => {
    const chars = word.split('')
    for(let y = 0; y < n; y++){
        for(let x = 0; x < n; x++){
            if(checkWord(chars, x, y, 0, 1)) return true
            if(checkWord(chars, x, y, 0, -1)) return true
            if(checkWord(chars, x, y, 1, 0)) return true
            if(checkWord(chars, x, y, -1, 0)) return true
            if(checkWord(chars, x, y, 1, 1)) return true
            if(checkWord(chars, x, y, 1, -1)) return true
            if(checkWord(chars, x, y, -1, 1)) return true
            if(checkWord(chars, x, y, -1, -1)) return true
        }
    }
    return false
}

const solution = possibleWords.filter(word => !isWordHidden(word)).sort().join(',')
console.log(solution)
1 Like

Knowit dag 4:

Kode

Ganske rett frem:

const fs = require('fs')

const counts = fs.readFileSync('./dag4.txt', 'utf-8')
    .split('\n')
    .flatMap(line => line.split(', ').map(item => item.split(': ')))
    .reduce((counts, [name, num]) => {
        counts[name] += Number(num)
        return counts
    }, { sukker: 0, melk: 0, egg: 0, mel: 0 })

const solution = Math.min(
    Math.floor(counts.sukker / 2),
    Math.floor(counts.melk / 3),
    Math.floor(counts.mel / 3),
    Math.floor(counts.egg),
)

console.log(solution)

Knowit dag 5:

Kode

Styra noe j**** med denne fordi jeg leste oppgaven feil. Trodde den musa kunne løpe langs med samme veggen flere ganger, og dermed omkretse et areal som ikke var del av huset (aka en bakhage). Men det var jo mye lettere enn det, et eneste stort polygon. Kunne løst det med en formell, men siden jeg allerede var dypt inne i en annen tankerekke gikk jeg for å fargelegge utsida av huset, og telle opp ruter som ikke var fargelagt.

const fs = require('fs')

const letters = fs.readFileSync('./dag5.txt', 'utf-8').split('')

const getCoordKey = (x, y) => `${x}#${y}`
let wallPoints = {}
let x = 0
let y = 0
let i = 0
while(i < letters.length){
    const letter = letters[i]
    while(i < letters.length && letter === letters[i]){
        if(letter === 'H') x++
        if(letter === 'V') x--
        if(letter === 'O') y--
        if(letter === 'N') y++
        i++
        wallPoints[getCoordKey(x, y)] = {x, y}

    }
}

const xs = Object.values(wallPoints).map(coord => coord.x)
const ys = Object.values(wallPoints).map(coord => coord.y)

const minX = Math.min(...xs) - 1
const maxX = Math.max(...xs) + 1
const minY = Math.min(...ys) - 1
const maxY = Math.max(...ys) + 1

const colorMap = {}

const color = (x, y) => {
    let queue = [{x,y}]

    while(queue.length > 0){
        const {x,y} = queue.pop()
        if(x < minX || x > maxX) continue
        if(y < minY || y > maxY) continue
        const key = getCoordKey(x, y)
        if(colorMap.hasOwnProperty(key)){
            continue
        }
        colorMap[key] = true

        const wallOnRight = wallPoints[getCoordKey(x + 1, y)] && wallPoints[getCoordKey(x + 1, y + 1)]
        !wallOnRight && queue.push({x: x+1, y})

        const wallOnLeft = wallPoints[getCoordKey(x, y)] && wallPoints[getCoordKey(x, y+1)]
        !wallOnLeft && queue.push({x: x-1, y})

        const wallOnDown = wallPoints[getCoordKey(x, y + 1)] && wallPoints[getCoordKey(x+1, y + 1)]
        !wallOnDown && queue.push({x, y: y+1})

        const wallOnUp = wallPoints[getCoordKey(x, y)] && wallPoints[getCoordKey(x+1, y)]
        !wallOnUp && queue.push({x, y: y-1})
    }
}

color(minX, minY)

const outsideCount = Object.values(colorMap).length
const totalCount = (maxX - minX + 1) * (maxY - minY + 1)

console.log(totalCount - outsideCount)

Dagens knowit var det forresten en feil i oppgaveteksten som gjorde den umulig, så hvis noen andre har prøvd og gitt opp anbefaler jeg å prøve igjen nå.

1 Like

Knowit dag 6:

Kode

Etter at oppgaven ble fiksa var det ganske enkelt. Bare trekk fra en og en godteripose fra slutten til du har noe som er delelig med 127.

const fs = require('fs')

const candyBags = fs.readFileSync('./dag6.txt', 'utf-8').split(',').map(x => Number(x))
const nElves = 127

let totalCandies = candyBags.reduce((a, b) => a + b, 0)
candyBags.reverse().find(nCandies => {
    totalCandies -= nCandies
    return totalCandies % nElves === 0
})

console.log(totalCandies/nElves)

AOC dag 7

Kode

Gjorde lista om til en trestruktur (var ingen sirkulære avhengigheter), la til både children og parents for å gjøre live litt lettere. Oppgave 1 var bare å traversere oppover i treet, mens oppgave 2 var nedover i treet. La til memoisering i oppg 2, men det var egentlig ikke nødvendig.

const fs = require('fs')

const graph = fs.readFileSync('./day7.txt', 'utf-8')
    .split('\n')
    .map(line => {
        const [color, rest] = line.slice(0, line.length - 1)
            .replace(/ bags?/g, '')
            .split(' contain ')

        if(rest === 'no other'){
            return {color, contents: []}
        }

        const contents = rest.split(', ').map(str => {
            const m = /^(\d+) ([\w ]+)$/.exec(str)
            return {count: Number(m[1]), color: m[2]}
        })

        return { color, contents }
    })
    .reduce((graph, item) => {
        graph[item.color] = { children: item.contents, parents: [] }
        return graph
    }, {})

Object.entries(graph).forEach(([color, value]) => {
    value.children.forEach(child => {
        graph[child.color].parents.push(color)
    })
})

const traverseParents = (color, cb) => {
    graph[color].parents.forEach(parent => {
        cb(parent)
        traverseParents(parent, cb)
    })
}

const part1 = () => {
    const colors = []
    traverseParents('shiny gold', color => {
        colors.push(color)
    })

    console.log([...new Set(colors)].length)
}

const countCache = {}
const countBagsInside = (color) => {
    if(countCache[color]) return countCache[color]
    let count = 0
    graph[color].children.forEach(bag => {
        count += bag.count + bag.count * countBagsInside(bag.color)
    })
    countCache[color] = count
    return count
}

const part2 = () => {
    const count = countBagsInside('shiny gold')
    console.log(count)
}

part1()
part2()
1 Like

Knowit dag 7:

Sammendrag

Største utfordringa her var egentlig å skille trærne fra hverandre. Så kjapt at det var 2 spaces mellom hvert tre, og maks en space mellom greiner. Så gikk bare opp stammen på hvert tre og sjekket symmetri på hver linje.

Det var en annen kar jeg så som inverterte hvert tre og sjekket at den inverterte versjonen var lik den vanlige. Den synes jeg var ganske fin.

const fs = require('fs')

const lines = fs.readFileSync('./dag7.txt', 'utf-8').split('\n')

const isSymmetricAtHeight = (x, y) => {
    let blankCharsInARow = 0
    for(let i = x + 1, j = x - 1; i < lines[y].length && j >= 0; i++, j--){
        if(lines[y][i] === ' '){
            blankCharsInARow++
        }else{
            blankCharsInARow = 0
        }
        if(blankCharsInARow >= 2) break
        if(lines[y][i] !== lines[y][j]) return false
    }
    return true
}

const heightRange = Array(lines.length).fill(0).map((x, i) => i)
const isTreeSymmetric = (x) => heightRange.every(y => isSymmetricAtHeight(x, y))

const lastLine = lines[lines.length - 1]
const nSymmetricTrees = lastLine.split('').filter((char, x) => {
    if(char === '#'){
        return isTreeSymmetric(x)
    }
    return false
}).length

console.log(nSymmetricTrees)

Knowit dag 8:

Sammendrag

Denne begynte jeg på kl 23 i går kveld, så veldig fort og gæli med andre ord. Cluet var å iterere over alle byene, ikke alle punktene. Det var få byer og mange punkter.

const fs = require('fs')

const coordsByCity = {}
const cityRoute = []

fs.readFileSync('./dag8.txt', 'utf-8')
    .split('\n')
    .forEach(line => {
        const m = /^(.+): \((\d+), (\d+)\)/.exec(line)
        if(m){
            const x = Number(m[2])
            const y = Number(m[3])
            coordsByCity[m[1]] = {x, y, dt: 0}
        }else{
            cityRoute.push(line)
        }
    })

const getDistance = (x1, y1, x2, y2) => Math.abs(x2 - x1) + Math.abs(y2 - y1)

const addTimeForCity = (city, x, y) => {
    const coords = coordsByCity[city]
    const distance = getDistance(coords.x, coords.y, x, y)
    if(distance === 0) return
    if(distance < 5){
        coordsByCity[city].dt += 0.25
    }else if(distance < 20){
        coordsByCity[city].dt += 0.5
    }else if(distance < 50){
        coordsByCity[city].dt += 0.75
    }else{
        coordsByCity[city].dt += 1
    }
}

let x = 0
let y = 0
const cities = Object.keys(coordsByCity)
for(let city of cityRoute){
    const cityCoords = coordsByCity[city]

    if(cityCoords.x - x !== 0){
        const xDir = (cityCoords.x - x) > 0 ? 1 : -1
        x += xDir
        while(true){
            cities.forEach(city => addTimeForCity(city, x, y))
            if(x === cityCoords.x) break
            x += xDir
        }
    }

    if(cityCoords.y - y !== 0){
        const yDir = (cityCoords.y - y) > 0 ? 1 : -1
        y += yDir
        while(true){
            cities.forEach(city => addTimeForCity(city, x, y))
            if(y === cityCoords.y) break
            y += yDir
        }
    }
}

const times = Object.values(coordsByCity).map(c => c.dt)

const max = Math.max(...times)
const min = Math.min(...times)

console.log(max - min)

Sånn, det tok litt tid å komme i gang i år gitt, men nå blir det :smiley:

Knowit dag 2:

Kode
const population = 5433000
const primeCheck = (n) => {
    if (n <= 3) return n > 1
    if (n % 2 == 0 || n % 3 == 0) return false
    i = 5
    while (i**2 <= n){
        if (n % i == 0 || n % (i + 2) == 0) return false
        i += 6
    }
    return true
}   

const containsSeven = (number) => {
    return (number+"").includes("7")
}

const findClosestPrime = (number) => {
    if(primeCheck(number)){
         return number
    }else{
        return findClosestPrime(number-1)
    } 
 }

let packageNumber = 0
let packagesDelivered = 0

while (packageNumber <= population){
    if(containsSeven(packageNumber)){
        packageNumber += findClosestPrime(packageNumber) 
    }else{
        packagesDelivered++
    } 
    packageNumber++
}

console.log("Packages delivered:", packagesDelivered)

Må ærlig innrømme at jeg måtte google hvordan continue fungerte. Det er ikke et keyword jeg ser ofte, gøy :sunny:

1 Like

Knowit dag 4:

Sammendrag
const fs = require('fs')
const ingredients = [{sukker: 0}, {mel: 0}, {melk: 0}, {egg: 0}]    
const orders = fs.readFileSync('./luke4.txt', 'utf8')
    .split('\r\n')
    .map(order => order.split(", ").map(item => item.split(': ')))
    .flat()

ingredients.forEach(ingredient => {
    ingredient[Object.keys(ingredient)[0]] = orders
    .filter(item => {
         if(item[0] === Object.keys(ingredient)[0])
             return item
         })
    .map(item => item[1])
    .reduce((a,b) => Number(a)+Number(b))    
})

const numberOfCakes = Math.min(
    Math.floor(ingredients[0].sukker / 2),
    Math.floor(ingredients[1].mel / 3),
    Math.floor(ingredients[2].melk / 3),
    ingredients[3].egg
    )

console.log("Number of cakes made", numberOfCakes)

Woaæææ, måten du bruker reduce på er jo helt konge @mrloba . Viste ikke det var mulig! Skjønner ikke helt hvordan den funksjonen fungerer innser jeg nå, her må det læres. Jeg har til og med skrevet om ting en del ganger for å gjøre det litt mer clean, men regner med at min bruk av Object.keys kanskje er et tegn på at noe kan gjøre anderledes! :grin:

Sneaky rekursiv loop der :laughing: Clean!

Reduce er kjekk, den kan du gjøre alt med. Men den blir ikke alltid like leselig da.

Knowit dag 9:

Sammendrag

Game of life ftw

const fs = require('fs')

const matrix = fs.readFileSync('./dag9.txt', 'utf-8')
    .split('\n')
    .map(line => line.split('').map(value => ({ value, nextValue: value })))

const inBounds = (x, y) => x >= 0 && y >= 0 && x < matrix[0].length && y < matrix.length
const getMatrixPoint = (x, y) => inBounds(x, y) ? matrix[y][x] : null

function sickNeighboors(x, y){
    return [
        getMatrixPoint(x-1, y)?.value === 'S',
        getMatrixPoint(x+1, y)?.value === 'S',
        getMatrixPoint(x, y-1)?.value === 'S',
        getMatrixPoint(x, y+1)?.value === 'S',
    ].filter(x => x === true).length
}

function tick(){
    for(let y = 0; y < matrix.length; y++){
        for(let x = 0; x < matrix[0].length; x++){
            if(sickNeighboors(x, y) >= 2){
                matrix[y][x].nextValue = 'S'
            }
        }
    }

    let done = true
    for(let y = 0; y < matrix.length; y++){
        for(let x = 0; x < matrix[0].length; x++){
            if(matrix[y][x].value !== matrix[y][x].nextValue){
                done = false
            }
            matrix[y][x].value = matrix[y][x].nextValue
        }
    }

    return done
}

let nTicks = 1
while(true){
    const done = tick()
    if(done) break
    nTicks++
}

console.log(nTicks)

Knowit dag 10:

Sammendrag
const fs = require('fs')

const pointsByElf = fs.readFileSync('./dag10.txt', 'utf-8')
    .split('\n')
    .map(line => line.split(','))
    .flatMap(elves => elves.map((elf, i) => ({elf, points: elves.length - (i+1)})))
    .reduce((pointsByElf, {elf, points}) => {
        pointsByElf[elf] = (pointsByElf[elf] ?? 0) + points
        return pointsByElf
    }, {})

const [elf, points] = Object.entries(pointsByElf).sort((a, b) => a[1] > b[1] ? -1 : 1)[0]

console.log(elf + '-' + points)

Knowit dag 11:

Sammendrag
const fs = require('fs')

const hints = fs.readFileSync('./dag11.txt', 'utf-8').split('\n')

const minCharVal = 'a'.charCodeAt(0)
const rotateChar = (a, b) => (a + b) % 26
const toChar = x => String.fromCharCode(x + minCharVal)
const fromChar = x => x.charCodeAt(0) - minCharVal
const addCharVal = (x, val) => toChar(rotateChar(fromChar(x), val))

const getNextHintRow = (str) => {
    return str
        .slice(1)
        .split('')
        .map(char => addCharVal(char, 1))
        .map((char, i) => addCharVal(char, fromChar(str[i])))
        .join('')
}

const possiblePwStrings = (hint) => {
    const hintRows = [hint]
    for(let i = 0; i < hint.length - 1; i++){
        hintRows.push(getNextHintRow(hintRows[i]))
    }
    const hintCols = []
    for(let i = 0; i < hint.length; i++){
        let col = ''
        for(let j = 0; j < hint.length - 1; j++){
            col += hintRows[j][i] ?? ''
        }
        hintCols.push(col)
    }
    return hintCols
}

const password = 'eamqia'

const solution = hints.find(hint => {
    return possiblePwStrings(hint).some(str => str.includes(password))
})

console.log(solution)

(her ble jeg plutselig opptatt med et annet prosjekt)

Knowit dag 22:

Sammendrag
const fs = require('fs')

const items = fs.readFileSync('./dag22.txt', 'utf-8').split('\n')
    .map(line => {
        const [chars, ...rest] = line.split(' ')
        const names = rest.join('').slice(1, -1).split(',').map(name => name.toLowerCase())
        return {chars, names}
    })

const removeNameMatches = (chars, name) => {
    let pos = 0
    for(let char of name){
        pos = chars.indexOf(char, pos)
        if(pos === -1) return null
        chars = chars.slice(0, pos) + chars.slice(pos+1)
    }

    return chars
}

function getCount(item){
    let chars = item.chars
    let count = 0
    for(name of item.names){
        const nextChars = removeNameMatches(chars, name)
        if(nextChars !== null){
            chars = nextChars
            count++
        }
    }
    return count
}

const solution = items
    .map(getCount)
    .map((x, i) => ({x, i}))
    .sort((a,b) => b.x - a.x)
    [0].i

console.log(solution)

Merker at javascript har dårlig med standard bibliotek når jeg løser disse oppgavene. Neste år skal jeg installere lodash eller ramda fra dag 1. Litt misunnelig på python sitt stb lib egentlig, noen burde lage en kopi av det til js (hvis ikke det finnes allerede?)

1 Like

Knowit dag 23:

Sammendrag
const fs = require('fs')

const pointsByWord = fs.readFileSync('./dag23words.txt', 'utf-8').split('\n')
    .reduce((pointsByWord, line) => {
        const [word, points] = line.split(' ')
        pointsByWord[word] = Number(points)
        return pointsByWord
    }, {})

const lines = fs.readFileSync('./dag23.txt', 'utf-8').split('\n')
    .map(line => {
        const [name, words] = line.split(': ')
        return {name, words: words.split(' ')}
    })

const trimPrefix = str => str.slice(str.startsWith('jule') ? 4 : 0)

const getVowelCount = str => [...str.matchAll(/[aeiouyæøå]/g)].length

const getVowelBonus = (prevWord, currWord) => {
    const diff = getVowelCount(currWord) - getVowelCount(prevWord)
    if(diff <= 0) return 0
    const multiplier = currWord.startsWith('jule') ? 2 : 1
    return diff * multiplier
}

const getWordBaseScore = (word) => pointsByWord[trimPrefix(word)]

const until = (arr, check) => {
    const index = arr.findIndex(check)
    if(index === -1) return arr
    return arr.slice(0, index)
}

const getRepetitionDivisor = (prevWords, word) => until(prevWords.reverse(), w => trimPrefix(w) !== trimPrefix(word)).length + 1

const getWordScore = (prevWords, word) => {
    const baseScore = getWordBaseScore(word)
    const vowelBonus = prevWords.length > 0 ? getVowelBonus(prevWords[prevWords.length - 1], word) : 0
    const repetitionDivisor = getRepetitionDivisor(prevWords, word)
    return Math.floor((baseScore + vowelBonus) / repetitionDivisor)
}

const results = lines.reduce((results, line) => {
    const score = line.words
        .map((word, i) => getWordScore(line.words.slice(0, i), word))
        .reduce((a, b) => a + b, 0)

    results[line.name] = (results[line.name] ?? 0) + score
    return results
}, {})

console.log(Object.entries(results).map(x => x.join(',')).join('\n'))

Og dag 24:

Sammendrag

Chill avslutning :slight_smile:

const fs = require('fs')

const houses = fs.readFileSync('./dag24.txt', 'utf-8').split('')

let remaining = 10
let total = 0
let i = 0
while(remaining > 0){
    let house = houses[i++]
    remaining--
    if(house === '1') remaining += 2
    total++
}

console.log(total)
1 Like