https://github.com/argeento/advent-of-code-2023
My solutions to AoC 2023 in Civet
https://github.com/argeento/advent-of-code-2023
advent-of-code advent-of-code-2023 civet
Last synced: 8 months ago
JSON representation
My solutions to AoC 2023 in Civet
- Host: GitHub
- URL: https://github.com/argeento/advent-of-code-2023
- Owner: Argeento
- Created: 2023-11-28T14:33:58.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2023-12-15T06:08:23.000Z (almost 2 years ago)
- Last Synced: 2025-02-12T07:26:38.718Z (9 months ago)
- Topics: advent-of-code, advent-of-code-2023, civet
- Homepage:
- Size: 88.9 KB
- Stars: 2
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
Lang: [Civet](https://civet.dev)
# Advent of Code 2023
Something is wrong with global snow production, and you've been selected to take a look.
The Elves have even given you a map; on it, they've used stars to mark the top fifty
locations that are likely to be having problems.
## Day 15: Lens Library ⭐⭐
```ts
{ log, getInput, sum, toNumber, entries, values } from ../utils.civet
codes := getInput import.meta.url |> .trim().split(',')
function calcHash(code: string)
[...code].reduce (nr, c) => (nr + c.charCodeAt 0) * 17 % 256, 0
log 'Part 1', sum codes.map calcHash
boxes := {}
for code of codes
label := code.replace /[^a-z]/g, ''
hash := calcHash label
(boxes[hash] ?= [])[label] = toNumber code
delete boxes[hash][label] if code.includes('-')
focusingPower .= 0
for [hash, lenses] of entries boxes
for focal, i of values lenses
focusingPower += (+hash + 1) * (i + 1) * focal
log 'Part 2', focusingPower
```
## Day 14: Parabolic Reflector Dish ⭐⭐
```ts
{ log, getLines, sum, cloneDeep, zip } from ../utils.civet
stones .= getLines import.meta.url |> .map .split ''
function step(stones: string[][])
return .= 0
for y of [0...stones.length]
for x of [0...stones.0.length]
if stones[y][x] is 'O' and stones[y - 1]?[x] is '.'
stones[y][x] = '.'
stones[y - 1][x] = 'O'
return++
function move(stones: string[][])
while step stones;
stones
function calcWeight(stones: string[][])
sum for line, y of stones
line.filter(& is 'O').length * (stones.length - y)
log 'Part 1', calcWeight move cloneDeep stones
function cycle()
for [0...4]
stones = zip(...move stones).map .reverse()
mem := {}
i .= 0
offset .= 0
loop
memKey := JSON.stringify stones
if mem[memKey]
offset = mem[memKey]
break
mem[memKey] = i++
cycle()
for [0...(1e9 - offset) % (i - offset)]
cycle()
log 'Part 2', calcWeight stones
```
## Day 13: Point of Incidence ⭐⭐
```ts
{ log, getInput, sum, zip } from ../utils.civet
patterns := getInput import.meta.url
.split('\n\n').map &.split('\n')
function diffs(str1: string, str2: string)
sum for c, i of str1
c is not str2[i]
function rotate(pattern: string[])
zip(...pattern.map &.split('')).flatMap &.join('')
function searchMirror(pattern: string[], possibleErrors: number)
for y of [0...pattern.length - 1]
errors .= 0
for i .= 0; y - i >= 0 and y + i + 1 < pattern.length; i++
errors += diffs pattern[y - i], pattern[y + i + 1]
return y + 1 if errors is possibleErrors
0
function getNote(pattern: string[], possibleErrors: number)
100 * searchMirror(pattern, possibleErrors) +
searchMirror(rotate(pattern), possibleErrors)
log 'Part 1', sum patterns.map (p) => getNote p, 0
log 'Part 2', sum patterns.map (p) => getNote p, 1
```
## Day 12: Hot Springs ⭐⭐
```ts
{ log, getLines, toNumbers, sum } from ../utils.civet
lines := getLines(import.meta.url).map &.split ' '
mem := {}
function combinations(springs: string, groups: number[], counter = 0): number
memKey := springs + groups
return mem[memKey] if mem[memKey]
return '#' is in springs ? 0 : 1 unless groups.length
[nr, ...rest] := groups
for i .= 0; i <= springs.length - rest.length - sum(rest) - nr; i++
break if '#' is in springs[0...i]
if '.' is not in springs[i...i + nr] and springs[i + nr] is not "#"
counter += combinations springs[i + nr + 1..], rest
mem[memKey] = counter
log 'Part 1', sum for [springs, groups] of lines
combinations springs, toNumbers groups
log 'Part 2', sum for [springs, groups] of lines
combinations
new Array(5).fill(springs).join('?'),
new Array(5).fill(toNumbers groups).flatMap (&)
```
## Day 11: Cosmic Expansion ⭐⭐
```ts
{ log, getLines, sum } from ../utils.civet
lines .= getLines import.meta.url
expandingRows := []
for line, y of lines
expandingRows.push y unless '#' is in line
expandingCols := []
for x of [0...lines.0.length]
expandingCols.push x if lines.every &[x] is '.'
galaxies := []
for y of [0...lines.length]
for x of [0...lines.0.length]
galaxies.push [x, y] if lines[y][x] is '#'
function getDistance([[x1, y1], [x2, y2]])
Math.abs(x1 - x2) + Math.abs(y1 - y2)
function getPairs(galaxies: number[][])
for i of [0...galaxies.length]
for j of [i + 1...galaxies.length]
[galaxies[i], galaxies[j]]
function expand(galaxies: number[][], multiplayer: number)
for [x, y] of galaxies
r := expandingRows.filter(& < y).length
c := expandingCols.filter(& < x).length
[x + c * (multiplayer - 1), y + r * (multiplayer - 1)]
function sumDistances(galaxies: number[][], expandMultiplier: number)
galaxies = expand galaxies, expandMultiplier
sum getPairs(galaxies).flatMap (&).map getDistance
log 'Part 1', sumDistances galaxies, 2
log 'Part 2', sumDistances galaxies, 1e6
```
## Day 10: Pipe Maze ⭐⭐
```ts
pointInPolygon from 'point-in-polygon'
{ log, getLines } from ../utils.civet
lines := getLines import.meta.url
startY := lines.findIndex &.includes 'S'
startX := lines[startY].indexOf 'S'
last .= [startX, startY]
current .= [startX, startY + 1]
polygon := [current]
while next := move current, last
last = current
polygon.push current = next
function move([x, y]: number[], [prevX, prevY]: number[])
disabledDir .= switch prevX - x
> 0 then 'E'
< 0 then 'W'
else prevY - y < 0 ? 'N' : 'S'
switch lines[y][x] + disabledDir
'-E' [x - 1, y]
'-W' [x + 1, y]
'|N' [x, y + 1]
'|S' [x, y - 1]
'7W' [x, y + 1]
'7S' [x - 1, y]
'LN' [x + 1, y]
'LE' [x, y - 1]
'JW' [x, y - 1]
'JN' [x - 1, y]
'FS' [x + 1, y]
'FE' [x, y + 1]
log 'Part 1', polygon.length / 2
area .= 0
for y of [0...lines.length]
for x of [0...lines.length]
unless polygon.some [px, py] => px is x and py is y
area++ if pointInPolygon [x, y], polygon
log 'Part 2', area
```
## Day 9: Mirage Maintenance ⭐⭐
```ts
{ log, getLines, toNumbers, sum } from ../utils.civet
lines := getLines(import.meta.url).map toNumbers
function getSequence(arr: number[])
for i of [1...arr.length]
arr[i] - arr[i - 1]
function predict(arr: number[])
arrs := [arr]
while sum arrs.-1
arrs.push getSequence arrs.-1
sum arrs.map .-1
log 'Part 1', sum lines.map predict
log 'Part 2', sum lines.map(.reverse()).map predict
```
## Day 8: Haunted Wasteland ⭐⭐
```ts
{ log, getInput, getLcm, keys } from ../utils.civet
input := getInput import.meta.url |> .split '\n\n'
insNr .= 0
getIns := => input.0[insNr++ % input.0.length] is 'L' ? 0 : 1
nodes := {}
for node of input.1.split('\n').map .match /\w+/g
nodes[node.0] = node[1..]
function movesNr(startNode: string, endNodes: string[])
return .= 0
name .= startNode
node .= nodes[startNode]
until name is in endNodes
return++
name = node[getIns()]
node = nodes[name]
log 'Part 1', movesNr 'AAA', ['ZZZ']
startNodes := keys(nodes).filter .endsWith 'A'
endNodes := keys(nodes).filter .endsWith 'Z'
log 'Part 2', getLcm startNodes.map (start) => movesNr start, endNodes
```
## Day 7: Camel Cards ⭐⭐
```ts
{ log, getLines, int, sum, desc } from ../utils.civet
type Hand
cards: string
bid: number
type: number
lines := getLines import.meta.url
log 'Part 1', sum getWins(lines, false)
log 'Part 2', sum getWins(lines, true)
function getWins(lines: string[], joker: boolean)
lines
.map (line) => parseHand(line, joker)
.sort compareHands
.map (hand, i) => hand.bid * (i + 1)
function parseHand(line: string, joker: boolean): Hand
[cards, bid] .= line.split ' '
cards: fixCardsStrength cards, joker
bid: int bid
type: getType cards, joker
function getType(cards: string, joker: boolean)
counter := count cards.replaceAll joker ? 'J' : '', ''
if joker then (counter.0 ?= 0) += cards.match(/J/g)?.length ?? 0
switch counter
[5] 6
[4, 1] 5
[3, 2] 4
[3, 1, 1] 3
[2, 2, 1] 2
[2, 1, 1, 1] 1
[...] 0
function count(cards: string)
counter: Record := {}
for card of cards.split('')
(counter[card] ?= 0)++
Object.values(counter).sort desc
function compareHands(a: Hand, b: Hand)
a.type is b.type
? a.cards > b.cards ? 1 : -1
: a.type - b.type
function fixCardsStrength(cards: string, joker: boolean)
cards
.replaceAll 'A', 'E'
.replaceAll 'K', 'D'
.replaceAll 'Q', 'C'
.replaceAll 'J', joker ? '1' : 'B'
.replaceAll 'T', 'A'
```
## Day 6: Wait For It ⭐⭐
```ts
{ log, getLines, toNumbers, toNumber, multiply } from ../utils.civet
lines := getLines import.meta.url
function timesWins(time: number, record: number)
return .= 0
for t of [1...time]
return++ if time - t > record / t
log 'Part 1', multiply for i of [0...4]
timesWins
toNumbers(lines.0)[i],
toNumbers(lines.1)[i]
log 'Part 2', timesWins
toNumber lines.0.replaceAll ' ', ''
toNumber lines.1.replaceAll ' ', ''
```
## Day 5: If You Give A Seed A Fertilizer ⭐⭐
```ts
{ log, getInput, toNumbers, inRange, chunk, min } from ../utils.civet
input := getInput(import.meta.url).split '\n\n'
seeds := toNumbers input.0
mappings := input[1..].map &.split('\n')[1..].map toNumbers
function translate(nr: number, map: number[][])
range := map.find (map) => inRange map.1, nr, map.1 + map.2
range ? nr + range.0 - range.1 : nr
function getMin(seeds: number[])
min .= Infinity
for let seed of seeds
for map of mappings
seed = translate seed, map
min = seed if seed < min
min
log 'Part 1', getMin seeds
log 'Part 2', min chunk(seeds, 2).map [start, length] =>
getMin [start...start + length]
// omptimzed part 2 -> src/05/index2.civet
```
## Day 4: Scratchcards ⭐⭐
```ts
{ log, getLines, sum, toNumbers, values } from ../utils.civet
lines := getLines import.meta.url
function wins (line: string)
[wins, my] := line.split(':').1.split('|').map toNumbers
my.filter(& is in wins).length
log 'Part 1', sum for line of lines
wins line |> (n) => n ? 1 << n - 1 : 0
cards := {}
for i in lines
cards[i] = 1
for line, i of lines
for j .= i + 1; j <= i + wins line; j++
cards[j] += cards[i]
log 'Part 2', sum values cards
```
## Day 3: Gear Ratios ⭐⭐
```ts
{ log, getLines, sum, flatten, values } from ../utils.civet
lines := getLines import.meta.url
parts: Record := {}
for line, y of lines
for m of line.matchAll /\d+/g
for y of [y - 1..y + 1]
for x of [m.index - 1..m.index + m.0.length]
unless /[0-9.]/.test lines[y]?.[x]
(parts.`${x},${y}` ?= []).push +m.0
log 'Part 1', sum flatten values parts
log 'Part 2', sum values(parts).map (x) => x.0 * x.1 ?= 0
```
## Day 2: Cube Conundrum ⭐⭐
```ts
{ log, getLines, max, sum, int, keys, multiply } from ../utils.civet
lines := getLines import.meta.url
games := lines.map (line) => Array.from line.match /\d+ ./g
limits := r:12, g:13, b:14
log 'Part 1', sum for game, id of games
if game.every (draw) => int(draw) <= limits[draw.-1]
id + 1
log 'Part 2', sum games.map (game) =>
multiply keys(limits).map (color) =>
game.filter(.includes color).map(int) |> max
```
## Day 1: Trebuchet?! ⭐⭐
```ts
{ getLines, log, sum, int } from ../utils.civet
lines := getLines import.meta.url
function parseValue(line: string)
nr := line.replace /[a-z]/g, ''
int nr.0 + nr.-1
function convertWords(line: string)
line
.replaceAll 'one', 'o1e'
.replaceAll 'two', 't2o'
.replaceAll 'three', 't3e'
.replaceAll 'four', 'f4r'
.replaceAll 'five', 'f5e'
.replaceAll 'six', 's6x'
.replaceAll 'seven', 's7n'
.replaceAll 'eight', 'e8t'
.replaceAll 'nine', 'n9e'
.replaceAll 'zero', 'z0o'
log 'Part 1', sum lines.map(parseValue)
log 'Part 2', sum lines.map(convertWords).map(parseValue)
```