kartoffelsaft@programming.devtoAdvent Of Code@programming.dev•❄️ - 2023 DAY 3 SOLUTIONS -❄️
·
11 months agoOh yeah, I misspoke, gonna edit.
Oh yeah, I misspoke, gonna edit.
hmm, my code keeps getting truncated at for y in ..
, anyone have any idea why? Maybe the "<" right after that confuses a parser somewhere?
Did this in Odin
Here's a tip: if you are using a language / standard library that doesn't have a set, you can mimic it with a map from your key to a nullary (in this case an empty struct)
package day3
import "core:fmt"
import "core:strings"
import "core:unicode"
import "core:strconv"
flood_get_num :: proc(s: string, i: int) -> (parsed: int, pos: int) {
if !unicode.is_digit(rune(s[i])) do return -99999, -1
pos = strings.last_index_proc(s[:i+1], proc(r:rune)->bool{return !unicode.is_digit(r)})
pos += 1
ok: bool
parsed, ok = strconv.parse_int(s[pos:])
return parsed, pos
}
p1 :: proc(input: []string) {
// wow what a gnarly type
foundNumSet := make(map[[2]int]struct{})
defer delete(foundNumSet)
total := 0
for y in 0..
Did mine in Odin. Found this day's to be super easy, most of the challenge was just parsing.
package day2
import "core:fmt"
import "core:strings"
import "core:strconv"
import "core:unicode"
Round :: struct {
red: int,
green: int,
blue: int,
}
parse_round :: proc(s: string) -> Round {
ret: Round
rest := s
for {
nextNumAt := strings.index_proc(rest, unicode.is_digit)
if nextNumAt == -1 do break
rest = rest[nextNumAt:]
numlen: int
num, ok := strconv.parse_int(rest, 10, &numlen)
rest = rest[numlen+len(" "):]
if rest[:3] == "red" {
ret.red = num
} else if rest[:4] == "blue" {
ret.blue = num
} else if rest[:5] == "green" {
ret.green = num
}
}
return ret
}
Game :: struct {
id: int,
rounds: [dynamic]Round,
}
parse_game :: proc(s: string) -> Game {
ret: Game
rest := s[len("Game "):]
idOk: bool
idLen: int
ret.id, idOk = strconv.parse_int(rest, 10, &idLen)
rest = rest[idLen+len(": "):]
for len(rest) > 0 {
endOfRound := strings.index_rune(rest, ';')
if endOfRound == -1 do endOfRound = len(rest)
append(&ret.rounds, parse_round(rest[:endOfRound]))
rest = rest[min(endOfRound+1, len(rest)):]
}
return ret
}
is_game_possible :: proc(game: Game) -> bool {
for round in game.rounds {
if round.red > 12 ||
round.green > 13 ||
round.blue > 14 {
return false
}
}
return true
}
p1 :: proc(input: []string) {
totalIds := 0
for line in input {
game := parse_game(line)
defer delete(game.rounds)
if is_game_possible(game) do totalIds += game.id
}
fmt.println(totalIds)
}
p2 :: proc(input: []string) {
totalPower := 0
for line in input {
game := parse_game(line)
defer delete(game.rounds)
minRed := 0
minGreen := 0
minBlue := 0
for round in game.rounds {
minRed = max(minRed , round.red )
minGreen = max(minGreen, round.green)
minBlue = max(minBlue , round.blue )
}
totalPower += minRed * minGreen * minBlue
}
fmt.println(totalPower)
}
Did this in Odin (very hashed together, especially finding the last number in part 2):
package day1
import "core:fmt"
import "core:strings"
import "core:strconv"
import "core:unicode"
p1 :: proc(input: []string) {
total := 0
for line in input {
firstNum := line[strings.index_proc(line, unicode.is_digit):][:1]
lastNum := line[strings.last_index_proc(line, unicode.is_digit):][:1]
calibrationValue := strings.concatenate({firstNum, lastNum})
defer delete(calibrationValue)
num, ok := strconv.parse_int(calibrationValue)
total += num
}
// daggonit thought it was the whole numbers
/*
for line in input {
firstNum := line
fFrom := strings.index_proc(firstNum, unicode.is_digit)
firstNum = firstNum[fFrom:]
fTo := strings.index_proc(firstNum, proc(r:rune)->bool {return !unicode.is_digit(r)})
if fTo == -1 do fTo = len(firstNum)
firstNum = firstNum[:fTo]
lastNum := line
lastNum = lastNum[:strings.last_index_proc(lastNum, unicode.is_digit)+1]
lastNum = lastNum[strings.last_index_proc(lastNum, proc(r:rune)->bool {return !unicode.is_digit(r)})+1:]
calibrationValue := strings.concatenate({firstNum, lastNum})
defer delete(calibrationValue)
num, ok := strconv.parse_int(calibrationValue, 10)
if !ok {
fmt.eprintf("%s could not be parsed from %s", calibrationValue, line)
return
}
total += num;
}
*/
fmt.println(total)
}
p2 :: proc(input: []string) {
parse_wordable :: proc(s: string) -> int {
if len(s) == 1 {
num, ok := strconv.parse_int(s)
return num
} else do switch s {
case "one" : return 1
case "two" : return 2
case "three": return 3
case "four" : return 4
case "five" : return 5
case "six" : return 6
case "seven": return 7
case "eight": return 8
case "nine" : return 9
}
return -1
}
total := 0
for line in input {
firstNumI, firstNumW := strings.index_multi(line, {
"one" , "1",
"two" , "2",
"three", "3",
"four" , "4",
"five" , "5",
"six" , "6",
"seven", "7",
"eight", "8",
"nine" , "9",
})
firstNum := line[firstNumI:][:firstNumW]
// last_index_multi doesn't seem to exist, doing this as backup
lastNumI, lastNumW := -1, -1
for {
nLastNumI, nLastNumW := strings.index_multi(line[lastNumI+1:], {
"one" , "1",
"two" , "2",
"three", "3",
"four" , "4",
"five" , "5",
"six" , "6",
"seven", "7",
"eight", "8",
"nine" , "9",
})
if nLastNumI == -1 do break
lastNumI += nLastNumI+1
lastNumW = nLastNumW
}
lastNum := line[lastNumI:][:lastNumW]
total += parse_wordable(firstNum)*10 + parse_wordable(lastNum)
}
fmt.println(total)
}
Had a ton of trouble with part 1 until I realized I misinterpreted it. Especially annoying because the example was working fine. So paradoxically part 2 was easier than 1.
Odin
When I read the problem description I expected the input to also be 2 digit numbers. When I looked at it I just had to say "huh."
Second part I think you definitely have to do in reverse (edit: if you are doing a linear search for the answer), as that allows you to nope out as soon as you find a match, whereas with doing it forward you have to keep checking just in case.
Formatted code
package day5 import "core:fmt" import "core:strings" import "core:slice" import "core:strconv" Range :: struct { dest: int, src: int, range: int, } Mapper :: struct { ranges: []Range, } parse_range :: proc(s: string) -> (ret: Range) { rest := s parseLen := -1 destOk: bool ret.dest, destOk = strconv.parse_int(rest, 10, &parseLen) rest = strings.trim_left_space(rest[parseLen:]) srcOk: bool ret.src, srcOk = strconv.parse_int(rest, 10, &parseLen) rest = strings.trim_left_space(rest[parseLen:]) rangeOk: bool ret.range, rangeOk = strconv.parse_int(rest, 10, &parseLen) return } parse_mapper :: proc(ss: []string) -> (ret: Mapper) { ret.ranges = make([]Range, len(ss)-1) for s, i in ss[1:] { ret.ranges[i] = parse_range(s) } return } parse_mappers :: proc(ss: []string) -> []Mapper { mapsStr := make([dynamic][]string) defer delete(mapsStr) restOfLines := ss isLineEmpty :: proc(s: string)->bool {return len(s)==0} for i, found := slice.linear_search_proc(restOfLines, isLineEmpty); found; i, found = slice.linear_search_proc(restOfLines, isLineEmpty) { append(&mapsStr, restOfLines[:i]) restOfLines = restOfLines[i+1:] } append(&mapsStr, restOfLines[:]) return slice.mapper(mapsStr[1:], parse_mapper) } apply_mapper :: proc(mapper: Mapper, num: int) -> int { for r in mapper.ranges { if num >= r.src && num - r.src < r.range do return num - r.src + r.dest } return num } p1 :: proc(input: []string) { maps := parse_mappers(input) defer { for m in maps do delete(m.ranges) delete(maps) } restSeeds := input[0][len("seeds: "):] min := 0x7fffffff for len(restSeeds) > 0 { seedLen := -1 seed, seedOk := strconv.parse_int(restSeeds, 10, &seedLen) restSeeds = strings.trim_left_space(restSeeds[seedLen:]) fmt.print(seed) for m in maps { seed = apply_mapper(m, seed) fmt.print(" ->", seed) } fmt.println() if seed < min do min = seed } fmt.println(min) } apply_mapper_reverse :: proc(mapper: Mapper, num: int) -> int { for r in mapper.ranges { if num >= r.dest && num - r.dest < r.range do return num - r.dest + r.src } return num } p2 :: proc(input: []string) { SeedRange :: struct { start: int, len: int, } seeds := make([dynamic]SeedRange) restSeeds := input[0][len("seeds: "):] for len(restSeeds) > 0 { seedLen := -1 seedS, seedSOk := strconv.parse_int(restSeeds, 10, &seedLen) restSeeds = strings.trim_left_space(restSeeds[seedLen:]) seedL, seedLOk := strconv.parse_int(restSeeds, 10, &seedLen) restSeeds = strings.trim_left_space(restSeeds[seedLen:]) append(&seeds, SeedRange{seedS, seedL}) } maps := parse_mappers(input) defer { for m in maps do delete(m.ranges) delete(maps) } for i := 0; true; i += 1 { rseed := i #reverse for m in maps { rseed = apply_mapper_reverse(m, rseed) } found := false for sr in seeds { if rseed >= sr.start && rseed < sr.start + sr.len { found = true break } } if found { fmt.println(i) break } } }