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 }