Skip to content

Latest commit

 

History

History
2175 lines (1929 loc) · 60.7 KB

README.md

File metadata and controls

2175 lines (1929 loc) · 60.7 KB

Advent of Code 2024

DataWeave scripts used in the adventofcode.com site for 2024.

I used the DataWeave extension for VS Code to create these scripts. Most of them should run in the DataWeave Playground with no issue. However, some of the more complex examples have to run with the DataWeave CLI.

To run any script with the CLI, you can use the following syntax (or use my ProstDev Tools VSCode extension):

dw run -i payload=<path to payload file> -f <path to transform.dwl file>

For example:

dw run -i payload=scripts/day1/part1/inputs/payload.csv -f scripts/day1/part1/transform.dwl

If there's no input, just remove the -i payload=<file> part.

You can filter the challenges using one of the following keywords (ctrl+F or cmd+F):

  • Keywords: csv, math, regex, reduce, strings, lines, matrix, ordering, two inputs, rules, navigation, recursive, tree, comparisons/matching

Similar repos

Table of Contents

Total stars: ⭐️ 31 / 50

🔹 Day 1

  • Challenge: Historian Hysteria

  • Keywords: csv, math

  • Example input:

    3   4
    4   3
    2   5
    1   3
    3   9
    3   3
    

⭐️ Part 1

Script
%dw 2.0
input payload application/csv separator=" ", header=false
output application/json
var a = payload.column_0 orderBy $
var b = payload.column_3 orderBy $
---
(0 to sizeOf(a)-1) map (abs(a[$] - b[$])) then sum($)

⭐️⭐️ Part 2

Script
import countBy from dw::core::Arrays
var p = read(payload, "application/csv", {header:false,separator:" "})
var a = p.column_0
var b = p.column_3
---
a map ((item) -> 
    (b countBy ($==item)) * item
) then sum($)

🔹 Day 2

7 6 4 2 1
1 2 7 8 9
9 7 6 2 1
1 3 2 4 5
8 6 4 4 1
1 3 6 7 9

⭐️ Part 1

Script
import every, countBy from dw::core::Arrays
var decreasing = "decreasing"
var increasing = "increasing"
---
((payload splitBy "\n") map (
    (($ splitBy " ") reduce ((number, a=[]) -> 
        if (isEmpty(a)) a+{
            prevNum: number,
            operation: null,
            isSafe: true
        } else (a[-1].operation match {
            case null -> a+{
                prevNum: number,
                operation: if (a[-1].prevNum-number > 0) decreasing else increasing,
                isSafe: [1, 2, 3] contains abs(a[-1].prevNum - number) 
            }
            case "$(decreasing)" -> a+{
                prevNum: number,
                operation: a[-1].operation,
                isSafe: [1, 2, 3] contains (a[-1].prevNum - number)
            }
            else -> a+{
                prevNum: number,
                operation: a[-1].operation,
                isSafe: [1, 2, 3] contains (number - a[-1].prevNum)
            }
        })
    )).isSafe every $
)) countBy $

⭐️⭐️ Part 2

Horrible code. But I did what I had to do :(

Script
import every, countBy from dw::core::Arrays
var decreasing = "decreasing"
var increasing = "increasing"
var newp = ((payload splitBy "\n") map (
    (($ splitBy " ") reduce ((number, a=[]) -> 
        if (isEmpty(a)) a+{
            prevNum: number,
            operation: null,
            isSafe: true
        } else (a[-1].operation match {
            case null -> a+{
                prevNum: number,
                operation: if (a[-1].prevNum-number > 0) decreasing else increasing,
                isSafe: [1, 2, 3] contains abs(a[-1].prevNum - number) 
            }
            case "$(decreasing)" -> a+{
                prevNum: number,
                operation: a[-1].operation,
                isSafe: [1, 2, 3] contains (a[-1].prevNum - number)
            }
            else -> a+{
                prevNum: number,
                operation: a[-1].operation,
                isSafe: [1, 2, 3] contains (number - a[-1].prevNum)
            }
        })
    ))
))
var safeOnes = newp filter ((item) -> item.isSafe every $)
var unsafeOnes = newp -- safeOnes
fun getScenarios(data) = data map ($ reduce ((number, a=[]) ->
    if (isEmpty(a)) a+{
        prevNum: number,
        operation: null,
        isSafe: true
    } else (a[-1].operation match {
        case null -> a+{
            prevNum: number,
            operation: if (a[-1].prevNum-number > 0) decreasing else increasing,
            isSafe: [1, 2, 3] contains abs(a[-1].prevNum - number) 
        }
        case "$(decreasing)" -> a+{
            prevNum: number,
            operation: a[-1].operation,
            isSafe: [1, 2, 3] contains (a[-1].prevNum - number)
        }
        else -> a+{
            prevNum: number,
            operation: a[-1].operation,
            isSafe: [1, 2, 3] contains (number - a[-1].prevNum)
        }
    })
))
---
unsafeOnes map ((firstArray) -> 
    getScenarios(firstArray.prevNum map ((number, numIndex) -> 
        firstArray.prevNum filter ((item, index) -> index != numIndex)
    )) filter ((item) -> item.isSafe every $)
) filter (!isEmpty($)) 
then sizeOf($)+sizeOf(safeOnes)

🔹 Day 3

  • Challenge: Mull It Over
  • Keywords: regex, reduce, strings
  • Example inputs:
xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))
xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))

⭐️ Part 1

Script
(flatten(payload scan /mul\(\d+,\d+\)/)) map do {
    var nums = flatten($ scan /\d+/)
    ---
    nums[0] * nums[1]
} then sum($)

⭐️⭐️ Part 2

Script
(payload scan /(mul|don't|do)\(\d*,?\d*\)/) reduce ((op, a={r:0,"do":true}) -> 
    op[0][0 to 2] match {
        case "mul" -> do {
            var nums = flatten(op[0] scan /\d+/)
            var newR = a.r + ((nums[0] default 0) * (nums[1] default 0))
            ---
            {
                r: if (a."do") newR else a.r,
                "do": a."do"
            }
        }
        case "don" -> { r: a.r, "do": false }
        else -> { r: a.r, "do": true }
    }
) then $.r

🔹 Day 4

MMMSXXMASM
MSAMXMSMSA
AMXSXMAAMM
MSAMASMSMX
XMASAMXAMM
XXAMMXXAMA
SMSMSASXSS
SAXAMASAAA
MAMMMXMMMM
MXMXAXMASX
M.S
.A.
M.S

⭐️ Part 1

Script
var lines = payload splitBy "\n"
var XMAS = "XMAS"
fun getLetter(x:Number,y:Number) = if ((x<0) or (y<0)) "" else (lines[x][y] default "")
fun getStr(str:String,x:Number,y:Number) = if ((x<0) or (y<0)) "" else (str[x to y])
---
flatten
(lines map ((lineStr, lineidx) -> 
    (lineStr splitBy "") map ((letter, letteridx) ->
        if (letter=="X") (
            // right
            (if (XMAS == getStr(lineStr,letteridx,letteridx+3)) 1 else 0)
            // left
            + (if (XMAS == getStr(lineStr,letteridx,letteridx-3)) 1 else 0)
            // down
            + (if (XMAS == (letter ++ getLetter(lineidx+1,letteridx) ++ getLetter(lineidx+2,letteridx) ++ getLetter(lineidx+3,letteridx))) 1 else 0)
            // // up
            + (if (XMAS == (letter ++ getLetter(lineidx-1,letteridx) ++ getLetter(lineidx-2,letteridx) ++ getLetter(lineidx-3,letteridx))) 1 else 0)
            // down-right
            + (if (XMAS == (letter ++ getLetter(lineidx+1,letteridx+1) ++ getLetter(lineidx+2,letteridx+2) ++ getLetter(lineidx+3,letteridx+3))) 1 else 0)
            // down-left
            + (if (XMAS == (letter ++ getLetter(lineidx+1,letteridx-1) ++ getLetter(lineidx+2,letteridx-2) ++ getLetter(lineidx+3,letteridx-3))) 1 else 0)
            // up-right
            + (if (XMAS == (letter ++ getLetter(lineidx-1,letteridx+1) ++ getLetter(lineidx-2,letteridx+2) ++ getLetter(lineidx-3,letteridx+3))) 1 else 0)
            // up-left
            + (if (XMAS == (letter ++ getLetter(lineidx-1,letteridx-1) ++ getLetter(lineidx-2,letteridx-2) ++ getLetter(lineidx-3,letteridx-3))) 1 else 0)
        )
        else 0
    )
)) then sum($)

⭐️⭐️ Part 2

Script
var lines = payload splitBy "\n"
fun getLetter(x:Number,y:Number) = if ((x<0) or (y<0)) "" else (lines[x][y] default "")
var xmas = ["MAS", "SAM"]
---
flatten
(lines map ((lineStr, lineidx) -> 
    (lineStr splitBy "") map ((letter, letteridx) ->
        if (letter=="A") do {
            var topleft = getLetter(lineidx-1, letteridx-1)
            var topright = getLetter(lineidx-1, letteridx+1)
            var bottomleft = getLetter(lineidx+1, letteridx-1)
            var bottomright = getLetter(lineidx+1, letteridx+1)
            var cross1 = topleft ++ letter ++ bottomright
            var cross2 = topright ++ letter ++ bottomleft
            ---
            if ( (xmas contains cross1) and (xmas contains cross2) ) 1 else 0
        }
        else 0
    )
)) then sum($)

🔹 Day 5

  • Challenge: Print Queue
  • Keywords: lines, ordering, two inputs, rules
  • Example input:
47|53
97|13
97|61
97|47
75|29
61|13
75|53
29|13
97|29
53|29
61|53
97|53
61|29
47|13
75|47
97|75
47|61
75|61
47|29
75|13
53|13

75,47,61,53,29
97,61,53,29,13
75,29,13
75,97,47,61,53
61,13,29
97,13,75,29,47

⭐️ Part 1

Script
import every from dw::core::Arrays
import substringBefore, substringAfter from dw::core::Strings
var p = payload splitBy "\n\n"
var orderingRules = p[0]
var updatesLines = p[1]splitBy "\n"
fun flatScan(a,b) = flatten(a scan b)
---
updatesLines map ((line, lineidx) -> do {
    var arr = (line splitBy ",")
    var isCorrect = (arr map ((num, numindex) -> 
        ((orderingRules flatScan "$(num)\|\d+|\d+\|$(num)") map (
            ((arr[numindex+1 to -1] default "") contains ($ substringBefore "|"))
            or ((if(numindex==0) "" else arr[numindex-1 to 0]) contains ($ substringAfter "|"))
        )) every (!$)
    )) every ($)
    ---
    if (isCorrect) arr[round(sizeOf(arr)/2)-1] as Number
    else 0
}) then sum($)

⭐️⭐️ Part 2 (unsolved)

tbd

🔹 Day 6

  • Challenge: Guard Gallivant
  • Keywords: matrix, navigation, recursive
  • Example input:
....#.....
.........#
..........
..#.......
.......#..
..........
.#..^.....
........#.
#.........
......#...

⭐️ Part 1

Script
output application/json
type Coordinates = {x:Number,y:Number}
var matrix = (payload splitBy "\n") map ($ splitBy "")
var guardPositions = ["^", "<", ">", "v"]
fun getChar(matrix:Array<Array<String>>,y:Number,x:Number):String = if ((x<0) or (y<0)) "" else (matrix[y][x] default "")
fun turnGuard(guard:String):String = guard match {
    case "^" -> ">"
    case ">" -> "v"
    case "v" -> "<"
    case "<" -> "^"
}
fun getInFrontCoord(guard:String,y:Number,x:Number):Coordinates = guard match {
    case "^" -> {y:y-1,x:x}
    case ">" -> {y:y,x:x+1}
    case "<" -> {y:y,x:x-1}
    case "v" -> {y:y+1,x:x}
}
fun getRoute(matrix:Array, coords=[]) = flatten(matrix map ((line, lineindex) -> 
    flatten(line map ((char, charindex) -> do {
        @Lazy
        var inFrontCoords = getInFrontCoord(char, lineindex, charindex)
        @Lazy
        var inFrontChar = getChar(matrix,inFrontCoords.y, inFrontCoords.x)
        @Lazy
        var guardCoords:Coordinates = {x:charindex,y:lineindex}
        ---
        if (guardPositions contains char) inFrontChar match {
            case "." -> getRoute(matrix update {
                case c at [inFrontCoords.y][inFrontCoords.x] -> char
                case g at [guardCoords.y][guardCoords.x] -> "."
            }, coords + guardCoords)
            case "#" -> getRoute(matrix update {
                case g at [guardCoords.y][guardCoords.x] -> turnGuard(char)
            }, coords)
            else -> coords
        }
        else null
    }))
))
---
sizeOf(getRoute(matrix) distinctBy $)

⭐️⭐️ Part 2 (unsolved)

tbd

🔹 Day 7

  • Challenge: Bridge Repair
  • Keywords: math, lines, recursive, tree
  • Example input:
190: 10 19
3267: 81 40 27
83: 17 5
156: 15 6
7290: 6 8 6 15
161011: 16 10 13
192: 17 8 14
21037: 9 7 18 13
292: 11 6 16 20

⭐️ Part 1

Script
%dw 2.0
import drop from dw::core::Arrays
import lines from dw::core::Strings
fun flatScan(a, b) = flatten(a scan b)
fun getResults(values, r=0) = do {
    var this = values[0]
    var next = values[1]
    var newValues = values drop 1
    ---
    if (isEmpty(next)) r
    else if (r==0) flatten([getResults(newValues, this+next), getResults(newValues, this*next)])
    else flatten([getResults(newValues, r+next),  getResults(newValues, r*next)])
}
---
lines(payload) map ((equation, equationIndex) -> do {
    var nums = equation flatScan /\d+/
    var result = nums[0] as Number
    var values = nums[1 to -1] map ($ as Number)
    ---
    if (getResults(values) contains result) result else 0
}) then sum($)

⭐️⭐️ Part 2

Script
%dw 2.0
import drop from dw::core::Arrays
import lines from dw::core::Strings
fun flatScan(a, b) = flatten(a scan b)
fun getResults(values, r=0) = do {
    var this = values[0]
    var next = values[1]
    var newValues = values drop 1
    ---
    if (isEmpty(next)) r
    else if (r==0) flatten([getResults(newValues, this+next), getResults(newValues, this*next), getResults(newValues, "$this$next" as Number)])
    else flatten([getResults(newValues, r+next),  getResults(newValues, r*next), getResults(newValues, "$r$next" as Number)])
}
---
lines(payload) map ((equation, equationIndex) -> do {
    var nums = equation flatScan /\d+/
    var result = nums[0] as Number
    var values = nums[1 to -1] map ($ as Number)
    ---
    if (getResults(values) contains result) result else 0
}) then sum($)

🔹 Day 8

............
........0...
.....0......
.......0....
....0.......
......A.....
............
............
........A...
.........A..
............
............

⭐️ Part 1

Script
import lines, isAlphanumeric from dw::core::Strings
output application/json
fun getChar(arr:Array<String>,x:Number,y:Number):String = if ((x<0) or (y<0)) "" else (arr[y][x] default "")
fun isAntenna(char:String) = isAlphanumeric(char)
fun getAntinodesBetween(coord1, coord2) = do {
    var x1 = coord1.x + coord1.x - coord2.x
    var y1 = coord1.y + coord1.y - coord2.y
    var x2 = coord2.x + coord2.x - coord1.x
    var y2 = coord2.y + coord2.y - coord1.y
    ---
    [
        {
            antinodeChar: getChar(payloadArr,x1,y1),
            antinodeCoords: {
                x: x1,
                y: y1
            }
        },
        {
            antinodeChar: getChar(payloadArr,x2,y2),
            antinodeCoords: {
                x: x2,
                y: y2
            }
        }
    ]
}
var payloadArr = lines(payload)
var antennas = flatten(payloadArr map ((line, y) -> 
    (line splitBy "") map ((char, x) -> 
        if (isAntenna(char)) {
            char: char,
            coords: {
                x: x,
                y: y,
            }
        } else {}
    ) filter (!isEmpty($))
) filter (!isEmpty($)))
---
antennas groupBy ($.char) 
pluck ((frequencies, frequencyGroup, index) -> do {
    @Lazy
    var sizeOfFrequencies = sizeOf(frequencies)
    @Lazy
    var numbers = 0 to sizeOfFrequencies-1
    ---
    if (sizeOfFrequencies >= 2) 
        flatten(frequencies map ((frequency, fi) -> 
            flatten((numbers - fi) map ((number) -> 
                (getAntinodesBetween(frequency.coords,frequencies[number].coords) filter (!isEmpty($.antinodeChar)))
            ))
        ))
    else []
}) 
then flatten($) distinctBy $ 
then sizeOf($)

⭐️⭐️ Part 2

Script
import lines, isAlphanumeric from dw::core::Strings
output application/json
type Coords = {
    x:Number,
    y:Number
}
type Frequency = {
    char:String,
    coords:Coords
}
fun getChar(arr:Array<String>,x:Number,y:Number):String = if ((x<0) or (y<0)) "" else (arr[y][x] default "")
fun isAntenna(char:String):Boolean = isAlphanumeric(char)
fun getAntinodesBetween(coord1:Coords, coord2:Coords, times:Number) = do {
    var x = coord1.x + ((times+1) * (coord2.x - coord1.x))
    var y = coord1.y + ((times+1) * (coord2.y - coord1.y))
    var char = getChar(payloadArr,x,y)
    ---
    [
        ({
            char: char,
            coords: {
                x: x,
                y: y
            }
        }) if (!isEmpty(char)),
    ] 
}
var payloadArr:Array<String> = lines(payload)
var antennas = flatten(payloadArr map ((line, y) -> 
    (line splitBy "") map ((char, x) -> 
        if (isAntenna(char)) {
            char: char,
            coords: {
                x: x,
                y: y,
            }
        } else {}
    ) filter (!isEmpty($))
) filter (!isEmpty($)))
fun getAntinodes(frequencies,times=1,acc=[]) = do {
    @Lazy
    var sizeOfFrequencies = sizeOf(frequencies)
    @Lazy
    var numbers = 0 to sizeOfFrequencies-1
    @Lazy
    var newFrequencies = flatten(frequencies map ((frequency, fi) -> 
            flatten((numbers - fi) map ((number) -> 
                (getAntinodesBetween(frequency.coords, frequencies[number].coords, times))
            ))
        ))
    ---
    if ((sizeOfFrequencies >= 2) and !isEmpty(newFrequencies))
        getAntinodes(frequencies,times+1,acc ++ newFrequencies)
    else acc
}
---
antennas groupBy ($.char) 
pluck ((frequencies) -> do {
    frequencies ++ getAntinodes(frequencies)
}) 
then flatten($) distinctBy $ 
then sizeOf($)

🔹 Day 9

  • Challenge: Disk Fragmenter
  • Keywords: reduce, strings, lines
  • Example input:
2333133121414131402

⭐️ Part 1

Script
import divideBy from dw::core::Arrays
var p = (payload splitBy "")
fun repeat(text: String, times: Number): Array =
    if(times <= 0) [] else (1 to times) map text
var files:Array = flatten((p divideBy 2) map ((item, index) -> 
    repeat(index, item[0]) ++ repeat(".", item[1] default 0)
))
var filesClean:Array = files - "."
var thisthing = (files reduce ((item, acc={ r:[], idx:-1 }) -> item match {
    case "." -> {
        r: acc.r + filesClean[acc.idx],
        idx: acc.idx - 1
    }
    else -> {
        r: acc.r + item,
        idx: acc.idx
    }
}))
---
thisthing.r[0 to thisthing.idx] map ($*$$) then sum($)

⭐️⭐️ Part 2 (unsolved)

tbd

🔹 Day 10

  • Challenge: Hoof It
  • Keywords: matrix, navigation, recursive
  • Example input:
89010123
78121874
87430965
96549874
45678903
32019012
01329801
10456732

⭐️ Part 1

Script
var lines = payload splitBy "\n"
fun getChar(x:Number,y:Number):String = if ((x<0) or (y<0)) "" else (lines[x][y] default "")
fun getRoutes(num:Number,numidx:Number,lineidx:Number) = do {
    var nextNum = num+1
    ---
    if (num ~= 9) [{x:numidx,y:lineidx}]
    else 
        (if (getChar(lineidx-1,numidx) ~= nextNum) getRoutes(nextNum,numidx,lineidx-1) else [])
        ++
        (if (getChar(lineidx+1,numidx) ~= nextNum) getRoutes(nextNum,numidx,lineidx+1) else [])
        ++
        (if (getChar(lineidx,numidx-1) ~= nextNum) getRoutes(nextNum,numidx-1,lineidx) else [])
        ++
        (if (getChar(lineidx,numidx+1) ~= nextNum) getRoutes(nextNum,numidx+1,lineidx) else [])
}
---
flatten(lines map ((line, lineidx) -> 
    (line splitBy "") map ((num, numidx) -> 
        num match {
            case "0" -> sizeOf(getRoutes(0,numidx,lineidx) distinctBy $)
            else -> 0
        }
    )
)) then sum($)

⭐️⭐️ Part 2

Script
var lines = payload splitBy "\n"
fun getChar(x:Number,y:Number):String = if ((x<0) or (y<0)) "" else (lines[x][y] default "")
fun getRoutes(num:Number,numidx:Number,lineidx:Number) = do {
    var nextNum = num+1
    ---
    if (num ~= 9) 1
    else 
        (if (getChar(lineidx-1,numidx) ~= nextNum) getRoutes(nextNum,numidx,lineidx-1) else 0)
        +
        (if (getChar(lineidx+1,numidx) ~= nextNum) getRoutes(nextNum,numidx,lineidx+1) else 0)
        +
        (if (getChar(lineidx,numidx-1) ~= nextNum) getRoutes(nextNum,numidx-1,lineidx) else 0)
        +
        (if (getChar(lineidx,numidx+1) ~= nextNum) getRoutes(nextNum,numidx+1,lineidx) else 0)
}
---
flatten(lines map ((line, lineidx) -> 
    (line splitBy "") map ((num, numidx) -> 
        num match {
            case "0" -> getRoutes(0,numidx,lineidx)
            else -> 0
        }
    )
)) then sum($)

🔹 Day 11

Initial arrangement:
125 17

After 1 blink:
253000 1 7

After 2 blinks:
253 0 2024 14168

After 3 blinks:
512072 1 20 24 28676032

After 4 blinks:
512 72 2024 2 0 2 4 2867 6032

After 5 blinks:
1036288 7 2 20 24 4048 1 4048 8096 28 67 60 32

After 6 blinks:
2097446912 14168 4048 2 0 2 4 40 48 2024 40 48 80 96 2 8 6 7 6 0 3 2

⭐️ Part 1

Script
fun removeExtraZeros(num:String):String = num as Number as String
fun blink(arr) = flatten(arr map ((num, numidx) -> 
    num match {
        case "0" -> "1"
        case n if isEven(sizeOf(n)) -> do {
            var i = sizeOf(n)/2
            ---
            [removeExtraZeros(n[0 to i-1]),removeExtraZeros(n[i to -1])]
        }
        else -> ($ * 2024) as String
    }
))
fun blinkTimes(arr,times:Number=1) = times match {
    case 0 -> arr
    else -> blink(arr) blinkTimes times-1
}
---
sizeOf((payload splitBy " ") blinkTimes 25)

⭐️⭐️ Part 2

Script
output application/json
fun removeExtraZeros(num:String):String = num as Number as String
fun blink(obj:Object) = namesOf(obj) reduce ((item, result={}) -> do {
    var itemValue = obj."$item"
    ---
    item match {
        case "0" -> result update {
            case new at ."1"! -> (new default 0) + itemValue
        }
        case n if isEven(sizeOf(n)) -> do {
            var i = sizeOf(n)/2
            var n1 = removeExtraZeros(n[0 to i-1])
            var n2 = removeExtraZeros(n[i to -1])
            var isSame = n1 == n2
            ---
            if (isSame) result update {
                case new at ."$n1"! -> (new default 0) + (itemValue * 2)
            } 
            else result update {
                case new1 at ."$n1"! -> (new1 default 0) + itemValue
                case new2 at ."$n2"! -> (new2 default 0) + itemValue
            }
        }
        else -> result update {
            case new at ."$($ * 2024)"! -> (new default 0) + itemValue
        }
    }
})
fun blinkTimes(obj:Object,times:Number) = times match {
    case 0 -> obj
    else -> blink(obj) blinkTimes times-1
}
fun arrToObj(arr:Array,result={}) = arr match {
    case [head ~ tail] -> tail arrToObj (result update {
        case x at ."$head"! -> (x default 0) + 1
    })
    case [] -> result
}
---
arrToObj(payload splitBy " ") blinkTimes 75
then sum(valuesOf($))

🔹 Day 12

  • Challenge: Garden Groups
  • Keywords: matrix, navigation, recursive, reduce
  • Example input:
RRRRIICCFF
RRRRIICCCF
VVRRRCCFFF
VVRCCCJFFF
VVVVCJJCFE
VVIVCCJJEE
VVIIICJJEE
MIIIIIJJEE
MIIISIJEEE
MMMISSJEEE

⭐️ Part 1

Ran with the full input in the DW CLI online here. Took less than 4 min. Not my best code :')

Script
%dw 2.0
import lines from dw::core::Strings
output application/json
type Coords = {
    x:Number,
    y:Number
}
type Plant = {
    char:String,
    coords:Coords
}
var pLines:Array<String> = lines(payload)
fun getChar(arr:Array<String>,x:Number,y:Number):String = if ((x<0) or (y<0)) "" else (arr[y][x] default "")
fun getPlant(x:Number,y:Number):Plant = {
    char: getChar(pLines,x,y),
    coords: {
        x:x,
        y:y
    }
}
fun getStringCoordsFromPlant(plant:Plant):String = 
    (plant.coords.x) ++ "," ++ (plant.coords.y)
var plants:Array<Plant> = flatten(pLines map ((line, y) -> 
    (line splitBy "") map ((plant, x) -> 
        getPlant(x,y)
    )
))
fun getClosePlantsStrings(plants) = plants reduce ((plant,acc={}) -> do {
    var left = getPlant(plant.coords.x-1, plant.coords.y)
    var right = getPlant(plant.coords.x+1, plant.coords.y)
    var up = getPlant(plant.coords.x, plant.coords.y-1)
    var down = getPlant(plant.coords.x, plant.coords.y+1)
    ---
    acc ++ (getStringCoordsFromPlant(plant)): [
        (getStringCoordsFromPlant(left)) if (left.char == plant.char),
        (getStringCoordsFromPlant(right)) if (right.char == plant.char),
        (getStringCoordsFromPlant(up)) if (up.char == plant.char),
        (getStringCoordsFromPlant(down)) if (down.char == plant.char)
    ] 
})
@TailRec()
fun getAllClose(arr, keys, obj) = do {
    var result = flatten(arr map ((item) -> 
        obj[item] -- keys
    )) distinctBy $
    ---
    if (isEmpty(result)) (keys ++ arr) 
    else getAllClose(
        result,
        (keys ++ arr),
        obj
    )
}
var regionsStringCoords = flatten((plants groupBy ($.char) pluck ((plantsByRegion, tempRegion) -> do {
    var obj = (getClosePlantsStrings(plantsByRegion))
    ---
    (obj pluck ((value, key) -> 
        getAllClose(value,[key as String],obj) orderBy $
    )) distinctBy $
})))
---
regionsStringCoords map ((region) -> do {
    var plants = region map ((str) -> do {
        var strSplit = str splitBy ","
        var plant = getPlant(strSplit[0] as Number, strSplit[1] as Number)
        var left = getPlant(plant.coords.x-1, plant.coords.y).char
        var right = getPlant(plant.coords.x+1, plant.coords.y).char
        var up = getPlant(plant.coords.x, plant.coords.y-1).char
        var down = getPlant(plant.coords.x, plant.coords.y+1).char
        var p = [
            (left) if (left == plant.char),
            (right) if (right == plant.char),
            (up) if (up == plant.char),
            (down) if (down == plant.char)
        ]
        ---
        {
            (plant),
            area: 1,
            perimeter: 4-sizeOf(p)
        }
    })
    ---
    sum(plants.area) * sum(plants.perimeter)
}) 
then sum($)

⭐️⭐️ Part 2

Got some help from reddit and ended up using the DFS algorithm mentioned there. The corner trick was amazing! I'm sure my code can be made way simpler but this was the first code that worked, so I just decided to leave it like that even if it's not the best :) Same as part 1, had to run this code with the full input in the DW CLI online here. Took less than 4 min to run!

Script
%dw 2.0
import lines from dw::core::Strings
output application/json
type Coords = {
    x:Number,
    y:Number
}
type Plant = {
    char:String,
    coords:Coords
}
var pLines:Array<String> = lines(payload)
fun getChar(arr:Array<String>,x:Number,y:Number):String = if ((x<0) or (y<0)) "" else (arr[y][x] default "")
fun getPlant(x:Number,y:Number):Plant = {
    char: getChar(pLines,x,y),
    coords: {
        x:x,
        y:y
    }
}
fun getStringCoordsFromPlant(plant:Plant):String = 
    (plant.coords.x) ++ "," ++ (plant.coords.y)
var plants:Array<Plant> = flatten(pLines map ((line, y) -> 
    (line splitBy "") map ((plant, x) -> 
        getPlant(x,y)
    )
))
fun getClosePlantsStrings(plants) = plants reduce ((plant,acc={}) -> do {
    var left = getPlant(plant.coords.x-1, plant.coords.y)
    var right = getPlant(plant.coords.x+1, plant.coords.y)
    var up = getPlant(plant.coords.x, plant.coords.y-1)
    var down = getPlant(plant.coords.x, plant.coords.y+1)
    ---
    acc ++ (getStringCoordsFromPlant(plant)): [
        (getStringCoordsFromPlant(left)) if (left.char == plant.char),
        (getStringCoordsFromPlant(right)) if (right.char == plant.char),
        (getStringCoordsFromPlant(up)) if (up.char == plant.char),
        (getStringCoordsFromPlant(down)) if (down.char == plant.char)
    ] 
})
@TailRec()
fun getAllClose(arr, keys, obj) = do {
    var result = flatten(arr map ((item) -> 
        obj[item] -- keys
    )) distinctBy $
    ---
    if (isEmpty(result)) (keys ++ arr) 
    else getAllClose(
        result,
        (keys ++ arr),
        obj
    )
}
var regionsStringCoords = flatten((plants groupBy ($.char) pluck ((plantsByRegion, tempRegion) -> do {
    var obj = (getClosePlantsStrings(plantsByRegion))
    ---
    (obj pluck ((value, key) -> 
        getAllClose(value,[key as String],obj) orderBy $
    )) distinctBy $
})))
var corners = [
  [
    "down",
    "right"
  ],
  [
    "down",
    "left"
  ],
  [
    "left",
    "up"
  ],
  [
    "right",
    "up"
  ]
]
fun countCorners(sides:Array<Plant>,char:String) = do {
    var upleft = 0
    var up = 1
    var upright = 2
    var left = 3
    var right = 4
    var downleft = 5
    var down = 6
    var downright = 7
    ---
    (if ( (sides[left].char != char) and (sides[up].char != char) ) 1 else 0)
    + (if ( (sides[right].char != char) and (sides[up].char != char) ) 1 else 0)
    + (if ( (sides[left].char != char) and (sides[down].char != char) ) 1 else 0)
    + (if ( (sides[right].char != char) and (sides[down].char != char) ) 1 else 0)
    + (if ( (sides[left].char == char) and (sides[up].char == char) and (sides[upleft].char != char)) 1 else 0)
    + (if ( (sides[right].char == char) and (sides[up].char == char) and (sides[upright].char != char)) 1 else 0)
    + (if ( (sides[left].char == char) and (sides[down].char == char) and (sides[downleft].char != char)) 1 else 0)
    + (if ( (sides[right].char == char) and (sides[down].char == char) and (sides[downright].char != char)) 1 else 0)
}
---
regionsStringCoords map ((region) -> do {
    var plants = region map ((str) -> do {
        var strSplit = str splitBy ","
        var plant = getPlant(strSplit[0] as Number, strSplit[1] as Number)
        var left = getPlant(plant.coords.x-1, plant.coords.y)
        var right = getPlant(plant.coords.x+1, plant.coords.y)
        var up = getPlant(plant.coords.x, plant.coords.y-1)
        var down = getPlant(plant.coords.x, plant.coords.y+1)
        var upleft = getPlant(plant.coords.x-1, plant.coords.y-1)
        var upright = getPlant(plant.coords.x+1, plant.coords.y-1)
        var downleft = getPlant(plant.coords.x-1, plant.coords.y+1)
        var downright = getPlant(plant.coords.x+1, plant.coords.y+1)
        var s = [
            upleft, //0
            up, //1
            upright, //2
            left, //3
            right, //4
            downleft, //5
            down, //6
            downright //7
        ]
        ---
        {
            area: 1,
            corners: countCorners(s,plant.char)
        }
    })
    ---
    sum(plants.area) * sum(plants.corners)
}) 
then sum($)

🔹 Day 13

Button A: X+94, Y+34
Button B: X+22, Y+67
Prize: X=8400, Y=5400

Button A: X+26, Y+66
Button B: X+67, Y+21
Prize: X=12748, Y=12176

Button A: X+17, Y+86
Button B: X+84, Y+37
Prize: X=7870, Y=6450

Button A: X+69, Y+23
Button B: X+27, Y+71
Prize: X=18641, Y=10279

⭐️ Part 1

To be completely honest, I didn't solve this one myself cause I was trying to make huge Trees and I realized it was impossible. So, I googled and ended up here. Tysm Grant! ✨

Script
output application/json
var machines = payload splitBy "\n\n"
---
machines map ((machine) -> do {
    var split = machine splitBy "\n"
    var prize = {
        x: (split[-1] splitBy " ")[1][2 to -2] as Number,
        y: (split[-1] splitBy " ")[-1][2 to -1] as Number
    }
    var buttonA = {
        x: (split[0] splitBy " ")[-2][2 to -2] as Number,
        y: (split[0] splitBy " ")[-1][2 to -1] as Number
    }
    var buttonB = {
        x: (split[1] splitBy " ")[-2][2 to -2] as Number,
        y: (split[1] splitBy " ")[-1][2 to -1] as Number
    }
    var D = (buttonA.x * buttonB.y) - (buttonA.y * buttonB.x)
    var Dx = (prize.x * buttonB.y) - (prize.y * buttonB.x)
    var Dy = (buttonA.x * prize.y) - (buttonA.y * prize.x)
    var A = Dx / D
    var B = Dy / D
    ---
    (if (isInteger(A)) A * 3 else 0) + (if (isInteger(B)) B else 0)
})
then sum($)

⭐️⭐️ Part 2

Exact same code as part 1, only adding + 10000000000000 to both x and y fields from var prize

Script
output application/json
var machines = payload splitBy "\n\n"
---
machines map ((machine) -> do {
    var split = machine splitBy "\n"
    var prize = {
        x: (split[-1] splitBy " ")[1][2 to -2] as Number + 10000000000000,
        y: (split[-1] splitBy " ")[-1][2 to -1] as Number + 10000000000000
    }
    var buttonA = {
        x: (split[0] splitBy " ")[-2][2 to -2] as Number,
        y: (split[0] splitBy " ")[-1][2 to -1] as Number
    }
    var buttonB = {
        x: (split[1] splitBy " ")[-2][2 to -2] as Number,
        y: (split[1] splitBy " ")[-1][2 to -1] as Number
    }
    var D = (buttonA.x * buttonB.y) - (buttonA.y * buttonB.x)
    var Dx = (prize.x * buttonB.y) - (prize.y * buttonB.x)
    var Dy = (buttonA.x * prize.y) - (buttonA.y * prize.x)
    var A = Dx / D
    var B = Dy / D
    ---
    (if (isInteger(A)) A * 3 else 0) + (if (isInteger(B)) B else 0)
})
then sum($)

🔹 Day 14

  • Challenge: Restroom Redoubt
  • Keywords: math, strings, lines, recursive
  • Example input:
p=0,4 v=3,-3
p=6,3 v=-1,-3
p=10,3 v=-1,2
p=2,0 v=2,-1
p=0,0 v=1,3
p=3,0 v=-2,-2
p=7,6 v=-1,-3
p=3,0 v=-1,-2
p=9,3 v=2,3
p=7,3 v=-1,2
p=2,4 v=2,-3
p=9,5 v=-3,-3

⭐️ Part 1

Script
output application/json
var robots = payload splitBy "\n"
var WIDTH = 101
var HEIGHT = 103
var SECONDS = 100
var widthMiddle = floor(WIDTH/2)
var heightMiddle = floor(HEIGHT/2)
type Coords = {
    x:Number,
    y:Number
}
fun stringToCoord(str:String):Coords = do {
    var split = str splitBy ","
    ---
    {x:split[0] as Number, y:split[1] as Number}
}
fun moveRobot(position:Coords,velocity:Coords):Coords = do {
    var x = position.x + velocity.x
    var y = position.y + velocity.y
    ---
    {
        x: if (x > WIDTH-1) x-WIDTH 
            else if (x < 0) WIDTH+x
            else x,
        y: if (y > HEIGHT-1) y-HEIGHT
            else if (y < 0) HEIGHT+y
            else y
    }
}
@TailRec()
fun moveRobotXTimes(position:Coords,velocity:Coords,times=SECONDS):Coords = do {
    times match {
        case 0 -> position
        else -> moveRobotXTimes(
            moveRobot(position, velocity), velocity, times-1
        )
    }
}
var robotsAfterMoving = robots map ((robot) -> do {
    var split = robot splitBy " "
    var position = stringToCoord(split[0][2 to -1])
    var velocity = stringToCoord(split[-1][2 to -1])
    ---
    moveRobotXTimes(position,velocity)
})
---
sizeOf(robotsAfterMoving filter (($.x < widthMiddle) and ($.y < heightMiddle)))
* sizeOf(robotsAfterMoving filter (($.x > widthMiddle) and ($.y < heightMiddle)))
* sizeOf(robotsAfterMoving filter (($.x < widthMiddle) and ($.y > heightMiddle)))
* sizeOf(robotsAfterMoving filter (($.x > widthMiddle) and ($.y > heightMiddle)))

⭐️⭐️ Part 2

omg this one was so interesting and fun!!! I ran this one in the DW CLI online here - it took 33 minutes to finish!

Script
output application/json
import countBy from dw::core::Arrays
var lines = payload splitBy "\n"
var WIDTH = 101
var HEIGHT = 103
type Coords = {
    x:Number,
    y:Number
}
type Robot = {
    position: Coords,
    velocity: Coords
}
type Direction = "left" | "up" | "down" | "right"
fun stringToCoord(str:String):Coords = do {
    var split = str splitBy ","
    ---
    {x:split[0] as Number, y:split[1] as Number}
}
fun moveRobot(robot:Robot):Coords = do {
    var x = robot.position.x + robot.velocity.x
    var y = robot.position.y + robot.velocity.y
    ---
    {
        x: if (x > WIDTH-1) x-WIDTH 
            else if (x < 0) WIDTH+x
            else x,
        y: if (y > HEIGHT-1) y-HEIGHT
            else if (y < 0) HEIGHT+y
            else y
    }
}
fun getNewCoords(from:Coords, direction:Direction):Coords = direction match {
    case "left" -> {x: from.x-1, y:from.y}
    case "right" -> {x: from.x+1, y:from.y}
    case "up" -> {x: from.x, y: from.y-1}
    case "down" -> {x: from.x, y: from.y+1}
}
fun areMostTouchingOthers(arr):Boolean = do {
    ((arr map ((item) -> 
        (arr contains getNewCoords(item,"left"))
        or (arr contains getNewCoords(item,"right"))
        or (arr contains getNewCoords(item,"up"))
        or (arr contains getNewCoords(item,"down"))
    )) countBy $) >= 350 // 70% of 500
}
var robots:Array<Robot> = lines map ((robot) -> do {
    var split = robot splitBy " "
    var position = stringToCoord(split[0][2 to -1])
    var velocity = stringToCoord(split[-1][2 to -1])
    ---
    {
        position:position,
        velocity:velocity
    }
})
@TailRec()
fun keepMovingRobots(robots,counter=0) = do {
    if (areMostTouchingOthers(robots.position)) counter
    else keepMovingRobots(
        robots map ((robot, index) -> 
            {
                position: moveRobot(robot),
                velocity: robot.velocity
            }
        )
        ,counter+1
    )
}
---
keepMovingRobots(robots)

⭐️⭐️ Part 2 - Spoiler/Second Script

SPOILER!!!

I ended up checking for when at least 70% of the robots were touching each other and that seemed to do the trick :D

Here's the cool pic i got!

tree

You can check the output with the following script. Just change the SECONDS variable.

Second script
output application/json
var robots = payload splitBy "\n"
var WIDTH = 101
var HEIGHT = 103
var SECONDS = 7037
type Coords = {
    x:Number,
    y:Number
}
fun stringToCoord(str:String):Coords = do {
    var split = str splitBy ","
    ---
    {x:split[0] as Number, y:split[1] as Number}
}
fun moveRobot(position:Coords,velocity:Coords):Coords = do {
    var x = position.x + velocity.x
    var y = position.y + velocity.y
    ---
    {
        x: if (x > WIDTH-1) x-WIDTH 
            else if (x < 0) WIDTH+x
            else x,
        y: if (y > HEIGHT-1) y-HEIGHT
            else if (y < 0) HEIGHT+y
            else y
    }
}
@TailRec()
fun moveRobotXTimes(position:Coords,velocity:Coords,times=SECONDS):Coords = do {
    times match {
        case 0 -> position
        else -> moveRobotXTimes(
            moveRobot(position, velocity), velocity, times-1
        )
    }
}
var robotsAfterMoving = robots map ((robot) -> do {
    var split = robot splitBy " "
    var position = stringToCoord(split[0][2 to -1])
    var velocity = stringToCoord(split[-1][2 to -1])
    ---
    moveRobotXTimes(position,velocity)
})
var obj = robotsAfterMoving groupBy ($.x ++ "," ++ $.y)
---
(0 to HEIGHT-1) map ((y) ->
    ((0 to WIDTH-1) map ((x) ->
        if (!isEmpty(obj[x ++ "," ++ y])) "X" else "."
    )) joinBy ""
)

🔹 Day 15

  • Challenge: Warehouse Woes
  • Keywords: strings, matrix, two inputs, navigation, recursive
  • Example input:
########
#..O.O.#
##@.O..#
#...O..#
#.#.O..#
#...O..#
#......#
########

<^^>>>vv<v>>v<<

⭐️ Part 1

Script
import mapString from dw::core::Strings
output application/json
type Coords = {x:Number,y:Number}
var lines = payload splitBy "\n\n"
var initialMap = do {
    var thismap = lines[0] splitBy "\n"
    ---
    {
        map: thismap,
        robot: (flatten(thismap map ((line, y) -> 
            (line splitBy "") map ((char, x) -> 
                char match {
                    case "@" -> {x:x,y:y}
                    else -> null
                }
            )
        )) filter (!isEmpty($)))[0] as Coords
    }
}
var movements = lines[1] replace "\n" with "" splitBy ""
fun getChar(arr:Array<String>,x:Number,y:Number):String = if ((x<0) or (y<0)) "" else (arr[y][x] default "")
@TailRec()
fun moveBoxes(thisMap, boxes:Array<Coords>, direction:String) = direction match {
    case "<" -> getChar(thisMap.map, boxes[-1].x-1, boxes[-1].y) match {
        case "#" -> thisMap
        case "O" -> moveBoxes(thisMap, boxes + {x:boxes[-1].x-1, y:boxes[-1].y}, direction)
        case "." -> thisMap update {
            case .robot.x -> boxes[0].x
            case .map[thisMap.robot.y] -> $ mapString ((character, index) -> 
                index match {
                    case x if (thisMap.robot.x == x) -> "."
                    case x if (boxes[0].x == x) -> "@"
                    case x if (boxes[-1].x-1 == x) -> "O"
                    else -> character
                }
            )
        }
    }
    case ">" -> getChar(thisMap.map, boxes[-1].x+1, boxes[-1].y) match {
        case "#" -> thisMap
        case "O" -> moveBoxes(thisMap, boxes + {x:boxes[-1].x+1, y:boxes[-1].y}, direction)
        case "." -> thisMap update {
            case .robot.x -> boxes[0].x
            case .map[thisMap.robot.y] -> $ mapString ((character, index) -> 
                index match {
                    case x if (thisMap.robot.x == x) -> "."
                    case x if (boxes[0].x == x) -> "@"
                    case x if (boxes[-1].x+1 == x) -> "O"
                    else -> character
                }
            )
        }
    }
    case "^" -> getChar(thisMap.map, boxes[-1].x, boxes[-1].y-1) match {
        case "#" -> thisMap
        case "O" -> moveBoxes(thisMap, boxes + {x:boxes[-1].x, y:boxes[-1].y-1}, direction)
        case "." -> thisMap update {
            case .robot.y -> boxes[0].y
            case .map[thisMap.robot.y] -> $ replace "@" with "."
            case .map[boxes[0].y] -> $[0 to boxes[0].x-1] ++ "@" ++ $[boxes[0].x+1 to -1]
            case .map[boxes[-1].y-1] -> $[0 to boxes[-1].x-1] ++ "O" ++ $[boxes[-1].x+1 to -1]
        }
    }
    case "v" -> getChar(thisMap.map, boxes[-1].x, boxes[-1].y+1) match {
        case "#" -> thisMap
        case "O" -> moveBoxes(thisMap, boxes + {x:boxes[-1].x, y:boxes[-1].y+1}, direction)
        case "." -> thisMap update {
            case .robot.y -> boxes[0].y
            case .map[thisMap.robot.y] -> $ replace "@" with "."
            case .map[boxes[0].y] -> $[0 to boxes[0].x-1] ++ "@" ++ $[boxes[0].x+1 to -1]
            case .map[boxes[-1].y+1] -> $[0 to boxes[-1].x-1] ++ "O" ++ $[boxes[-1].x+1 to -1]
        }
    }
}
fun moveRobot(thisMap, moveTo:String) = moveTo match {
    case "<" -> getChar(thisMap.map, thisMap.robot.x-1, thisMap.robot.y) match {
        case "#" -> thisMap
        case "O" -> moveBoxes(thisMap, [{x:thisMap.robot.x-1, y:thisMap.robot.y}], moveTo) 
        case "." -> thisMap update {
            case .robot.x -> $-1
            case .map[thisMap.robot.y] -> $ mapString ((character, index) -> 
                index match {
                    case x if (thisMap.robot.x == x) -> "."
                    case x if (thisMap.robot.x-1 == x) -> "@"
                    else -> character
                }
            )
        }
    }
    case ">" -> getChar(thisMap.map, thisMap.robot.x+1, thisMap.robot.y) match {
        case "#" -> thisMap
        case "O" -> moveBoxes(thisMap, [{x:thisMap.robot.x+1, y:thisMap.robot.y}], moveTo) 
        case "." -> thisMap update {
            case .robot.x -> $+1
            case .map[thisMap.robot.y] -> $ mapString ((character, index) -> 
                index match {
                    case x if (thisMap.robot.x == x) -> "."
                    case x if (thisMap.robot.x+1 == x) -> "@"
                    else -> character
                }
            )
        }
    }
    case "^" -> getChar(thisMap.map, thisMap.robot.x, thisMap.robot.y-1) match {
        case "#" -> thisMap
        case "O" -> moveBoxes(thisMap, [{x:thisMap.robot.x, y:thisMap.robot.y-1}], moveTo) 
        case "." -> thisMap update {
            case .robot.y -> $-1
            case .map[thisMap.robot.y] -> $ replace "@" with "."
            case .map[thisMap.robot.y-1] -> $[0 to thisMap.robot.x-1] ++ "@" ++ $[thisMap.robot.x+1 to -1]
        }
    }
    case "v" -> getChar(thisMap.map, thisMap.robot.x, thisMap.robot.y+1) match {
        case "#" -> thisMap
        case "O" -> moveBoxes(thisMap, [{x:thisMap.robot.x, y:thisMap.robot.y+1}], moveTo) 
        case "." -> thisMap update {
            case .robot.y -> $+1
            case .map[thisMap.robot.y] -> $ replace "@" with "."
            case .map[thisMap.robot.y+1] -> $[0 to thisMap.robot.x-1] ++ "@" ++ $[thisMap.robot.x+1 to -1]
        }
    }
}
@TailRec()
fun keepMoving(movementsList:Array<String>, thisMap) = movementsList match {
    case [headMovement ~ tailMovements] -> keepMoving(
        tailMovements,
        thisMap moveRobot headMovement
    )
    case [] -> thisMap
}
---
keepMoving(movements,initialMap).map map ((line, y) -> 
    sum((line splitBy "") map ((char, x) -> 
        if (char == "O") 100 * y + x
        else 0
    ))
) then sum($)

Part 2 (unsolved)

tbd

🔹 Day 19

  • Challenge: Linen Layout
  • Keywords: strings, lines, two inputs, rules, recursive
  • Example input:
r, wr, b, g, bwu, rb, gb, br

brwrr
bggr
gbbr
rrbgbr
ubwu
bwurrg
brgr
bbrgwb

⭐️ Part 1

Script
import countBy from dw::core::Arrays
import lines, substringAfter from dw::core::Strings
output application/json
var split = payload splitBy "\n\n"
var patternsList = split[0] splitBy ", "
fun checkDesign(initialDesign:String, currentDesign:String, acc="") = do {
    var filtered = patternsList filter (currentDesign startsWith $)
    ---
    if (isEmpty(currentDesign))
        initialDesign == acc
    else if (isEmpty(filtered)) false
    else filtered 
    reduce ((pattern, matches=false) -> 
        if (matches) true
        else checkDesign(
            initialDesign,
            currentDesign substringAfter pattern,
            acc ++ pattern
        ) 
    )
}
---
(lines(split[1]) map ((design) -> 
    checkDesign(design,design)
)) countBy $

⭐️⭐️ Part 2 (unsolved)

tbd

🔹 Day 23

  • Challenge: LAN Party
  • Keywords: lines, comparisons/matching
  • Example input:
kh-tc
qp-kh
de-cg
ka-co
yn-aq
qp-ub
cg-tb
vc-aq
tb-ka
wh-tc
yn-cg
kh-ub
ta-co
de-co
tc-td
tb-wq
wh-td
ta-ka
td-qp
aq-cg
wq-ub
ub-vc
de-ta
wq-aq
wq-vc
wh-yn
ka-de
kh-ta
co-tc
wh-qp
tb-vc
td-yn

⭐️ Part 1

Script
import lines from dw::core::Strings
output application/json
var connections = lines(payload) map ($ splitBy "-") reduce ((item, a={}) -> 
    a update {
        case x at ."$(item[0])"! -> (a[item[0]] default []) + item[1]
        case y at ."$(item[1])"! -> (a[item[1]] default []) + item[0]
    }
)
var matches = flatten(namesOf(connections) map ((computer1) -> 
    flatten(connections[computer1] map ((computer2) -> do {
        var threeMatchesOne = (connections[computer2] filter ((computer3) -> connections[computer3] contains computer1))
        ---
        if (!isEmpty(threeMatchesOne)) 
            threeMatchesOne filter ((computer3) -> (computer1 startsWith "t") or (computer2 startsWith "t") or (computer3 startsWith "t"))
            map ((computer3) ->
                [computer1, computer2, computer3] orderBy $
            )
        else []
    })) 
)) distinctBy $
---
sizeOf(matches)

⭐️⭐️ Part 2

Script
import lines from dw::core::Strings
output application/json
var connections = lines(payload) map ($ splitBy "-") reduce ((item, a={}) -> 
    a update {
        case x at ."$(item[0])"! -> (a[item[0]] default []) + item[1]
        case y at ."$(item[1])"! -> (a[item[1]] default []) + item[0]
    }
)
var list = namesOf(connections) map ((computer1) -> do {
    var cc1 = connections[computer1]
    var list = (cc1 + computer1) orderBy $
    var strings = (cc1 map ((computer2) -> do {
        var tocompare = (connections[computer2] + computer2) orderBy $
        ---
        (tocompare filter (list contains $)) joinBy ","
    })) orderBy $
    ---
    ((strings orderBy $) groupBy $) filterObject (sizeOf($) >= 2)
    mapObject ((value, key, index) -> {
        size: sizeOf(value),
        str: key
    })
})
---
((list filter (!isEmpty($))) orderBy -($.size))[0].str

🔹 Day 24

  • Challenge: Crossed Wires
  • Keywords: strings, lines, two inputs, rules, recursive, comparisons/matching
  • Example input:
x00: 1
x01: 0
x02: 1
x03: 1
x04: 0
y00: 1
y01: 1
y02: 1
y03: 1
y04: 1

ntg XOR fgs -> mjb
y02 OR x01 -> tnw
kwq OR kpj -> z05
x00 OR x03 -> fst
tgd XOR rvg -> z01
vdt OR tnw -> bfw
bfw AND frj -> z10
ffh OR nrd -> bqk
y00 AND y03 -> djm
y03 OR y00 -> psh
bqk OR frj -> z08
tnw OR fst -> frj
gnj AND tgd -> z11
bfw XOR mjb -> z00
x03 OR x00 -> vdt
gnj AND wpb -> z02
x04 AND y00 -> kjc
djm OR pbm -> qhw
nrd AND vdt -> hwm
kjc AND fst -> rvg
y04 OR y02 -> fgs
y01 AND x02 -> pbm
ntg OR kjc -> kwq
psh XOR fgs -> tgd
qhw XOR tgd -> z09
pbm OR djm -> kpj
x03 XOR y03 -> ffh
x00 XOR y04 -> ntg
bfw OR bqk -> z06
nrd XOR fgs -> wpb
frj XOR qhw -> z04
bqk OR frj -> z07
y03 OR x01 -> nrd
hwm AND bqk -> z03
tgd XOR rvg -> z12
tnw OR pbm -> gnj

⭐️ Part 1

Script
import fromBinary from dw::core::Numbers
import lines from dw::core::Strings
output application/json
var splitPayload = payload splitBy "\n\n"
var wires:Object = (lines(splitPayload[0]) map ($ splitBy ": ")) reduce ((item, a={}) -> 
    a ++ {
        (item[0]): item[1] ~= 1
    }
)
fun getWiresObject(gates:Array<String>, wiresRec) = {
    (gates map ((gate) -> do {
        @Lazy
        var split = gate splitBy " "
        @Lazy
        var wire1 = split[0]
        @Lazy
        var wire2 = split[2]
        @Lazy
        var wire3 = split[-1]
        ---
        if (!isEmpty(wiresRec[wire1]) and !isEmpty(wiresRec[wire2])) {
            (wire3): split[1] match {
                case "AND" -> wiresRec[wire1] and wiresRec[wire2]
                case "OR" -> wiresRec[wire1] or wiresRec[wire2]
                case "XOR" -> wiresRec[wire1] != wiresRec[wire2]
            }
        }
        else {
            keepTrying: gate
        }
    }))
}
fun getWiresTailRec(gates:Array<String>, wiresRec=wires) = do {
    var result = getWiresObject(gates, wiresRec)
    var newGates = result.*keepTrying
    var newWires = wiresRec ++ result
    ---
    if (isEmpty(newGates)) newWires 
    else getWiresTailRec(newGates, newWires - "keepTrying")
}
---
getWiresTailRec(lines(splitPayload[1])) 
filterObject ($$ startsWith "z")
orderBy $$
mapObject (($$): if ($) 1 else 0)
then fromBinary(valuesOf($)[-1 to 0] joinBy "")

⭐️⭐️ Part 2 (unsolved)

tbd

🔹 Day 25

  • Challenge: Code Chronicle
  • Keywords: matrix, two inputs, comparisons/matching
  • Example input:
#####
.####
.####
.####
.#.#.
.#...
.....

#####
##.##
.#.##
...##
...#.
...#.
.....

.....
#....
#....
#...#
#.#.#
#.###
#####

.....
.....
#.#..
###..
###.#
###.#
#####

.....
.....
.....
#....
#.#..
#.#.#
#####

⭐️ Part 1

Script
import every, countBy from dw::core::Arrays
output application/json
fun getMap(arr) = arr map ((item) -> do {
    var lines = (item splitBy "\n")[1 to -2]
    ---
    (0 to sizeOf(lines)-1) map (
        sum(lines map ((line) -> 
            if (line[$] == "#") 1 else 0
        ))
    )
})
var arr = (payload splitBy "\n\n")
var locks = getMap(arr filter ($ startsWith "#####"))
var keys = getMap(arr filter ($ startsWith "....."))
---
sum(locks map ((lock, locki) -> 
    (keys map ((key, keyi) -> 
        (key map ((keypin, keypini) -> 
            5-keypin >= lock[keypini]
        )) every $
    )) countBy $
))

⭐️⭐️ Part 2

Need to finish the rest of the challenges to be unlocked x-x