2024 Day 23 Complete
This commit is contained in:
parent
4f5898255b
commit
268d0a0141
3380
2024/day23/input
Normal file
3380
2024/day23/input
Normal file
File diff suppressed because it is too large
Load Diff
179
2024/day23/main.go
Normal file
179
2024/day23/main.go
Normal file
@ -0,0 +1,179 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
h "git.bullercodeworks.com/brian/adventofcode/helpers"
|
||||
)
|
||||
|
||||
func main() {
|
||||
inp := h.StdinToStringSlice()
|
||||
part1(inp)
|
||||
fmt.Println()
|
||||
part2(inp)
|
||||
}
|
||||
|
||||
func parseInput(inp []string) NetworkMap {
|
||||
network := make(map[string]h.Set)
|
||||
for _, l := range inp {
|
||||
pts := strings.Split(l, "-")
|
||||
if _, ok := network[pts[0]]; !ok {
|
||||
network[pts[0]] = h.NewSet(1)
|
||||
}
|
||||
if _, ok := network[pts[1]]; !ok {
|
||||
network[pts[1]] = h.NewSet(1)
|
||||
}
|
||||
network[pts[0]].Add(pts[1])
|
||||
network[pts[1]].Add(pts[0])
|
||||
}
|
||||
return NewNetworkMap(network)
|
||||
}
|
||||
|
||||
func part1(inp []string) {
|
||||
nwk := parseInput(inp)
|
||||
fmt.Println("# Part 1")
|
||||
total := 0
|
||||
wrk := nwk
|
||||
for _, comp := range wrk.Comps {
|
||||
conns := make([]string, 0, len(comp.Conns))
|
||||
for name := range comp.Conns {
|
||||
conns = append(conns, name)
|
||||
total++
|
||||
}
|
||||
}
|
||||
tris := wrk.FindTGroups()
|
||||
fmt.Println(len(tris))
|
||||
}
|
||||
|
||||
func part2(inp []string) {
|
||||
nwk := parseInput(inp)
|
||||
cnt := len(nwk.Comps)
|
||||
wrk := h.NewSet(cnt)
|
||||
for nm := range nwk.Comps {
|
||||
wrk.Add(nm)
|
||||
}
|
||||
group := BronKerbosch(h.NewSet(cnt+1), wrk, h.NewSet(cnt+1), h.NewSet(0), nwk.Network)
|
||||
fmt.Println("Group Size:", group.Size())
|
||||
fmt.Println("Password:", strings.Join(group.ToSortedSlice(), ","))
|
||||
}
|
||||
|
||||
func BronKerbosch(cl, chk, excl, kmax h.Set, graph map[string]h.Set) h.Set {
|
||||
if chk.Empty() && excl.Empty() {
|
||||
return cl
|
||||
}
|
||||
for vx := range chk {
|
||||
vxSet := h.NewSetFromValues(vx)
|
||||
vxConns := graph[vx]
|
||||
nC := cl.Union(vxSet)
|
||||
nWrk := chk.Intersection(vxConns)
|
||||
if nC.Size()+nWrk.Size() <= kmax.Size() {
|
||||
continue
|
||||
}
|
||||
newExcl := excl.Intersection(vxConns)
|
||||
fC := BronKerbosch(nC, nWrk, newExcl, kmax, graph)
|
||||
if fC.Size() > kmax.Size() {
|
||||
kmax = fC
|
||||
}
|
||||
chk.Remove(vx)
|
||||
excl.Add(vx)
|
||||
}
|
||||
return kmax
|
||||
}
|
||||
|
||||
type NetworkMap struct {
|
||||
Network map[string]h.Set
|
||||
Comps map[string]*Comp
|
||||
}
|
||||
|
||||
func NewNetworkMap(nwk map[string]h.Set) NetworkMap {
|
||||
nm := NetworkMap{Network: nwk, Comps: make(map[string]*Comp)}
|
||||
for name, conns := range nwk {
|
||||
for conn := range conns {
|
||||
nm.Connect(name, conn)
|
||||
}
|
||||
}
|
||||
return nm
|
||||
}
|
||||
|
||||
func (n *NetworkMap) Connect(c1, c2 string) {
|
||||
n.GetComputer(c1).Connect(n.GetComputer(c2))
|
||||
}
|
||||
|
||||
func (n *NetworkMap) GetComputer(nm string) *Comp {
|
||||
if cm, ok := n.Comps[nm]; ok {
|
||||
return cm
|
||||
}
|
||||
cm := NewComp(nm)
|
||||
n.Comps[nm] = cm
|
||||
return cm
|
||||
}
|
||||
|
||||
func (n *NetworkMap) FindTGroups() map[Group]bool {
|
||||
ret := make(map[Group]bool)
|
||||
chk := make(map[string]bool)
|
||||
for cn, comp := range n.Comps {
|
||||
if chk[cn] {
|
||||
continue
|
||||
}
|
||||
for nn, next := range comp.Conns {
|
||||
friends := comp.FindFriends(next)
|
||||
for _, friend := range friends {
|
||||
if cn[0] == 't' || nn[0] == 't' || friend[0] == 't' {
|
||||
grp := NewGroup([3]string{cn, nn, friend})
|
||||
ret[grp] = true
|
||||
}
|
||||
}
|
||||
chk[cn] = true
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
type Group struct {
|
||||
Comps [3]string
|
||||
}
|
||||
|
||||
func NewGroup(nodes [3]string) Group {
|
||||
s := nodes[:]
|
||||
sort.Strings(s)
|
||||
return Group{Comps: [3]string{s[0], s[1], s[2]}}
|
||||
}
|
||||
|
||||
func (g Group) String() string {
|
||||
return fmt.Sprintf("%s-%s-%s", g.Comps[0], g.Comps[1], g.Comps[2])
|
||||
}
|
||||
|
||||
type Comp struct {
|
||||
Name string
|
||||
Conns map[string]*Comp
|
||||
}
|
||||
|
||||
func NewComp(n string) *Comp {
|
||||
return &Comp{Name: n, Conns: make(map[string]*Comp)}
|
||||
}
|
||||
|
||||
func (c *Comp) Connect(o *Comp) {
|
||||
c.Conns[o.Name] = o
|
||||
o.Conns[c.Name] = c
|
||||
}
|
||||
|
||||
func (c *Comp) FindFriends(o *Comp) []string {
|
||||
var friends []string
|
||||
checked := make(map[string]bool)
|
||||
for name := range c.Conns {
|
||||
if name == c.Name || name == o.Name {
|
||||
continue
|
||||
}
|
||||
if _, ok := checked[name]; ok {
|
||||
continue
|
||||
}
|
||||
if _, ok := o.Conns[name]; !ok {
|
||||
continue
|
||||
}
|
||||
friends = append(friends, name)
|
||||
checked[name] = true
|
||||
}
|
||||
return friends
|
||||
}
|
32
2024/day23/testinput
Normal file
32
2024/day23/testinput
Normal file
@ -0,0 +1,32 @@
|
||||
kh-tc
|
||||
qp-kh
|
||||
de-cg
|
||||
ka-co
|
||||
yn-aq
|
||||
qp-ub
|
||||
cg-tb
|
||||
vc-aq
|
||||
tb-ka
|
||||
wh-tc
|
||||
yn-cg
|
||||
kh-ub
|
||||
ta-co
|
||||
de-co
|
||||
tc-td
|
||||
tb-wq
|
||||
wh-td
|
||||
ta-ka
|
||||
td-qp
|
||||
aq-cg
|
||||
wq-ub
|
||||
ub-vc
|
||||
de-ta
|
||||
wq-aq
|
||||
wq-vc
|
||||
wh-yn
|
||||
ka-de
|
||||
kh-ta
|
||||
co-tc
|
||||
wh-qp
|
||||
tb-vc
|
||||
td-yn
|
72
helpers/set.go
Normal file
72
helpers/set.go
Normal file
@ -0,0 +1,72 @@
|
||||
package aoc
|
||||
|
||||
import "slices"
|
||||
|
||||
type Set map[string]bool
|
||||
|
||||
func NewSet(l int) Set {
|
||||
return make(map[string]bool, l)
|
||||
}
|
||||
|
||||
func NewSetFromValues(v ...string) Set {
|
||||
s := NewSet(len(v))
|
||||
for _, val := range v {
|
||||
s[val] = true
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s Set) Add(nm string) {
|
||||
s[nm] = true
|
||||
}
|
||||
|
||||
func (s Set) Remove(nm string) {
|
||||
delete(s, nm)
|
||||
}
|
||||
|
||||
func (s Set) Contains(nm string) bool {
|
||||
_, ok := s[nm]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (s Set) Empty() bool {
|
||||
return len(s) == 0
|
||||
}
|
||||
|
||||
func (s Set) Size() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s Set) Intersection(o Set) Set {
|
||||
smallest, toCheck := s, o
|
||||
if o.Size() < s.Size() {
|
||||
smallest, toCheck = o, s
|
||||
}
|
||||
ix := NewSet(smallest.Size())
|
||||
for nm := range smallest {
|
||||
if toCheck.Contains(nm) {
|
||||
ix.Add(nm)
|
||||
}
|
||||
}
|
||||
return ix
|
||||
}
|
||||
|
||||
func (s Set) Union(o Set) Set {
|
||||
un := NewSet(s.Size() + o.Size())
|
||||
for nm := range s {
|
||||
un.Add(nm)
|
||||
}
|
||||
for nm := range o {
|
||||
un.Add(nm)
|
||||
}
|
||||
return un
|
||||
}
|
||||
|
||||
func (s Set) ToSortedSlice() []string {
|
||||
sl := make([]string, 0, s.Size())
|
||||
for nm := range s {
|
||||
sl = append(sl, nm)
|
||||
}
|
||||
slices.Sort(sl)
|
||||
return sl
|
||||
}
|
Loading…
Reference in New Issue
Block a user