package aoc import ( "bufio" "fmt" "io/ioutil" "log" "math" "os" "strconv" "strings" ) // Some handy Constants const ( BORDER_NS = "\u2502" BORDER_WE = "\u2500" BORDER_NW = "\u250C" BORDER_NE = "\u2510" BORDER_SW = "\u2514" BORDER_SE = "\u2518" FILL_CHAR = "\u2588" CLEAR_SCREEN = "\033[H\033[2J" MAX_INT = int(^uint(0) >> 1) MIN_INT = -MAX_INT - 1 SHRUG = "¯\\_(ツ)_/¯" ) // Gcd Finds the greatest common denominator func Gcd(x, y int) int { for y != 0 { x, y = y, x%y } return x } // Lcm finds the least common multiple, using gcd func Lcm(a, b int, integers ...int) int { result := a * b / Gcd(a, b) for i := 0; i < len(integers); i++ { result = Lcm(result, integers[i]) } return result } // AbsInt returns the absolute value of i func AbsInt(i int) int { if i < 0 { return i * -1 } return i } // ArgIsSet return true if an argument with the asked for key is present func ArgIsSet(a string) bool { for i := range os.Args { if os.Args[i] == a || strings.HasPrefix(os.Args[i], a+"=") { return true } } return false } // GetArgValue returns the argument with the asked for key or "" func GetArgValue(a string) string { for i := range os.Args { if strings.HasPrefix(os.Args[i], a+"=") { return strings.TrimPrefix(os.Args[i], a+"=") } } return "" } // GetArgNumber returns the asked for argument position or "" func GetArgNumber(i int) string { if len(os.Args) > i { return os.Args[i] } return "" } // OptArgNumber returns either the asked for argument position or the passed default func OptArgNumber(i int, def string) string { if len(os.Args) > i { return os.Args[i] } return def } // StdinToIntSlice reads from stdin and returns it as an int slice func StdinToIntSlice() []int { var ret []int st := StdinToStringSlice() for _, v := range st { ret = append(ret, Atoi(v)) } return ret } // StdinToStringSlice reads from stdin and returns it as a string slice func StdinToStringSlice() []string { var input []string scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { input = append(input, scanner.Text()) } return input } // StdinToCoordMap reads stdin and returns it as a CoordByteMap func StdinToCoordMap() CoordByteMap { return StringSliceToCoordByteMap(StdinToStringSlice()) } // Atoi is basically redundant 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 } // Itoa is basically redundant func Itoa(i int) string { return strconv.Itoa(i) } // StdinToString reads from stdin and returns a string func StdinToString() string { var input string scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { input += scanner.Text() } return input } // FileToStringSlice takes a file and returns it as a slice of strings func FileToStringSlice(fn string) []string { return strings.Split(string(FileToBytes(fn)), "\n") } // FileToString reads a file and returns it as a string func FileToString(fn string) string { return string(FileToBytes(fn)) } // FileToBytes reads a file and returns it as a slice of bytes func FileToBytes(fn string) []byte { var c []byte var err error c, err = ioutil.ReadFile(fn) if err != nil { fmt.Println("Unable to read file: " + fn) os.Exit(1) } return c } // PrintProgress is for outputting a progress bar func PrintProgress(curr, total int) { pct := int(float64(curr)/float64(total)) * 100 for i := 0; i < 100; i += 10 { if pct > i { fmt.Print(FILL_CHAR) } } } // StringPermutations takes a string and returns all permutations of it func StringPermutations(str string) []string { perms := stringPermHelper(str, 0) var wrk []string // Now de-dupe for i := range perms { var found bool for j := range wrk { if wrk[j] == perms[i] { found = true } } if !found { wrk = append(wrk, perms[i]) } } return wrk } func stringPermHelper(str string, i int) []string { ret := []string{str} if i != len(str) { r := []rune(str) for j := i; j < len(r); j++ { r[i], r[j] = r[j], r[i] ret = append(ret, stringPermHelper(string(r), i+1)...) r[i], r[j] = r[j], r[i] } } return ret } // IntPermutations takes a slice of ints and returns all permutations of it func IntPermutations(inp []int) [][]int { perms := intPermHelper(inp, 0) var wrk [][]int // Now de-dupe for i := range perms { var found bool for j := range wrk { if IntSlicesAreEqual(perms[i], wrk[j]) { found = true break } } if !found { wrk = append(wrk, perms[i]) } } return wrk } func intPermHelper(inp []int, i int) [][]int { ret := [][]int{inp} if i != len(inp) { r := make([]int, len(inp)) copy(r, inp) for j := i; j < len(r); j++ { r[i], r[j] = r[j], r[i] ret = append(ret, intPermHelper(r, i+1)...) r[i], r[j] = r[j], r[i] } } return ret } // IntSlicesAreEqual takes two int slices and returns if they are equal func IntSlicesAreEqual(s1 []int, s2 []int) bool { if len(s1) != len(s2) { return false } for k := range s1 { if s1[k] != s2[k] { return false } } return true } func StringSliceIndex(h []string, n string) int { for k, v := range h { if v == n { return k } } return -1 } // StringSliceContains takes a string slice and a string and return true // if the string is in the slice func StringSliceContains(h []string, n string) bool { for _, v := range h { if v == n { return true } } return false } // IntSliceContains takes an int slice and an int and return true // if the int is in the slice func IntSliceContains(h []int, n int) bool { for _, v := range h { if v == n { return true } } return false } // AppendString returns a slice of strings that are base+group[...] func AppendStrings(base string, group []string) []string { for k, v := range group { group[k] = base + v } return group } // UnionStringSlice returns a slice that combines list1 and list2 func UnionStringSlice(list1, list2 []string) []string { for k := range list1 { if !StringSliceContains(list2, list1[k]) { list2 = append(list2, list1[k]) } } return list2 } // IntersectStringSlice returns a slice that contains all elements that // both list1 and list2 contain func IntersectStringSlice(list1, list2 []string) []string { var ret []string for k := range list1 { if StringSliceContains(list2, list1[k]) { ret = append(ret, list1[k]) } } return ret } // Unique removes all duplicates func UniqueStringSlice(list []string) []string { var ret []string for k := 0; k < len(list); k++ { var dupe bool for j := k; j < len(list); j++ { if list[k] == list[j] { dupe = true break } } if !dupe { ret = append(ret, list[k]) } } return ret } // IsPrime takes a number and return true if that number is prime func IsPrime(value int) bool { for i := 2; i <= int(math.Floor(float64(value)/2)); i++ { if value%i == 0 { return false } } return value > 1 } func Min(v1, v2 int) int { if v1 < v2 { return v1 } return v2 } func Max(v1, v2 int) int { if v1 > v2 { return v1 } return v2 }