add day12 part 1
This commit is contained in:
151
day12/price.go
Normal file
151
day12/price.go
Normal file
@@ -0,0 +1,151 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"fmt"
|
||||
"strings"
|
||||
"errors"
|
||||
)
|
||||
|
||||
|
||||
// data types
|
||||
|
||||
type Field struct {
|
||||
garden *Garden
|
||||
x uint32
|
||||
y uint32
|
||||
}
|
||||
|
||||
func (f Field) val() byte {
|
||||
return (*f.garden).fields[int(f.y)][int(f.x)]
|
||||
}
|
||||
|
||||
func (f Field) eval_region(r *Region) []Field {
|
||||
field_val := f.val()
|
||||
neighbours := make([]Field, 0, 4)
|
||||
garden := (*f.garden).fields
|
||||
|
||||
if field_val >= 'a' { return neighbours }
|
||||
|
||||
if f.x > 0 {
|
||||
if garden[f.y][f.x-1] == field_val {
|
||||
// has fitting left field
|
||||
neighbours = append(neighbours, Field{f.garden, f.x-1, f.y})
|
||||
} else if garden[f.y][f.x-1] != field_val + ('a' - 'A') {
|
||||
r.perimeter++
|
||||
}
|
||||
} else {
|
||||
r.perimeter++
|
||||
}
|
||||
|
||||
if int(f.x) < len(garden[0]) - 1 {
|
||||
if garden[f.y][f.x+1] == field_val {
|
||||
// has fitting right field
|
||||
neighbours = append(neighbours, Field{f.garden, f.x+1, f.y})
|
||||
} else if garden[f.y][f.x+1] != field_val + ('a' - 'A') {
|
||||
r.perimeter++
|
||||
}
|
||||
} else {
|
||||
r.perimeter++
|
||||
}
|
||||
|
||||
if int(f.y) > 0 {
|
||||
if garden[f.y-1][f.x] == field_val {
|
||||
// har fitting lower field
|
||||
neighbours = append(neighbours, Field{f.garden, f.x, f.y-1})
|
||||
} else if garden[f.y-1][f.x] != field_val + ('a' - 'A') {
|
||||
r.perimeter++
|
||||
}
|
||||
} else {
|
||||
r.perimeter++
|
||||
}
|
||||
|
||||
if int(f.y) < len(garden) - 1 {
|
||||
if garden[f.y+1][f.x] == field_val {
|
||||
// has fitting upper field
|
||||
neighbours = append(neighbours, Field{f.garden, f.x, f.y+1})
|
||||
} else if garden[f.y+1][f.x] != field_val + ('a' - 'A') {
|
||||
r.perimeter++
|
||||
}
|
||||
} else {
|
||||
r.perimeter++
|
||||
}
|
||||
|
||||
// mark field as processed (change to lower case)
|
||||
garden[f.y][f.x] = f.val() + ('a' - 'A')
|
||||
|
||||
r.area++
|
||||
|
||||
return neighbours
|
||||
}
|
||||
|
||||
type Region struct {
|
||||
area uint32
|
||||
perimeter uint32
|
||||
}
|
||||
|
||||
|
||||
type Garden struct {
|
||||
fields [][]byte
|
||||
}
|
||||
|
||||
func (g Garden) field() (Field, error) {
|
||||
for i := range g.fields {
|
||||
for j := range g.fields[i] {
|
||||
if g.fields[i][j] < 'a' {
|
||||
return Field{&g, uint32(j), uint32(i)}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return Field{nil, 0, 0}, errors.New("no more fields")
|
||||
}
|
||||
|
||||
|
||||
|
||||
// general util
|
||||
func check(e error) {
|
||||
if e != nil { panic(e) }
|
||||
}
|
||||
|
||||
func new_garden_matrix(input string) Garden {
|
||||
dat_str := strings.TrimSpace(input)
|
||||
lines := strings.Split(dat_str, "\n")
|
||||
out := make([][]byte, 0, len(lines))
|
||||
|
||||
for _, line := range lines {
|
||||
out = append(out, []byte(line))
|
||||
}
|
||||
return Garden{out}
|
||||
}
|
||||
|
||||
|
||||
// main loop
|
||||
func main() {
|
||||
|
||||
// read in file
|
||||
dat, err := os.ReadFile("data.txt")
|
||||
check(err)
|
||||
garden := new_garden_matrix(string(dat))
|
||||
neighbours := make(chan Field, 1000)
|
||||
|
||||
price_acc := 0
|
||||
|
||||
f, err := garden.field()
|
||||
for err == nil {
|
||||
r := Region{0,0}
|
||||
neighbours <- f
|
||||
for len(neighbours) > 0 {
|
||||
field := <- neighbours
|
||||
for _, new_field := range field.eval_region(&r) {
|
||||
neighbours <- new_field
|
||||
}
|
||||
}
|
||||
|
||||
price_acc += int(r.area * r.perimeter)
|
||||
|
||||
f, err = garden.field()
|
||||
}
|
||||
close(neighbours)
|
||||
|
||||
fmt.Println(price_acc)
|
||||
}
|
||||
Reference in New Issue
Block a user