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" CLEAR_LINE = "\033[1K" MAX_INT = int(^uint(0) >> 1) MIN_INT = -MAX_INT - 1 SHRUG = "¯\\_(ツ)_/¯" ) func CheckErr(err error) { if err != nil { panic(err) } } // Fact returns the factorial of the given int func Fact(x int) int { var ret int for i := 0; i <= x; i++ { ret += i } return ret } // Abs returns the absolute value of the given int func Abs(x int) int { if x < 0 { return x * -1 } return x } // 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 } // 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 } // 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()) } // Atof parses a float out of a string func Atof(i string) float64 { var ret float64 var err error if ret, err = strconv.ParseFloat(i, 64); err != nil { log.Fatalf("Invalid Atof: %s\n%v", i, err) } return ret } // Atoi goes through i and removes and characters that aren't numeric (or -) // Then runs it through the normal Atoi func Atoi(i string) int { var wrk string for _, bt := range i { if bt == '-' || (bt >= '0' && bt <= '9') { wrk = fmt.Sprintf("%s%s", wrk, string(bt)) } } var ret int var err error if ret, err = strconv.Atoi(wrk); err != nil { log.Fatalf("Invalid Atoi: %s\n%v", i, err) } return ret } // Itoa is basically redundant func Itoa(i int) string { return strconv.Itoa(i) } // Atoui is the same as Atoi, but with unsigned ints func Atoui(i string) uint64 { var ret uint64 var err error if ret, err = strconv.ParseUint(i, 10, 64); err != nil { log.Fatalf("Invalid Atoi: %s\n%v", i, err) } return ret } // 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) fmt.Print("[") for i := 0; i < 100; i += 10 { if pct > i { fmt.Print(FILL_CHAR) } else { fmt.Print(" ") } } fmt.Print("]") } func ClearProgress() { fmt.Print("\b\b\b\b\b\b\b\b\b\b\b\b") } // 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 SliceMin(sl []int) int { switch len(sl) { case 0: return MIN_INT case 1: return sl[0] case 2: return Min(sl[0], sl[1]) default: return Min(sl[0], sl[1], sl[2:]...) } } func Min(v1, v2 int, vrest ...int) int { min := v2 if v1 < v2 { min = v1 } for i := range vrest { if vrest[i] < min { min = vrest[i] } } return min } func Max(v1, v2 int, vrest ...int) int { max := v2 if v1 > v2 { max = v1 } for i := range vrest { if vrest[i] > max { max = vrest[i] } } return max } // Sum adds up all of the numbers from l to h func Sum(l, h int) int { var ret int for i := Min(l, h); i <= Max(l, h); i++ { ret = ret + i } return ret } func ManhattanDistance(x1, y1, x2, y2 int) int { return AbsInt(x1-x2) + AbsInt(y1-y2) } func PromptUser(text string, required bool) string { var resp string fmt.Print(text + ": ") scanner := bufio.NewScanner(os.Stdin) if scanner.Scan() { resp = scanner.Text() } if resp == "" && required { fmt.Println("Non-empty response is required") return PromptUser(text, required) } return strings.TrimSpace(resp) }