advent-of-code/tools.go

291 lines
4.4 KiB
Go
Raw Normal View History

2023-12-08 16:24:48 -07:00
package aoc
import (
"bufio"
2023-12-16 12:43:17 -07:00
"cmp"
2023-12-08 16:24:48 -07:00
"fmt"
"os"
2023-12-09 10:52:49 -07:00
"path/filepath"
2023-12-09 14:57:02 -07:00
"strconv"
2023-12-08 20:33:36 -07:00
"strings"
2023-12-08 16:24:48 -07:00
)
func Runner[R any, F func(*bufio.Scanner) (R, error)](run F) (R, error) {
if len(os.Args) != 2 {
2023-12-09 10:52:49 -07:00
Log("Usage:", filepath.Base(os.Args[0]), "FILE")
2023-12-08 20:33:36 -07:00
os.Exit(22)
2023-12-08 16:24:48 -07:00
}
input, err := os.Open(os.Args[1])
if err != nil {
2023-12-08 20:33:36 -07:00
Log(err)
os.Exit(1)
2023-12-08 16:24:48 -07:00
}
scan := bufio.NewScanner(input)
return run(scan)
}
2023-12-09 10:52:49 -07:00
func MustResult[T any](result T, err error) {
if err != nil {
fmt.Println("ERR", err)
os.Exit(1)
}
Log("result", result)
}
2023-12-08 20:33:36 -07:00
func Log(v ...any) { fmt.Fprintln(os.Stderr, v...) }
func Logf(format string, v ...any) {
if !strings.HasSuffix(format, "\n") {
format += "\n"
}
fmt.Fprintf(os.Stderr, format, v...)
}
2023-12-08 19:09:00 -07:00
func Reverse[T any](arr []T) []T {
for i := 0; i < len(arr)/2; i++ {
arr[i], arr[len(arr)-i-1] = arr[len(arr)-i-1], arr[i]
}
return arr
}
2023-12-08 20:33:36 -07:00
type integer interface {
int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64
}
2023-12-09 14:57:02 -07:00
2023-12-08 20:33:36 -07:00
// type float interface {
// complex64 | complex128 | float32 | float64
// }
// type number interface{ integer | float }
2023-12-08 19:09:00 -07:00
2023-12-08 16:24:48 -07:00
// greatest common divisor (GCD) via Euclidean algorithm
2023-12-08 20:33:36 -07:00
func GCD[T integer](a, b T) T {
2023-12-08 16:24:48 -07:00
for b != 0 {
t := b
b = a % b
a = t
}
return a
}
// find Least Common Multiple (LCM) via GCD
2023-12-08 20:33:36 -07:00
func LCM[T integer](integers ...T) T {
2023-12-08 16:24:48 -07:00
if len(integers) == 0 {
return 0
}
if len(integers) == 1 {
return integers[0]
}
a, b := integers[0], integers[1]
result := a * b / GCD(a, b)
for _, c := range integers[2:] {
result = LCM(result, c)
}
return result
}
2023-12-09 14:57:02 -07:00
func ReadStringToInts(fields []string) []int {
2023-12-16 12:43:17 -07:00
return SliceMap(Atoi, fields...)
2023-12-09 14:57:02 -07:00
}
2023-12-12 13:44:28 -07:00
type Node[T any] struct {
value T
pos int
left *Node[T]
}
func (n *Node[T]) add(a *Node[T]) *Node[T] {
if a == nil {
return n
}
if n == nil {
return a
}
n.left = a
return a
}
func (n *Node[T]) Value() (value T, ok bool) {
if n == nil {
return
}
return n.value, true
}
func (n *Node[T]) Position() int {
if n == nil {
return -1
}
return n.pos
}
func (n *Node[T]) SetPosition(i int) {
if n == nil {
return
}
n.pos = i
}
func (n *Node[T]) Next() *Node[T] {
if n == nil {
return nil
}
return n.left
}
func (n *Node[T]) String() string {
if n == nil {
return "EOL"
}
return fmt.Sprintf("node %v", n.value)
}
type List[T any] struct {
head *Node[T]
n *Node[T]
p map[int]*Node[T]
}
func NewList[T any](a *Node[T]) *List[T] {
lis := &List[T]{
head: a,
n: a,
p: make(map[int]*Node[T]),
}
lis.add(a)
return lis
}
func (l *List[T]) Add(value T, pos int) {
a := &Node[T]{value: value, pos: pos}
l.add(a)
}
func (l *List[T]) add(a *Node[T]) {
if l.head == nil {
l.head = a
}
if a == nil {
return
}
l.n = l.n.add(a)
l.p[a.pos] = a
}
func (l *List[T]) Get(pos int) *Node[T] {
return l.p[pos]
}
2023-12-13 08:32:37 -07:00
func (l *List[T]) GetN(pos ...int) []*Node[T] {
2023-12-12 13:44:28 -07:00
lis := make([]*Node[T], len(pos))
for i, p := range pos {
lis[i] = l.p[p]
}
return lis
}
func (l *List[T]) Head() *Node[T] {
return l.head
2023-12-13 08:32:37 -07:00
}
func SliceMap[T, U any](fn func(T) U, in ...T) []U {
lis := make([]U, len(in))
for i := range lis {
lis[i] = fn(in[i])
}
return lis
}
func SliceIMap[T, U any](fn func(int, T) U, in ...T) []U {
lis := make([]U, len(in))
for i := range lis {
lis[i] = fn(i, in[i])
}
return lis
}
func Atoi(s string) int {
i, _ := strconv.Atoi(s)
return i
}
2023-12-16 12:43:17 -07:00
func Repeat[T any](s T, i int) []T {
lis := make([]T, i)
2023-12-13 08:32:37 -07:00
for i := range lis {
lis[i] = s
}
return lis
}
func Sum[T integer](arr ...T) T {
var acc T
for _, a := range arr {
acc += a
}
return acc
}
2023-12-16 12:43:17 -07:00
func SumFunc[T any, U integer](fn func(T) U, input ...T) U {
2023-12-13 08:32:37 -07:00
return Sum(SliceMap(fn, input...)...)
}
2023-12-16 12:43:17 -07:00
func SumIFunc[T any, U integer](fn func(int, T) U, input ...T) U {
2023-12-13 08:32:37 -07:00
return Sum(SliceIMap(fn, input...)...)
}
func Power2(n int) int {
2023-12-16 12:43:17 -07:00
if n == 0 {
return 1
}
2023-12-13 08:32:37 -07:00
p := 2
for ; n > 1; n-- {
p *= 2
}
return p
}
func ABS(i int) int {
if i < 0 {
return -i
}
return i
}
2023-12-13 17:02:16 -07:00
func Transpose[T any](matrix [][]T) [][]T {
rows, cols := len(matrix), len(matrix[0])
2023-12-16 12:43:17 -07:00
2023-12-13 17:02:16 -07:00
m := make([][]T, cols)
for i := range m {
m[i] = make([]T, rows)
}
2023-12-16 12:43:17 -07:00
2023-12-13 17:02:16 -07:00
for i := 0; i < cols; i++ {
for j := 0; j < rows; j++ {
m[i][j] = matrix[j][i]
}
}
return m
2023-12-15 09:57:44 -07:00
}
func Reduce[T, U any](fn func(int, T, U) U, u U, list ...T) U {
for i, t := range list {
u = fn(i, t, u)
2023-12-16 12:43:17 -07:00
}
2023-12-15 09:57:44 -07:00
return u
2023-12-16 12:43:17 -07:00
}
func Max[T cmp.Ordered](a T, v ...T) T {
for _, b := range v {
if b > a {
a = b
}
}
return a
}
func Min[T cmp.Ordered](a T, v ...T) T {
for _, b := range v {
if b < a {
a = b
}
}
return a
}