package main import ( "fmt" "os" "strconv" "strings" ) type Report struct { number int levels []int valid bool direction string flag int dampened bool } // Reports stored one per line with levels in each column. // In safe reports, the levels are either all increasing or all decreasing AND // Any two adjacent levels differ by at least one and at most three. func main() { input, err := os.ReadFile("input") if err != nil { fmt.Println(err) } var reports []Report lines := strings.Split(string(input), "\n") for idx, val := range lines[0 : len(lines)-1] { reportFields := strings.Fields(val) report := Report{ number: idx, valid: true, direction: "ASC", flag: -1, dampened: false, } for _, field := range reportFields { reportVal, err := strconv.Atoi(field) if err != nil { break } report.levels = append(report.levels, reportVal) } reports = append(reports, report) } var valid int for _, report := range reports { if report.IsValid() { valid++ } fmt.Printf("%v\n", report) } fmt.Printf("Total: %v Valid %v\n", len(reports), valid) } func (report *Report) IsValid() bool { if report.flag > 0 { report.dampened = true } // Determine direction if len(report.levels) >= 1 { report.direction = DetermineDirection(report.levels[0], report.levels[1]) report.valid = report.ValidDirection() && report.ValidDeltas() } if !report.valid && report.flag > 0 && !report.dampened { fmt.Printf("DAMPING:%v\n", report.levels) report.levels = remove(report.levels, report.flag) fmt.Printf("DAMPING:%v\n", report.levels) return report.IsValid() } return report.valid } func remove(slice []int, s int) []int { return append(slice[:s], slice[s+1:]...) } func (report *Report) ValidDeltas() bool { for idx, val := range report.levels { if prev := idx - 1; prev < 0 { continue } last := report.levels[idx-1] delta := Abs(val - last) if delta < 1 || delta > 3 { report.flag = idx return false } } return true } func (report *Report) ValidDirection() bool { for idx, val := range report.levels { if prev := idx - 1; prev < 0 { continue } last := report.levels[idx-1] switch report.direction { case "ASC": if last > val { report.flag = idx return false } case "DESC": if last < val { report.flag = idx return false } default: panic("aaaaaa") } } return true } func DetermineDirection(one, two int) string { diff := one - two if diff < 0 { return "ASC" } return "DESC" } func Abs(input int) int { if input < 0 { return -input } return input }