## DEV Community is a community of 848,701 amazing developers

We're a place where coders share, stay up-to-date and grow their careers. # Advent of code - Day 24

Are you participating in the Advent of code this year?

If you don't know what the advent of code is, it's a website where you'll find a daily challenge (every day it gets harder). It's a really fun event, you should participate!

I try to solve the exercises using either JavaScript or TypeScript and will share my solutions daily (with one day delay so no one can cheat!). I only share the solution for the second part.

Another game of life, but with hexagons this time! The trick here was to make sure you only process the black tiles and their adjacent tiles. Just drop all white tiles, they are useless! Once I figured that out, performance dropped to a ok level (this code runs in about 10 seconds).

Here is my solution for day #24:

``````interface Position {
e: number
se: number
sw: number
w: number
nw: number
ne: number
}

export function extract(str: string): (keyof Position)[] {
if (str.length === 0) return []
if (['e', 'w'].includes(str)) return [str as keyof Position, ...extract(str.slice(1))]
return [str.slice(0, 2) as keyof Position, ...extract(str.slice(2))]
}

function count(position: (keyof Position)[]): Position {
return position.reduce(
(acc, value) => {
acc[value] += 1
return acc
},
{
e: 0,
se: 0,
sw: 0,
w: 0,
nw: 0,
ne: 0,
},
)
}

interface Tile {
position: Position
state: State
}

enum State {
Black,
White,
}

const opposition: Record<keyof Position, keyof Position> = {
e: 'w',
w: 'e',
nw: 'se',
se: 'nw',
sw: 'ne',
ne: 'sw',
}

const complementaries: Record<keyof Position, (keyof Position)[]> = {
e: ['se', 'ne'],
w: ['sw', 'nw'],

se: ['sw', 'e'],
sw: ['se', 'w'],
nw: ['ne', 'w'],
ne: ['nw', 'e'],
}

function rationalize(position: Position): Position {
for (let key of (Object.keys(opposition) as unknown) as (keyof Position)[]) {
if (position[key] < 0) {
return rationalize({
...position,
[key]: 0,
[opposition[key]]: position[opposition[key]] - position[key],
})
}
if (position[key] > 0 && position[opposition[key]] > 0) {
return rationalize({
...position,
[key]: position[key] - 1,
[opposition[key]]: position[opposition[key]] - 1,
})
}
}
for (let key of (Object.keys(complementaries) as unknown) as (keyof Position)[]) {
if (complementaries[key].every((comp) => position[comp] > 0)) {
return rationalize({
...position,
[complementaries[key]]: position[complementaries[key]] - 1,
[complementaries[key]]: position[complementaries[key]] - 1,
[key]: position[key] + 1,
})
}
}
return position
}

function print(position: Position): string {
return `\${position.e},\${position.se},\${position.sw},\${position.w},\${position.nw},\${position.ne}`
}

export function moveTo(newCenter: Position, tile: Position): Position {
return rationalize(
((Object.keys(tile) as unknown) as (keyof Position)[]).reduce(
(acc: Position, key) => {
acc[key] = tile[key] - newCenter[key]
return acc
},
{
e: 0,
se: 0,
sw: 0,
w: 0,
nw: 0,
ne: 0,
},
),
)
}

interface PotentialTile {
position: Position
}

const keys = (Object.keys(newPosition) as unknown) as (keyof Position)[]
return keys.filter((key) => newPosition[key] === 1).length === 1 && keys.every((key) => newPosition[key] <= 1)
}

export function findAdjacent(tile: Tile): Position[] {
return ((Object.keys(tile.position) as unknown) as (keyof Position)[]).map((key) => {
return {
...tile.position,
[key]: tile.position[key] + 1,
}
})
}

function runTurn(allTiles: Tile[]) {
const potentialNewTiles: Record<string, PotentialTile> = {}
const processed = new Set()

const indexedTiles = allTiles.reduce((acc: Record<string, Tile>, v) => {
acc[print(v.position)] = v
return acc
}, {})

const existingTiles = allTiles
.map((tile) => {

const printedPosition = print(actualPosition)
if (processed.has(printedPosition)) return
potentialNewTiles[printedPosition] = potentialNewTiles[printedPosition] || {
position: actualPosition,
}
})

.map((position) => indexedTiles[print(rationalize(position))])
.filter(Boolean)

return {
...tile,
state: numberOfBlackAdjacents === 1 || numberOfBlackAdjacents === 2 ? State.Black : State.White,
}
})
.filter((tile) => tile.state === State.Black)

const newTiles = Object.keys(potentialNewTiles)
.filter((key) => !processed.has(key))
.map((key) => {
return {
position: potentialNewTiles[key].position,
state: State.Black,
}
})

return [...existingTiles, ...newTiles]
}

const positions = input
.split('\n')
.map(extract)
.map(count)
.map(rationalize)
.reduce((acc: Record<string, Tile>, value) => {
acc[print(value)] = acc[print(value)] || { position: value, state: State.White }
acc[print(value)].state = acc[print(value)].state === State.Black ? State.White : State.Black
return acc
}, {})

const tiles = Object.keys(positions)
.map((key) => positions[key])
.filter((tile) => tile.state === State.Black)
let currentTiles = tiles

for (let i = 0; i < 101; i++) {
console.log(`Turn: \${i}: \${currentTiles.filter((t) => t.state === State.Black).length}`)
currentTiles = runTurn(currentTiles)
}

``````