chore: save day18 #12
@ -24,8 +24,8 @@ func (r result) String() string { return fmt.Sprintf("%#v", r) }
 | 
			
		||||
 | 
			
		||||
func run(scan *bufio.Scanner) (*result, error) {
 | 
			
		||||
 | 
			
		||||
	var vecsPT1 []vector
 | 
			
		||||
	var vecsPT2 []vector
 | 
			
		||||
	var vecsPT1 []aoc.Vector
 | 
			
		||||
	var vecsPT2 []aoc.Vector
 | 
			
		||||
 | 
			
		||||
	for scan.Scan() {
 | 
			
		||||
		text := scan.Text()
 | 
			
		||||
@ -45,45 +45,7 @@ func run(scan *bufio.Scanner) (*result, error) {
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type vector struct {
 | 
			
		||||
	offset point
 | 
			
		||||
	scale  int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type point [2]int
 | 
			
		||||
 | 
			
		||||
func (p point) add(a point) point {
 | 
			
		||||
	return point{p[0] + a[0], p[1] + a[1]}
 | 
			
		||||
}
 | 
			
		||||
func (p point) scale(m int) point {
 | 
			
		||||
	return point{p[0] * m, p[1] * m}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// numPoints the number of the points inside an outline plus the number of points in the outline
 | 
			
		||||
func numPoints(outline []point, borderLength int) int {
 | 
			
		||||
	// shoelace - find the float area in a shape
 | 
			
		||||
	sum := 0
 | 
			
		||||
	for _, p := range pairwise(outline) {
 | 
			
		||||
		row1, col1 := p[0][0], p[0][1]
 | 
			
		||||
		row2, col2 := p[1][0], p[1][1]
 | 
			
		||||
 | 
			
		||||
		sum += row1*col2 - row2*col1
 | 
			
		||||
	}
 | 
			
		||||
	area := sum / 2
 | 
			
		||||
 | 
			
		||||
	// pick's theorem - find the number of points in a shape given its area
 | 
			
		||||
	return (aoc.ABS(area) - borderLength/2 + 1) + borderLength
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func pairwise[T any](arr []T) [][2]T {
 | 
			
		||||
	var pairs [][2]T
 | 
			
		||||
	for i := range arr[:len(arr)-1] {
 | 
			
		||||
		pairs = append(pairs, [2]T{arr[i], arr[i+1]})
 | 
			
		||||
	}
 | 
			
		||||
	return pairs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var OFFSET = map[string]point{
 | 
			
		||||
var OFFSET = map[string]aoc.Point{
 | 
			
		||||
	"R": {0, 1},
 | 
			
		||||
	"D": {1, 0},
 | 
			
		||||
	"L": {0, -1},
 | 
			
		||||
@ -91,39 +53,38 @@ var OFFSET = map[string]point{
 | 
			
		||||
}
 | 
			
		||||
var OFFSET_INDEXES = maps.Values(OFFSET)
 | 
			
		||||
 | 
			
		||||
func fromLine(text string) (vector, string) {
 | 
			
		||||
	v := vector{}
 | 
			
		||||
func fromLine(text string) (aoc.Vector, string) {
 | 
			
		||||
	v := aoc.Vector{}
 | 
			
		||||
	s, text, _ := strings.Cut(text, " ")
 | 
			
		||||
	v.offset = OFFSET[s]
 | 
			
		||||
	v.Offset = OFFSET[s]
 | 
			
		||||
 | 
			
		||||
	s, text, _ = strings.Cut(text, " ")
 | 
			
		||||
	v.scale = aoc.Atoi(s)
 | 
			
		||||
	v.Scale = aoc.Atoi(s)
 | 
			
		||||
 | 
			
		||||
	_, text, _ = strings.Cut(text, "(#")
 | 
			
		||||
	s, _, _ = strings.Cut(text, ")")
 | 
			
		||||
	return v, s
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
func fromColor(c string) vector {
 | 
			
		||||
func fromColor(c string) aoc.Vector {
 | 
			
		||||
	scale, _ := strconv.ParseInt(c[:5], 16, 64)
 | 
			
		||||
	offset := OFFSET_INDEXES[c[5]-'0']
 | 
			
		||||
 | 
			
		||||
	return vector{
 | 
			
		||||
		offset: offset,
 | 
			
		||||
		scale:  int(scale),
 | 
			
		||||
	return aoc.Vector{
 | 
			
		||||
		Offset: offset,
 | 
			
		||||
		Scale:  int(scale),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func findArea(vecs []vector) int {
 | 
			
		||||
	shoelace := []point{{0,0}}
 | 
			
		||||
func findArea(vecs []aoc.Vector) int {
 | 
			
		||||
	shoelace := []aoc.Point{{0,0}}
 | 
			
		||||
	borderLength := 0
 | 
			
		||||
 | 
			
		||||
	for _, vec := range vecs {
 | 
			
		||||
		scaled_offset := vec.offset.scale(vec.scale)
 | 
			
		||||
		shoelace = append(shoelace, shoelace[len(shoelace)-1].add(scaled_offset))
 | 
			
		||||
		borderLength += vec.scale
 | 
			
		||||
		shoelace = append(shoelace, shoelace[len(shoelace)-1].Add(vec.Point()))
 | 
			
		||||
		borderLength += vec.Scale
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return numPoints(shoelace, borderLength)
 | 
			
		||||
	return aoc.NumPoints(shoelace, borderLength)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										51
									
								
								grids.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								grids.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,51 @@
 | 
			
		||||
package aoc
 | 
			
		||||
 | 
			
		||||
type Vector struct {
 | 
			
		||||
	Offset Point
 | 
			
		||||
	Scale  int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (v Vector) Point() Point {
 | 
			
		||||
	return v.Offset.Scale(v.Scale)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Point [2]int
 | 
			
		||||
 | 
			
		||||
func (p Point) Add(a Point) Point {
 | 
			
		||||
	return Point{p[0] + a[0], p[1] + a[1]}
 | 
			
		||||
}
 | 
			
		||||
func (p Point) Scale(m int) Point {
 | 
			
		||||
	return Point{p[0] * m, p[1] * m}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Transpose[T any](matrix [][]T) [][]T {
 | 
			
		||||
	rows, cols := len(matrix), len(matrix[0])
 | 
			
		||||
 | 
			
		||||
	m := make([][]T, cols)
 | 
			
		||||
	for i := range m {
 | 
			
		||||
		m[i] = make([]T, rows)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i := 0; i < cols; i++ {
 | 
			
		||||
		for j := 0; j < rows; j++ {
 | 
			
		||||
			m[i][j] = matrix[j][i]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return m
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NumPoints the number of the points inside an outline plus the number of points in the outline
 | 
			
		||||
func NumPoints(outline []Point, borderLength int) int {
 | 
			
		||||
	// shoelace - find the float area in a shape
 | 
			
		||||
	sum := 0
 | 
			
		||||
	for _, p := range Pairwise(outline) {
 | 
			
		||||
		row1, col1 := p[0][0], p[0][1]
 | 
			
		||||
		row2, col2 := p[1][0], p[1][1]
 | 
			
		||||
 | 
			
		||||
		sum += row1*col2 - row2*col1
 | 
			
		||||
	}
 | 
			
		||||
	area := sum / 2
 | 
			
		||||
 | 
			
		||||
	// pick's theorem - find the number of points in a shape given its area
 | 
			
		||||
	return (ABS(area) - borderLength/2 + 1) + borderLength
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										57
									
								
								itertools.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								itertools.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,57 @@
 | 
			
		||||
package aoc
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"strconv"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Atoi(s string) int {
 | 
			
		||||
	i, _ := strconv.Atoi(s)
 | 
			
		||||
	return i
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Repeat[T any](s T, i int) []T {
 | 
			
		||||
	lis := make([]T, i)
 | 
			
		||||
	for i := range lis {
 | 
			
		||||
		lis[i] = s
 | 
			
		||||
	}
 | 
			
		||||
	return lis
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
	}
 | 
			
		||||
	return u
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Pairwise iterates over a list pairing i, i+1
 | 
			
		||||
func Pairwise[T any](arr []T) [][2]T {
 | 
			
		||||
	var pairs [][2]T
 | 
			
		||||
	for i := range arr[:len(arr)-1] {
 | 
			
		||||
		pairs = append(pairs, [2]T{arr[i], arr[i+1]})
 | 
			
		||||
	}
 | 
			
		||||
	return pairs
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										101
									
								
								lists.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								lists.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,101 @@
 | 
			
		||||
package aoc
 | 
			
		||||
 | 
			
		||||
import "fmt"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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]
 | 
			
		||||
}
 | 
			
		||||
func (l *List[T]) GetN(pos ...int) []*Node[T] {
 | 
			
		||||
	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
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										90
									
								
								math.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								math.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,90 @@
 | 
			
		||||
package aoc
 | 
			
		||||
 | 
			
		||||
import "cmp"
 | 
			
		||||
 | 
			
		||||
type integer interface {
 | 
			
		||||
	int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// type float interface {
 | 
			
		||||
// 	complex64 | complex128 | float32 | float64
 | 
			
		||||
// }
 | 
			
		||||
// type number interface{ integer | float }
 | 
			
		||||
 | 
			
		||||
// greatest common divisor (GCD) via Euclidean algorithm
 | 
			
		||||
func GCD[T integer](a, b T) T {
 | 
			
		||||
	for b != 0 {
 | 
			
		||||
		t := b
 | 
			
		||||
		b = a % b
 | 
			
		||||
		a = t
 | 
			
		||||
	}
 | 
			
		||||
	return a
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// find Least Common Multiple (LCM) via GCD
 | 
			
		||||
func LCM[T integer](integers ...T) T {
 | 
			
		||||
	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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Sum[T integer](arr ...T) T {
 | 
			
		||||
	var acc T
 | 
			
		||||
	for _, a := range arr {
 | 
			
		||||
		acc += a
 | 
			
		||||
	}
 | 
			
		||||
	return acc
 | 
			
		||||
}
 | 
			
		||||
func SumFunc[T any, U integer](fn func(T) U, input ...T) U {
 | 
			
		||||
	return Sum(SliceMap(fn, input...)...)
 | 
			
		||||
}
 | 
			
		||||
func SumIFunc[T any, U integer](fn func(int, T) U, input ...T) U {
 | 
			
		||||
	return Sum(SliceIMap(fn, input...)...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Power2(n int) int {
 | 
			
		||||
	if n == 0 {
 | 
			
		||||
		return 1
 | 
			
		||||
	}
 | 
			
		||||
	p := 2
 | 
			
		||||
	for ; n > 1; n-- {
 | 
			
		||||
		p *= 2
 | 
			
		||||
	}
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ABS(i int) int {
 | 
			
		||||
	if i < 0 {
 | 
			
		||||
		return -i
 | 
			
		||||
	}
 | 
			
		||||
	return i
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										47
									
								
								runner.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								runner.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
			
		||||
package aoc
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Runner[R any, F func(*bufio.Scanner) (R, error)](run F) (R, error) {
 | 
			
		||||
	if len(os.Args) != 2 {
 | 
			
		||||
		Log("Usage:", filepath.Base(os.Args[0]), "FILE")
 | 
			
		||||
		os.Exit(22)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	input, err := os.Open(os.Args[1])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		Log(err)
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	scan := bufio.NewScanner(input)
 | 
			
		||||
	return run(scan)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func MustResult[T any](result T, err error) {
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("ERR", err)
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Log("result", result)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func ReadStringToInts(fields []string) []int {
 | 
			
		||||
	return SliceMap(Atoi, fields...)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										290
									
								
								tools.go
									
									
									
									
									
								
							
							
						
						
									
										290
									
								
								tools.go
									
									
									
									
									
								
							@ -1,290 +0,0 @@
 | 
			
		||||
package aoc
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"cmp"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Runner[R any, F func(*bufio.Scanner) (R, error)](run F) (R, error) {
 | 
			
		||||
	if len(os.Args) != 2 {
 | 
			
		||||
		Log("Usage:", filepath.Base(os.Args[0]), "FILE")
 | 
			
		||||
		os.Exit(22)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	input, err := os.Open(os.Args[1])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		Log(err)
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	scan := bufio.NewScanner(input)
 | 
			
		||||
	return run(scan)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func MustResult[T any](result T, err error) {
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("ERR", err)
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Log("result", result)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type integer interface {
 | 
			
		||||
	int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// type float interface {
 | 
			
		||||
// 	complex64 | complex128 | float32 | float64
 | 
			
		||||
// }
 | 
			
		||||
// type number interface{ integer | float }
 | 
			
		||||
 | 
			
		||||
// greatest common divisor (GCD) via Euclidean algorithm
 | 
			
		||||
func GCD[T integer](a, b T) T {
 | 
			
		||||
	for b != 0 {
 | 
			
		||||
		t := b
 | 
			
		||||
		b = a % b
 | 
			
		||||
		a = t
 | 
			
		||||
	}
 | 
			
		||||
	return a
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// find Least Common Multiple (LCM) via GCD
 | 
			
		||||
func LCM[T integer](integers ...T) T {
 | 
			
		||||
	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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ReadStringToInts(fields []string) []int {
 | 
			
		||||
	return SliceMap(Atoi, fields...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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]
 | 
			
		||||
}
 | 
			
		||||
func (l *List[T]) GetN(pos ...int) []*Node[T] {
 | 
			
		||||
	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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Repeat[T any](s T, i int) []T {
 | 
			
		||||
	lis := make([]T, i)
 | 
			
		||||
	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
 | 
			
		||||
}
 | 
			
		||||
func SumFunc[T any, U integer](fn func(T) U, input ...T) U {
 | 
			
		||||
	return Sum(SliceMap(fn, input...)...)
 | 
			
		||||
}
 | 
			
		||||
func SumIFunc[T any, U integer](fn func(int, T) U, input ...T) U {
 | 
			
		||||
	return Sum(SliceIMap(fn, input...)...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Power2(n int) int {
 | 
			
		||||
	if n == 0 {
 | 
			
		||||
		return 1
 | 
			
		||||
	}
 | 
			
		||||
	p := 2
 | 
			
		||||
	for ; n > 1; n-- {
 | 
			
		||||
		p *= 2
 | 
			
		||||
	}
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ABS(i int) int {
 | 
			
		||||
	if i < 0 {
 | 
			
		||||
		return -i
 | 
			
		||||
	}
 | 
			
		||||
	return i
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Transpose[T any](matrix [][]T) [][]T {
 | 
			
		||||
	rows, cols := len(matrix), len(matrix[0])
 | 
			
		||||
 | 
			
		||||
	m := make([][]T, cols)
 | 
			
		||||
	for i := range m {
 | 
			
		||||
		m[i] = make([]T, rows)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i := 0; i < cols; i++ {
 | 
			
		||||
		for j := 0; j < rows; j++ {
 | 
			
		||||
			m[i][j] = matrix[j][i]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return m
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
	}
 | 
			
		||||
	return u
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user