Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions 2025/01/kylepritchard.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
module main

import os
import strconv

fn main() {
codes := os.read_file('rotations.input') or { panic('Failed to read file') }

mut start := 50
mut count := 0
mut count2 := 0

for line in codes.split_into_lines() {
if line.len == 0 {
continue
}

if line[0] == `L` {
move_str := line[1..].trim_space()
mut move := strconv.atoi(move_str) or { 0 }

for move > 0 {
start--
if start == 0 {
count2++
}
if start == -1 {
start = 99
}
move--
}

if start == 0 {
count++
}
} else {
move_str := line[1..].trim_space()
mut move := strconv.atoi(move_str) or { 0 }

for move > 0 {
start++
if start == 100 {
start = 0
}
if start == 0 {
count2++
}
move--
}

if start == 0 {
count++
}
}
}

println('Part 1: ${count}')
println('Part 2: ${count2}')
}
85 changes: 85 additions & 0 deletions 2025/02/kylepritchard.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
module main

import os
import strconv

fn has_exact_two_halves(s string) bool {
if s.len % 2 != 0 {
return false
}
half := s.len / 2
return s[0..half] == s[half..]
}

fn has_repeating_pattern(s string) bool {
for pattern_len in 1 .. s.len / 2 + 1 {
if s.len % pattern_len != 0 {
continue
}

pattern := s[0..pattern_len]
mut matches := true

repetitions := s.len / pattern_len
for rep in 1 .. repetitions {
start := rep * pattern_len
end := start + pattern_len
if s[start..end] != pattern {
matches = false
break
}
}

if matches {
return true
}
}
return false
}

fn main() {
content := os.read_file('ids.input') or { panic('Failed to read file: ${err}') }

ids := content.split(',')

mut sum1 := i64(0)
mut sum2 := i64(0)

for id in ids {
if id.len == 0 {
continue
}

range_parts := id.split('-')

start_str := range_parts[0].trim_space()
end_str := range_parts[1].trim_space()

start := strconv.parse_int(start_str, 10, 64) or {
eprintln('Start number isn\'t valid: "${id}"')
continue
}

end := strconv.parse_int(end_str, 10, 64) or {
eprintln('End number isn\'t valid: "${id}"')
continue
}

for num in start .. end + 1 {
num_str := num.str()

// Part 1
if has_exact_two_halves(num_str) {
sum1 += num
}

// Part 2
if has_repeating_pattern(num_str) {
sum2 += num
}
}
}

println('Part 1: ${sum1}')
println('Part 2: ${sum2}')
}
71 changes: 71 additions & 0 deletions 2025/03/kylepritchard.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
module main

import os
import strconv

fn max_sequence(s string, k int) string {
to_remove := s.len - k
mut remove_left := to_remove

mut stack := []u8{len: 0, cap: s.len}

for i in 0 .. s.len {
c := s[i]
for stack.len > 0 && remove_left > 0 && stack[stack.len - 1] < c {
stack.delete_last()
remove_left--
}
stack << c
}

if remove_left > 0 {
stack = stack[..stack.len - remove_left].clone()
}

if stack.len > k {
stack = stack[..k].clone()
}

return stack.bytestr()
}

fn main() {
content := os.read_file('banks.input') or { panic('Failed to read file: ${err}') }
lines := content.split_into_lines()

// Part 1
mut total_joltage := i64(0)
for line in lines {
if line.len == 0 {
continue
}

seq := max_sequence(line, 2)
if seq.len == 0 {
continue
}

num := strconv.parse_int(seq, 10, 64) or { 0 }
total_joltage += num
}

println('Part 1: ${total_joltage}')

// Part 2
total_joltage = 0
for line in lines {
if line.len == 0 {
continue
}

seq := max_sequence(line, 12)
if seq.len == 0 {
continue
}

num := strconv.parse_int(seq, 10, 64) or { 0 }
total_joltage += num
}

println('Part 2: ${total_joltage}')
}
159 changes: 159 additions & 0 deletions 2025/04/kylepritchard.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
module main

import os

struct Pos {
row int
col int
}

struct Offset {
dr int
dc int
}

fn count_adjacent(grid []u8, rows int, cols int, i int, j int, neighbors []Offset) int {
mut count := 0

for offset in neighbors {
ni := i + offset.dr
nj := j + offset.dc

if ni >= 0 && nj >= 0 && ni < rows && nj < cols { // inside grid
nidx := ni * cols + nj
if grid[nidx] == `@` {
count++
if count >= 4 {
break
}
}
}
}
return count
}

fn main() {
// Read input file
content := os.read_file('department.input') or { panic('Failed to read file: ${err}') }
lines := content.split_into_lines()

mut grid_lines := []string{}
for line in lines {
if line.len > 0 {
grid_lines << line
}
}

rows := grid_lines.len
cols := grid_lines[0].len

mut grid1 := []u8{len: rows * cols, cap: rows * cols}
mut grid2 := []u8{len: rows * cols, cap: rows * cols}

for i in 0 .. rows {
line := grid_lines[i]
row_start := i * cols
for j in 0 .. cols {
grid1[row_start + j] = line[j]
grid2[row_start + j] = line[j]
}
}

neighbors := [
Offset{-1, -1}, // diagonal above left
Offset{-1, 0}, // above
Offset{-1, 1}, // diagional above right
Offset{0, -1}, // left
Offset{0, 1}, // right
Offset{1, -1}, // diagonal below left
Offset{1, 0}, // below
Offset{1, 1}, // diagonal below right
]

// Part 1
mut part1_count := 0
for i in 0 .. rows {
row_start := i * cols
for j in 0 .. cols {
idx := row_start + j
if grid1[idx] == `@` {
adj_count := count_adjacent(grid1, rows, cols, i, j, neighbors)
if adj_count < 4 {
part1_count++
}
}
}
}

println('Part 1: ${part1_count}')

// Part 2
mut total_removed := 0
mut current_grid := grid2.clone()
mut changed := true

mut to_check := []Pos{cap: rows * cols}

for i in 0 .. rows {
for j in 0 .. cols {
to_check << Pos{i, j}
}
}

for changed {
changed = false
mut to_remove := []Pos{cap: to_check.len}
mut next_to_check := []Pos{cap: rows * cols}
mut modified := []bool{len: rows * cols, init: false}

for pos in to_check {
i := pos.row
j := pos.col
idx := i * cols + j

if current_grid[idx] != `@` {
continue
}

adj_count := count_adjacent(current_grid, rows, cols, i, j, neighbors)
if adj_count < 4 {
to_remove << pos
}
}

// Remove rolls
if to_remove.len > 0 {
changed = true
total_removed += to_remove.len

// Mark positions as removed and track their neighbors
for pos in to_remove {
i := pos.row
j := pos.col
idx := i * cols + j
current_grid[idx] = `.`
modified[idx] = true

// Add neighbors to next iteration's check list
for offset in neighbors {
ni := i + offset.dr
nj := j + offset.dc
if ni >= 0 && nj >= 0 && ni < rows && nj < cols {
nidx := ni * cols + nj
if !modified[nidx] {
modified[nidx] = true
next_to_check << Pos{ni, nj}
}
}
}
}

to_check = next_to_check.clone()
} else {
// No more to remove
break
}
}

println('Part 2: ${total_removed}')
}
2 changes: 2 additions & 0 deletions known/2025/01/kylepritchard.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Part 1: 3
Part 2: 6
2 changes: 2 additions & 0 deletions known/2025/02/kylepritchard.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Part 1: 1227775554
Part 2: 4174379265
2 changes: 2 additions & 0 deletions known/2025/03/kylepritchard.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Part 1: 357
Part 2: 3121910778619
2 changes: 2 additions & 0 deletions known/2025/04/kylepritchard.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Part 1: 13
Part 2: 43