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…
Reference in New Issue
Block a user