Compare commits

...

3 commits

Author SHA1 Message Date
976d3b5e01 solve day 6 (with maths) 2023-12-08 19:04:55 +01:00
fa66368b91 solve day 5 part 2 2023-12-08 18:14:11 +01:00
908c7a9d29 solve day 5 part 1 2023-12-08 17:12:46 +01:00
10 changed files with 669 additions and 0 deletions

188
2023/day05_almanac.go Normal file
View file

@ -0,0 +1,188 @@
package _023
import (
"bufio"
"io"
"slices"
"strings"
)
func Day05Part1(input io.Reader) (int, error) {
scanner := bufio.NewScanner(input)
scanner.Scan()
seeds := lineToInts(strings.TrimPrefix(scanner.Text(), "seeds: "))
scanner.Scan()
inMap := false
var currentMap day05Map
for scanner.Scan() {
line := scanner.Text()
if line == "" {
for i, seed := range seeds {
seeds[i] = currentMap.convert(seed)
}
inMap = false
currentMap = nil
} else if strings.HasSuffix(line, "map:") {
inMap = true
} else if inMap {
currentMap = append(currentMap, newDay05Range(line))
}
}
if inMap {
// Convert one last time if necessary
for i, seed := range seeds {
seeds[i] = currentMap.convert(seed)
}
}
return slices.Min(seeds), nil
}
func Day05Part2(input io.Reader) (int, error) {
scanner := bufio.NewScanner(input)
scanner.Scan()
seedRanges := parseSeedRanges(lineToInts(strings.TrimPrefix(scanner.Text(), "seeds: ")))
scanner.Scan()
inMap := false
var currentMap day05Map
for scanner.Scan() {
line := scanner.Text()
if line == "" {
var newRanges []day05SeedRange
for _, sRange := range seedRanges {
newRanges = append(newRanges, currentMap.convertRange(sRange)...)
}
seedRanges = newRanges
inMap = false
currentMap = nil
} else if strings.HasSuffix(line, "map:") {
inMap = true
} else if inMap {
currentMap = append(currentMap, newDay05Range(line))
}
}
if inMap {
// Convert one last time if necessary
var newRanges []day05SeedRange
for _, sRange := range seedRanges {
newRanges = append(newRanges, currentMap.convertRange(sRange)...)
}
seedRanges = newRanges
inMap = false
currentMap = nil
}
mini := int(^uint(0) >> 1) // highest int
for _, r := range seedRanges {
if r.start < mini {
mini = r.start
}
}
return mini, nil
}
func parseSeedRanges(ints []int) []day05SeedRange {
ranges := make([]day05SeedRange, len(ints)/2)
for i := 0; i < len(ints)-1; i += 2 {
ranges[i/2] = day05SeedRange{start: ints[i], end: ints[i] + ints[i+1]}
}
return ranges
}
// range is [start; end)
// start is included, end is not.
type day05SeedRange struct {
start, end int
}
type day05Range struct {
destStart, sourceStart, length int
}
func newDay05Range(line string) day05Range {
ints := lineToInts(line)
return day05Range{
destStart: ints[0],
sourceStart: ints[1],
length: ints[2],
}
}
func (r day05Range) sourceEnd() int {
return r.sourceStart + r.length
}
func (r day05Range) destEnd() int {
return r.destStart + r.length
}
func (r day05Range) convert(n int) (int, bool) {
if n >= r.sourceStart && n < r.sourceEnd() {
return r.mustConvert(n), true
}
return n, false
}
func (r day05Range) mustConvert(n int) int {
return n - r.sourceStart + r.destStart
}
func (r day05Range) convertRange(s day05SeedRange) (converted []day05SeedRange, notConverted []day05SeedRange) {
if r.sourceStart <= s.start && s.end <= r.sourceEnd() {
// s-----s
// r--------r
return []day05SeedRange{{start: r.mustConvert(s.start), end: r.mustConvert(s.end)}}, nil
} else if s.start < r.sourceStart && r.sourceStart <= s.end && s.end <= r.sourceEnd() {
// s-------s
// r--------r
return []day05SeedRange{{start: r.destStart, end: r.mustConvert(s.end)}}, []day05SeedRange{{start: s.start, end: r.sourceStart}}
} else if r.sourceStart <= s.start && s.start <= r.sourceEnd() && r.sourceEnd() < s.end {
// s-------s
// r--------r
return []day05SeedRange{{start: r.mustConvert(s.start), end: r.destEnd()}}, []day05SeedRange{{start: r.sourceEnd(), end: s.end}}
} else if s.start <= r.sourceStart && r.sourceEnd() < s.end {
// s------------s
// r--------r
return []day05SeedRange{{start: r.destStart, end: r.destEnd()}}, []day05SeedRange{{start: s.start, end: r.sourceStart}, {start: r.sourceEnd(), end: s.end}}
} else {
// s---s
// r-----r
return nil, []day05SeedRange{s}
}
}
type day05Map []day05Range
func (m day05Map) convert(n int) int {
for _, dRange := range m {
if conv, ok := dRange.convert(n); ok {
return conv
}
}
return n
}
func (m day05Map) convertRange(s day05SeedRange) []day05SeedRange {
var converted []day05SeedRange
toConvert := []day05SeedRange{s}
for _, dRange := range m {
var toConvertNext []day05SeedRange
for _, c := range toConvert {
var conv []day05SeedRange
conv, toConvertNext = dRange.convertRange(c)
converted = append(converted, conv...)
}
toConvert = toConvertNext
}
converted = append(converted, toConvert...)
return converted
}

View file

@ -0,0 +1,63 @@
package _023
import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"os"
"testing"
)
func TestDay05Part1(t *testing.T) {
tests := []testCase{
{"inputs/day05_test1", 1},
{"inputs/day05", 227653707},
}
for _, test := range tests {
t.Run(test.filename, check(test, Day05Part1))
}
t.Run("inputs/day05", func(t *testing.T) {
file, err := os.Open("inputs/day05")
require.NoError(t, err)
got, err := Day05Part1(file)
require.NoError(t, err)
assert.Less(t, got, 392296326) // 392296326 is too high
})
}
func TestDay05Part2(t *testing.T) {
tests := []testCase{
{"inputs/day05_test2", 46},
{"inputs/day05", 78775051},
}
for _, test := range tests {
t.Run(test.filename, check(test, Day05Part2))
}
}
func TestDay05Ranges(t *testing.T) {
tests := []struct {
name string
dRange day05Range
seedRange day05SeedRange
expected []day05SeedRange
}{
{
"seed included in range",
day05Range{0, 5, 5},
day05SeedRange{6, 8},
[]day05SeedRange{{1, 3}},
},
{
"range included in seed",
day05Range{0, 10, 2},
day05SeedRange{9, 13},
[]day05SeedRange{{0, 2}, {9, 10}, {12, 13}},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
got := day05Map{test.dRange}.convertRange(test.seedRange)
assert.Equal(t, test.expected, got)
})
}
}

63
2023/day06_boats.go Normal file
View file

@ -0,0 +1,63 @@
package _023
import (
"bufio"
"fmt"
"io"
"math"
"strings"
)
func Day06Part1(input io.Reader) (int, error) {
scanner := bufio.NewScanner(input)
scanner.Scan()
times := lineToInts(strings.TrimPrefix(scanner.Text(), "Time:"))
scanner.Scan()
distances := lineToInts(strings.TrimPrefix(scanner.Text(), "Distance:"))
fmt.Println(times, distances)
margin := 1
for i := 0; i < len(times); i++ {
x1, x2 := zeros(times[i], distances[i])
if distance(x1, times[i]) <= distances[i] {
x1++
}
margin *= x2 - x1
}
return margin, nil
}
func zeros(time, distance int) (int, int) {
t, d := float64(time), float64(distance)
delta := math.Sqrt(math.Pow(t, 2) - 4*d)
return int(math.Ceil((t - delta) / 2)), int(math.Ceil((t + delta) / 2))
}
func distance(timePress, timeMax int) int {
return timePress * (timeMax - timePress)
}
func Day06Part2(input io.Reader) (int, error) {
scanner := bufio.NewScanner(input)
scanner.Scan()
times := lineToInts(strings.ReplaceAll(strings.TrimPrefix(scanner.Text(), "Time:"), " ", ""))
scanner.Scan()
distances := lineToInts(strings.ReplaceAll(strings.TrimPrefix(scanner.Text(), "Distance:"), " ", ""))
fmt.Println(times, distances)
margin := 1
for i := 0; i < len(times); i++ {
x1, x2 := zeros(times[i], distances[i])
if distance(x1, times[i]) <= distances[i] {
x1++
}
margin *= x2 - x1
}
return margin, nil
}

25
2023/day06_boats_test.go Normal file
View file

@ -0,0 +1,25 @@
package _023
import (
"testing"
)
func TestDay06Part1(t *testing.T) {
tests := []testCase{
{"inputs/day06_test1", 288},
{"inputs/day06", 1660968},
}
for _, test := range tests {
t.Run(test.filename, check(test, Day06Part1))
}
}
func TestDay06Part2(t *testing.T) {
tests := []testCase{
{"inputs/day06_test1", 71503},
{"inputs/day06", 26499773},
}
for _, test := range tests {
t.Run(test.filename, check(test, Day06Part2))
}
}

236
2023/inputs/day05 Normal file
View file

@ -0,0 +1,236 @@
seeds: 2880930400 17599561 549922357 200746426 1378552684 43534336 155057073 56546377 824205101 378503603 1678376802 130912435 2685513694 137778160 2492361384 188575752 3139914842 1092214826 2989476473 58874625
seed-to-soil map:
341680072 47360832 98093750
1677587229 1836834678 160297919
1122651749 4014790961 280176335
2279929873 2689269992 53644948
3916120104 1199400457 172302726
0 381576527 58197295
1402828084 3450816018 274759145
3909949227 2540063154 6170877
802918801 2384227172 155835982
4088422830 3244271552 206544466
958754783 1997132597 28874650
58197295 306349987 75226540
180784667 145454582 160895405
2334903647 1543332738 293501940
3699983017 2997982209 25342830
2333574821 2687941166 1328826
3111317969 1371703183 171629555
2806959198 2135774873 248452299
2766721604 717118138 40237594
3055411497 2632034694 55906472
2628405587 3023325039 138316017
1837885148 757355732 442044725
3725325847 2813358829 184623380
3353391413 2026007247 109767626
987629433 3962399141 10015813
717118138 2546234031 85800663
3282947524 2742914940 70443889
1080275742 3972414954 42376007
133423835 0 47360832
3463159039 3725575163 236823978
997645246 3161641056 82630496
soil-to-fertilizer map:
303672059 1087423328 103502353
171922589 2907629744 91556518
2064217168 468859004 91214014
1129888530 1046445685 40977643
3698610046 4215442249 79525047
1045870106 1586657152 41455160
1170866173 1322928302 17679660
4160148003 3332238470 107558461
4267706464 3853049576 27260832
0 3007612896 90771201
3447204990 3880310408 249339913
1189561657 1438888401 43309463
4019710828 3219712242 104981462
2226263856 2187322171 114088350
553216166 1847338068 182148047
3217647099 3439796931 229557891
2832115692 1482197864 23307900
867366834 94995931 178503272
1969221237 0 94995931
3785679859 3704810535 148239041
1095751900 2693816297 34136630
4124692290 3669354822 35455713
454935727 1340607962 98280439
2204466075 1628112312 21797781
1947833351 2164918461 21387886
2634687717 1649910093 197427975
263479107 2850768768 40192952
3696544903 3217647099 2065143
735364213 1190925681 132002621
3050783393 2337205982 47600704
1087325266 2999186262 8426634
3778135093 3324693704 7544766
2855423592 273499203 195359801
90771201 1505505764 81151388
2340352206 560073018 290906919
1531641800 939263745 107181940
1188545833 2186306347 1015824
1355686961 850979937 88283808
1492181516 2029486115 39460284
1638823740 2384806686 309009611
2155431182 2894390312 13239432
1443970769 2068946399 48210747
1232871120 2727952927 122815841
3933918900 4129650321 85791928
2631259125 2890961720 3428592
407174412 2117157146 47761315
2168670614 2301410521 35795461
fertilizer-to-water map:
4253126168 3603943470 41841128
3150812716 3873122781 161556325
4132148538 3445929121 16652907
4071215062 2557593856 10373731
3585414898 2401284809 61555959
124617758 989226185 56063423
1311995731 916233018 72993167
180681181 891200267 25032751
1577315548 1448436684 231921083
69948934 1391916079 39397864
2730663795 3577458422 26485048
2453473122 3255362867 102306532
4148801445 3801350502 12292818
3002725397 3107275548 148087319
3525935437 3813643320 59479461
3982955340 3357669399 88259722
2631712351 2567967587 98951444
628324302 2038793089 109830184
3427245435 3721480891 3936914
796140554 1045289608 36965524
939693576 1140241200 24301167
205713932 1680357767 358435322
4161094263 2666919031 92031905
1103981621 0 206162329
1809236631 761213122 129987145
1310143950 1431313943 1851781
4081588793 3056715803 50559745
738154486 1082255132 57986068
564149254 206162329 64175048
3722667150 4034679106 260288190
3431182349 2462840768 94753088
109346798 1433165724 15270960
2757148843 2811139249 245576554
1044349135 2294919620 59632486
833106078 270337377 106587498
3646970857 3645784598 75696293
0 2354552106 4006979
1974270838 376924875 384288247
3312369041 3462582028 114876394
2401284809 2758950936 52188313
1384988898 1199589429 192326650
963994743 2214565228 80354392
1939223776 1164542367 35047062
4006979 2148623273 65941955
2555779654 3725417805 75932697
water-to-light map:
1553071310 2767299260 81555093
1638385137 3758734 7165416
3923895602 3742459208 355646104
2563492152 40550035 317968
357175543 151852464 53516575
756535305 2730597762 36701498
1142337672 1915537677 164067723
436470886 2848854353 61956232
1316538987 1679005354 102639946
609765571 2079605400 146769734
1306405395 2660382036 10133592
3817572860 3406157555 106322742
2023184953 353497588 62195869
3531543848 4223491605 71475691
410692118 126073696 25778768
4279541706 3727562743 14896465
2903607795 1495097536 74179449
1794747312 2279656479 95385933
2783150325 2269091374 10565105
3406157555 4098105312 125386293
2145462956 205369039 148128549
2833741244 2401175172 69866551
793236803 685594104 306384629
1645550553 2511185277 149196759
1419178933 1781645300 133892377
1634626403 0 3758734
3274934245 2471041723 36449164
0 1097896179 357175543
2563810120 991978733 105917446
4294438171 3727033618 529125
2688189328 1569276985 94960997
2669727566 2507490887 3694390
3311383409 10924150 29625885
1099621432 2226375134 42716240
1890133245 2910810585 133051708
583632811 2375042412 26132760
498427118 40868003 85205693
2293591505 415693457 269900647
2673421956 1664237982 14767372
2085380822 2670515628 60082134
3603019539 3512480297 214553321
2977787244 3043862293 297147001
2793715430 1455071722 40025814
light-to-temperature map:
3752181853 3850028427 61847460
3392702182 4061054452 68370555
3610251302 4129425007 141930551
2019529001 2633762146 55812503
1423059901 2612524947 21237199
1637625157 3160312690 128493598
2109055159 2018596226 368399035
343891384 811352094 920120231
154347384 2422980947 189544000
2075341504 1978947609 33713655
1444297100 2966984633 193328057
35985686 2689574649 118361698
2477454194 0 811352094
1772053717 1854798742 124148867
1264011615 2807936347 159048286
0 2386995261 35985686
1766118755 2012661264 5934962
3814029313 3392702182 457326245
3461072737 3911875887 149178565
1896202584 1731472325 123326417
temperature-to-humidity map:
3344602117 2991074372 262457649
1707309180 3911386116 383581180
3778482785 2130995124 374719434
3607059766 3253532021 171423019
584508486 478912361 161371970
1578590582 2505714558 128718598
3294145751 1806488186 50456366
1143023241 2829557603 161516769
1304540010 1856944552 274050572
2090890360 3424955040 344665999
2435556359 1143023241 663464945
496214964 1000471163 88293522
0 640284331 360186832
3099021304 2634433156 195124447
360186832 342884229 136028132
745880456 0 342884229
4153202219 3769621039 141765077
humidity-to-location map:
3114211644 984440400 35385940
3530465412 479339778 128291026
0 3699707734 285474938
2898087648 3606829306 92878428
2762235329 607630804 135852319
4210792153 4197161772 84175143
3149597584 31394121 380867828
1848709689 0 31394121
1880103810 412261949 67077829
285474938 1579019790 1563234751
2990966076 3566305423 40523883
2434079297 1019826340 328156032
2371232521 3985182672 62846776
1947181639 3142254541 424050882
3899713715 1347982372 148315733
3031489959 1496298105 82721685
4197161772 4281336915 13630381
3658756438 743483123 240957277

34
2023/inputs/day05_test1 Normal file
View file

@ -0,0 +1,34 @@
seeds: 79 14 55 13
seed-to-soil map:
50 98 2
52 50 48
soil-to-fertilizer map:
0 15 37
37 52 2
39 0 15
fertilizer-to-water map:
49 53 8
0 11 42
42 0 7
57 7 4
water-to-light map:
88 18 7
18 25 70
light-to-temperature map:
45 77 23
81 45 19
68 64 13
temperature-to-humidity map:
0 69 1
1 0 69
humidity-to-location map:
60 56 37
56 93 4
1 35 1

33
2023/inputs/day05_test2 Normal file
View file

@ -0,0 +1,33 @@
seeds: 79 14 55 13
seed-to-soil map:
50 98 2
52 50 48
soil-to-fertilizer map:
0 15 37
37 52 2
39 0 15
fertilizer-to-water map:
49 53 8
0 11 42
42 0 7
57 7 4
water-to-light map:
88 18 7
18 25 70
light-to-temperature map:
45 77 23
81 45 19
68 64 13
temperature-to-humidity map:
0 69 1
1 0 69
humidity-to-location map:
60 56 37
56 93 4

2
2023/inputs/day06 Normal file
View file

@ -0,0 +1,2 @@
Time: 47 98 66 98
Distance: 400 1213 1011 1540

2
2023/inputs/day06_test1 Normal file
View file

@ -0,0 +1,2 @@
Time: 7 15 30
Distance: 9 40 200

23
2023/lib.go Normal file
View file

@ -0,0 +1,23 @@
package _023
import (
"regexp"
"strconv"
"strings"
)
var reg = regexp.MustCompile(`\s+`)
func lineToInts(line string) []int {
line = strings.TrimSpace(line)
values := reg.Split(line, -1)
ints := make([]int, len(values))
for i, value := range values {
number, err := strconv.Atoi(value)
if err != nil {
panic(err)
}
ints[i] = number
}
return ints
}