package main import ( "bufio" "fmt" "log" "os" "strconv" "strings" ) var progs map[int][]int var groups map[int][]int func main() { inp := StdinToStrings() part1(inp) part2() } func part1(inp []string) { progs = make(map[int][]int) for i := range inp { pts := strings.Split(inp[i], " ") mn := Atoi(pts[0]) for _, v := range pts[2:] { if v[len(v)-1] == ',' { v = v[:len(v)-1] } if v = strings.TrimSpace(v); v != "" { sub := Atoi(v) progs[mn] = append(progs[mn], sub) } } } var res int for k := range progs { if pRes, _ := progCanAccess(k, 0, []int{}); pRes { res++ } } fmt.Println(res, "programs can access zero") } func part2() { groups = make(map[int][]int) for k, v := range progs { isNew := true for gk := range groups { if can, _ := progCanAccess(k, gk, []int{}); can { AddToGroup(gk, k) isNew = false break } } if isNew { // We went through all groups and couldn't access any groups[k] = v } } fmt.Println(len(groups), "total groups") } func AddToGroup(grp, prog int) { if !SliceContains(groups[grp], prog) { groups[grp] = append(groups[grp], prog) } for _, v := range progs[prog] { if !SliceContains(groups[grp], v) { groups[grp] = append(groups[grp], v) } } } func progCanAccess(st, end int, tried []int) (bool, []int) { // Have we already tried this one? if SliceContains(tried, st) { return false, tried } tried = append(tried, st) // Is this it? if st == end { return true, tried } // Is it direct? if SliceContains(progs[st], end) { return true, tried } // Ok, recurse var res bool for _, v := range progs[st] { if res, tried = progCanAccess(v, end, tried); res { return res, tried } } return false, tried } func SliceContains(sl []int, tgt int) bool { for i := range sl { if sl[i] == tgt { return true } } return false } func StdinToStrings() []string { var input []string scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { input = append(input, scanner.Text()) } return input } func Atoi(i string) int { var ret int var err error if ret, err = strconv.Atoi(i); err != nil { log.Fatal("Invalid Atoi") } return ret }