396 lines
6.4 KiB
Go
396 lines
6.4 KiB
Go
|
package aoc
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
"cmp"
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"sort"
|
||
|
"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 uinteger interface {
|
||
|
uint | uint8 | uint16 | uint32 | uint64
|
||
|
}
|
||
|
type sinteger interface {
|
||
|
int | int8 | int16 | int32 | int64
|
||
|
}
|
||
|
type integer interface {
|
||
|
sinteger | uinteger
|
||
|
}
|
||
|
|
||
|
// 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
|
||
|
}
|
||
|
|
||
|
type PQElem[T any, I integer] struct {
|
||
|
Value T
|
||
|
Priority I
|
||
|
}
|
||
|
type PQList[T any, I integer] []PQElem[T, I]
|
||
|
|
||
|
func (pq PQList[T, I]) Len() int {
|
||
|
return len(pq)
|
||
|
}
|
||
|
func (pq PQList[T, I]) Less(i int, j int) bool {
|
||
|
return pq[i].Priority < pq[j].Priority
|
||
|
}
|
||
|
func (pq PQList[T, I]) Swap(i int, j int) {
|
||
|
pq[i], pq[j] = pq[j], pq[i]
|
||
|
}
|
||
|
|
||
|
var _ sort.Interface = (*PQList[rune, int])(nil)
|
||
|
|
||
|
type PriorityQueue[T any, I integer] struct {
|
||
|
elem PQList[T, I]
|
||
|
}
|
||
|
|
||
|
func (pq *PriorityQueue[T, I]) Enqueue(elem T, priority I) {
|
||
|
pq.elem = append(pq.elem, PQElem[T, I]{elem, priority})
|
||
|
sort.Sort(pq.elem)
|
||
|
}
|
||
|
func (pq *PriorityQueue[T, I]) IsEmpty() bool {
|
||
|
return len(pq.elem) == 0
|
||
|
}
|
||
|
func (pq *PriorityQueue[T, I]) Dequeue() (T, bool) {
|
||
|
var elem T
|
||
|
if pq.IsEmpty() {
|
||
|
return elem, false
|
||
|
}
|
||
|
|
||
|
elem, pq.elem = pq.elem[0].Value, pq.elem[1:]
|
||
|
return elem, true
|
||
|
}
|
||
|
|
||
|
type Vertex[V comparable, I integer] struct {
|
||
|
to V
|
||
|
score I
|
||
|
}
|
||
|
type graph[V comparable, I uinteger] struct {
|
||
|
adj map[V][]Vertex[V, I]
|
||
|
}
|
||
|
|
||
|
func Graph[V comparable, I uinteger](size int) *graph[V, I] {
|
||
|
return &graph[V, I]{
|
||
|
adj: make(map[V][]Vertex[V, I], size),
|
||
|
}
|
||
|
}
|
||
|
func (g *graph[V, I]) AddEdge(u, v V, w I) {
|
||
|
g.adj[u] = append(g.adj[u], Vertex[V, I]{to: v, score: w})
|
||
|
g.adj[v] = append(g.adj[v], Vertex[V, I]{to: u, score: w})
|
||
|
}
|
||
|
func (g *graph[V, I]) Dijkstra(m interface{Get()}, src V) map[V]I {
|
||
|
pq := PriorityQueue[V, I]{}
|
||
|
dist := make(map[V]I, len(g.adj))
|
||
|
visited := make(map[V]bool, len(g.adj))
|
||
|
var INF I
|
||
|
INF = ^INF
|
||
|
|
||
|
pq.Enqueue(src, 0)
|
||
|
dist[src] = 0
|
||
|
|
||
|
for !pq.IsEmpty() {
|
||
|
u, _ := pq.Dequeue()
|
||
|
|
||
|
if _, ok := visited[u]; ok {
|
||
|
continue
|
||
|
}
|
||
|
visited[u] = true
|
||
|
|
||
|
for _, v := range g.adj[u] {
|
||
|
_, ok := visited[v.to]
|
||
|
var du, dv I
|
||
|
if d, inf := dist[u]; !inf {
|
||
|
du = INF
|
||
|
} else {
|
||
|
du = d
|
||
|
}
|
||
|
if d, inf := dist[v.to]; !inf {
|
||
|
dv = INF
|
||
|
} else {
|
||
|
dv = d
|
||
|
}
|
||
|
|
||
|
if !ok && du+v.score < dv {
|
||
|
dist[v.to] = du + v.score
|
||
|
pq.Enqueue(v.to, du+v.score)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return dist
|
||
|
}
|