275 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			275 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 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
 | |
| }
 | |
| 
 | |
| // 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
 | |
| }
 | |
| 
 | |
| // 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
 | |
| }
 |