Compare commits
5 Commits
ec912023fd
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 019510f0b6 | |||
| 8b102c2c61 | |||
| ce1b496761 | |||
| 2d5190c044 | |||
| b73303c965 |
@@ -8,7 +8,7 @@ using Golang.
|
||||
General pattern to run the code is using **stdin** to pass the data file:
|
||||
|
||||
```sh
|
||||
go run ./day1 < ./day1/input.txt
|
||||
go run ./day1 < ./day1/example.txt
|
||||
```
|
||||
|
||||
Majority of solutions support `-debug` flag.
|
||||
|
||||
11
day5/example.txt
Normal file
11
day5/example.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
3-5
|
||||
10-14
|
||||
16-20
|
||||
12-18
|
||||
|
||||
1
|
||||
5
|
||||
8
|
||||
11
|
||||
17
|
||||
32
|
||||
123
day5/main.go
Normal file
123
day5/main.go
Normal file
@@ -0,0 +1,123 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"cmp"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
f := os.Stdin
|
||||
if len(os.Args) > 1 && os.Args[1] != "-" {
|
||||
var err error
|
||||
f, err = os.Open(os.Args[1])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
}
|
||||
|
||||
fresh, available, err := readIngredients(f)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
var availableFresh int
|
||||
for _, id := range available {
|
||||
for _, r := range fresh {
|
||||
if r.Includes(id) {
|
||||
availableFresh++
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var freshIds int
|
||||
compactFresh := compactedRanges(fresh)
|
||||
for _, r := range compactFresh {
|
||||
freshIds += r.to - r.from + 1
|
||||
}
|
||||
|
||||
fmt.Println("available fresh:", availableFresh)
|
||||
fmt.Println("total fresh:", freshIds)
|
||||
}
|
||||
|
||||
type idsRange struct {
|
||||
from, to int
|
||||
}
|
||||
|
||||
func (r idsRange) Includes(n int) bool {
|
||||
return r.from <= n && n <= r.to
|
||||
}
|
||||
|
||||
func readIngredients(r io.Reader) (fresh []idsRange, available []int, err error) {
|
||||
seenEmptyLine := false
|
||||
sc := bufio.NewScanner(r)
|
||||
for sc.Scan() {
|
||||
if sc.Text() == "" {
|
||||
seenEmptyLine = true
|
||||
continue
|
||||
}
|
||||
if seenEmptyLine {
|
||||
id, err := strconv.ParseUint(sc.Text(), 10, 0)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
available = append(available, int(id))
|
||||
} else {
|
||||
r, err := parseRange(sc.Text())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
fresh = append(fresh, r)
|
||||
}
|
||||
}
|
||||
return fresh, available, nil
|
||||
}
|
||||
|
||||
func parseRange(s string) (idsRange, error) {
|
||||
before, after, ok := strings.Cut(s, "-")
|
||||
if !ok {
|
||||
return idsRange{}, fmt.Errorf("range %q: missing hyphen", s)
|
||||
}
|
||||
from, err := strconv.ParseUint(before, 10, 0)
|
||||
if err != nil {
|
||||
return idsRange{}, fmt.Errorf("range from: %w", err)
|
||||
}
|
||||
to, err := strconv.ParseUint(after, 10, 0)
|
||||
if err != nil {
|
||||
return idsRange{}, fmt.Errorf("range to: %w", err)
|
||||
}
|
||||
return idsRange{
|
||||
from: int(from),
|
||||
to: int(to),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func compactedRanges(ranges []idsRange) []idsRange {
|
||||
ranges = slices.Clone(ranges)
|
||||
|
||||
slices.SortFunc(ranges, func(a, b idsRange) int {
|
||||
if x := cmp.Compare(a.from, b.from); x != 0 {
|
||||
return x
|
||||
}
|
||||
return cmp.Compare(a.to, b.to)
|
||||
})
|
||||
|
||||
i := 0
|
||||
for j := 1; j < len(ranges); j++ {
|
||||
if !ranges[i].Includes(ranges[j].from) {
|
||||
i++
|
||||
ranges[i] = ranges[j]
|
||||
continue
|
||||
}
|
||||
ranges[i].to = max(ranges[i].to, ranges[j].to)
|
||||
}
|
||||
return ranges[:i+1]
|
||||
}
|
||||
68
day5/main_test.go
Normal file
68
day5/main_test.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_compactedRanges(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string // description of this test case
|
||||
ranges []idsRange
|
||||
want []idsRange
|
||||
}{
|
||||
{
|
||||
name: "single",
|
||||
ranges: []idsRange{
|
||||
{0, 10},
|
||||
},
|
||||
want: []idsRange{
|
||||
{0, 10},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "identical",
|
||||
ranges: []idsRange{
|
||||
{0, 10},
|
||||
{0, 10},
|
||||
{0, 10},
|
||||
{20, 30},
|
||||
{20, 30},
|
||||
},
|
||||
want: []idsRange{
|
||||
{0, 10},
|
||||
{20, 30},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "simple",
|
||||
ranges: []idsRange{
|
||||
{0, 10},
|
||||
{2, 11},
|
||||
{20, 30},
|
||||
},
|
||||
want: []idsRange{
|
||||
{0, 11},
|
||||
{20, 30},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "swallows",
|
||||
ranges: []idsRange{
|
||||
{0, 10},
|
||||
{2, 8},
|
||||
{20, 30},
|
||||
},
|
||||
want: []idsRange{
|
||||
{0, 10},
|
||||
{20, 30},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert.Equal(t, tt.want, compactedRanges(tt.ranges))
|
||||
})
|
||||
}
|
||||
}
|
||||
4
day6/example.txt
Normal file
4
day6/example.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
123 328 51 64
|
||||
45 64 387 23
|
||||
6 98 215 314
|
||||
* + * +
|
||||
217
day6/main.go
Normal file
217
day6/main.go
Normal file
@@ -0,0 +1,217 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"iter"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
f := os.Stdin
|
||||
if len(os.Args) > 1 && os.Args[1] != "-" {
|
||||
var err error
|
||||
f, err = os.Open(os.Args[1])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
}
|
||||
|
||||
lines, err := readLines(f)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
problems1, err := parseProblemsPart1(lines)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
problems2, err := parseProblemsPart2(lines)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
var result1, result2 int
|
||||
for _, p := range problems1 {
|
||||
result1 += p.Solve()
|
||||
}
|
||||
for _, p := range problems2 {
|
||||
result2 += p.Solve()
|
||||
}
|
||||
fmt.Println("part one:", result1)
|
||||
fmt.Println("part two:", result2)
|
||||
}
|
||||
|
||||
type Action int
|
||||
|
||||
const (
|
||||
ActionAdd Action = iota
|
||||
ActionMultiply
|
||||
)
|
||||
|
||||
type problem struct {
|
||||
Values []int
|
||||
Action
|
||||
}
|
||||
|
||||
func (p problem) Solve() int {
|
||||
if len(p.Values) == 0 {
|
||||
return 0
|
||||
}
|
||||
answer := p.Values[0]
|
||||
for _, v := range p.Values[1:] {
|
||||
switch p.Action {
|
||||
case ActionAdd:
|
||||
answer += v
|
||||
case ActionMultiply:
|
||||
answer *= v
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported action %d", p.Action))
|
||||
}
|
||||
}
|
||||
return answer
|
||||
}
|
||||
|
||||
func readLines(r io.Reader) ([]string, error) {
|
||||
var lines []string
|
||||
sc := bufio.NewScanner(r)
|
||||
for sc.Scan() {
|
||||
lines = append(lines, sc.Text())
|
||||
}
|
||||
return lines, sc.Err()
|
||||
}
|
||||
|
||||
func parseFields(lines []string) [][]string {
|
||||
cutAll := func(lines []string, sep string) (before, after []string, ok bool) {
|
||||
var found bool
|
||||
var i int
|
||||
for _, line := range lines {
|
||||
j := strings.Index(line, sep)
|
||||
if j < 0 {
|
||||
j = len(line)
|
||||
} else {
|
||||
found = true
|
||||
}
|
||||
i = max(i, j)
|
||||
}
|
||||
if !found {
|
||||
return lines, nil, false
|
||||
}
|
||||
|
||||
before = make([]string, 0, len(lines))
|
||||
after = make([]string, 0, len(lines))
|
||||
for _, line := range lines {
|
||||
before = append(before, line[:min(i, len(line))])
|
||||
after = append(after, line[min(i+len(sep), len(line)):])
|
||||
}
|
||||
return before, after, true
|
||||
}
|
||||
|
||||
fields := make([][]string, len(lines))
|
||||
for {
|
||||
before, after, ok := cutAll(lines, " ")
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
for i, v := range before {
|
||||
fields[i] = append(fields[i], v)
|
||||
}
|
||||
lines = after
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
func parseProblemsPart1(lines []string) ([]problem, error) {
|
||||
if len(lines) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
var data [][]string
|
||||
for _, line := range lines {
|
||||
data = append(data, strings.Fields(line))
|
||||
}
|
||||
|
||||
problems := make([]problem, len(data[0]))
|
||||
for i, row := range data {
|
||||
if len(row) != len(problems) {
|
||||
return nil, fmt.Errorf("line %d: unexpected number of fields", i+2)
|
||||
}
|
||||
|
||||
last := i == len(data)-1
|
||||
for j, v := range row {
|
||||
p := &problems[j]
|
||||
if last {
|
||||
switch v {
|
||||
case "+":
|
||||
p.Action = ActionAdd
|
||||
case "*":
|
||||
p.Action = ActionMultiply
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected action %q", v)
|
||||
}
|
||||
} else {
|
||||
n, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.Values = append(p.Values, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
return problems, nil
|
||||
}
|
||||
|
||||
func parseProblemsPart2(lines []string) ([]problem, error) {
|
||||
fields := parseFields(lines)
|
||||
var problems []problem
|
||||
|
||||
for col := range columnsSeq(fields) {
|
||||
var p problem
|
||||
switch s := strings.TrimSpace(col[len(col)-1]); s {
|
||||
case "+":
|
||||
p.Action = ActionAdd
|
||||
case "*":
|
||||
p.Action = ActionMultiply
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected action %q", s)
|
||||
}
|
||||
|
||||
var colBytes [][]byte
|
||||
for _, v := range col[:len(col)-1] {
|
||||
colBytes = append(colBytes, []byte(v))
|
||||
}
|
||||
for v := range columnsSeq(colBytes) {
|
||||
s := string(bytes.TrimSpace(v))
|
||||
n, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.Values = append(p.Values, n)
|
||||
}
|
||||
|
||||
problems = append(problems, p)
|
||||
}
|
||||
return problems, nil
|
||||
}
|
||||
|
||||
func columnsSeq[T any](data [][]T) iter.Seq[[]T] {
|
||||
return func(yield func([]T) bool) {
|
||||
if len(data) < 1 {
|
||||
return
|
||||
}
|
||||
for x := range len(data[0]) {
|
||||
var col []T
|
||||
for y := range data {
|
||||
col = append(col, data[y][x])
|
||||
}
|
||||
if !yield(col) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
16
day7/example.txt
Normal file
16
day7/example.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
.......S.......
|
||||
...............
|
||||
.......^.......
|
||||
...............
|
||||
......^.^......
|
||||
...............
|
||||
.....^.^.^.....
|
||||
...............
|
||||
....^.^...^....
|
||||
...............
|
||||
...^.^...^.^...
|
||||
...............
|
||||
..^...^.....^..
|
||||
...............
|
||||
.^.^.^.^.^...^.
|
||||
...............
|
||||
145
day7/main.go
Normal file
145
day7/main.go
Normal file
@@ -0,0 +1,145 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"slices"
|
||||
)
|
||||
|
||||
func main() {
|
||||
debug := flag.Bool("debug", false, "Debug.")
|
||||
flag.Parse()
|
||||
|
||||
f := os.Stdin
|
||||
if flag.NArg() > 0 && flag.Arg(0) != "-" {
|
||||
var err error
|
||||
f, err = os.Open(flag.Arg(0))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
}
|
||||
|
||||
diagram, err := readDiagram(f)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
splits := diagram.Propagate()
|
||||
var timelines int
|
||||
for _, row := range slices.Backward(diagram) {
|
||||
for _, c := range row {
|
||||
if c.Marker != BeamMarker {
|
||||
continue
|
||||
}
|
||||
timelines += c.WaysToReach
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if *debug {
|
||||
for _, row := range diagram {
|
||||
for _, c := range row {
|
||||
if c.Marker == BeamMarker {
|
||||
if c.WaysToReach < 10 {
|
||||
fmt.Print(c.WaysToReach)
|
||||
} else {
|
||||
b := 'A' + c.WaysToReach - 10
|
||||
if b > 'Z' {
|
||||
b = int(c.Marker)
|
||||
}
|
||||
fmt.Printf("%c", b)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("%c", c.Marker)
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("beam split", splits, "times into", timelines, "timelines")
|
||||
}
|
||||
|
||||
type Marker byte
|
||||
|
||||
const (
|
||||
BeamEmitterMarker Marker = 'S'
|
||||
BeamMarker Marker = '|'
|
||||
SplitterMarker Marker = '^'
|
||||
EmptyMarker Marker = '.'
|
||||
)
|
||||
|
||||
type Cell struct {
|
||||
Marker Marker
|
||||
WaysToReach int
|
||||
}
|
||||
|
||||
type diagram [][]Cell
|
||||
|
||||
func (d diagram) Propagate() (splits int) {
|
||||
splitoff := func(x, y, dx int) {
|
||||
x1 := x + dx
|
||||
if x1 < 0 || x1 >= len(d[y]) {
|
||||
return // out of range
|
||||
}
|
||||
switch d[y][x1].Marker {
|
||||
case EmptyMarker:
|
||||
d[y][x1] = Cell{
|
||||
Marker: BeamMarker,
|
||||
WaysToReach: d[y-1][x].WaysToReach,
|
||||
}
|
||||
case BeamMarker:
|
||||
d[y][x1].WaysToReach += d[y-1][x].WaysToReach
|
||||
}
|
||||
}
|
||||
|
||||
propagateCell := func(x, y int) {
|
||||
switch d[y-1][x].Marker {
|
||||
case BeamEmitterMarker:
|
||||
d[y-1][x].WaysToReach = 1
|
||||
case BeamMarker:
|
||||
default:
|
||||
return
|
||||
}
|
||||
// we have a beam above
|
||||
|
||||
switch d[y][x].Marker {
|
||||
case EmptyMarker:
|
||||
d[y][x] = Cell{
|
||||
Marker: BeamMarker,
|
||||
WaysToReach: d[y-1][x].WaysToReach,
|
||||
}
|
||||
case BeamMarker:
|
||||
d[y][x].WaysToReach += d[y-1][x].WaysToReach
|
||||
case SplitterMarker:
|
||||
splitoff(x, y, -1)
|
||||
splitoff(x, y, +1)
|
||||
splits++
|
||||
}
|
||||
}
|
||||
|
||||
for y := 1; y < len(d); y++ {
|
||||
for x := range d[y] {
|
||||
propagateCell(x, y)
|
||||
}
|
||||
}
|
||||
return splits
|
||||
}
|
||||
|
||||
func readDiagram(r io.Reader) (diagram, error) {
|
||||
var diagram diagram
|
||||
sc := bufio.NewScanner(r)
|
||||
for sc.Scan() {
|
||||
cells := make([]Cell, 0, len(sc.Bytes()))
|
||||
for _, b := range sc.Bytes() {
|
||||
cells = append(cells, Cell{Marker: Marker(b)})
|
||||
}
|
||||
diagram = append(diagram, cells)
|
||||
}
|
||||
return diagram, sc.Err()
|
||||
}
|
||||
20
day8/example.txt
Normal file
20
day8/example.txt
Normal file
@@ -0,0 +1,20 @@
|
||||
162,817,812
|
||||
57,618,57
|
||||
906,360,560
|
||||
592,479,940
|
||||
352,342,300
|
||||
466,668,158
|
||||
542,29,236
|
||||
431,825,988
|
||||
739,650,466
|
||||
52,470,668
|
||||
216,146,977
|
||||
819,987,18
|
||||
117,168,530
|
||||
805,96,715
|
||||
346,949,466
|
||||
970,615,88
|
||||
941,993,340
|
||||
862,61,35
|
||||
984,92,344
|
||||
425,690,689
|
||||
187
day8/main.go
Normal file
187
day8/main.go
Normal file
@@ -0,0 +1,187 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"maps"
|
||||
"math"
|
||||
"os"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
connections := flag.Int("connect", -1, "Number of connections to perform (-1 unlimited).")
|
||||
debug := flag.Bool("debug", false, "Debug.")
|
||||
flag.Parse()
|
||||
|
||||
f := os.Stdin
|
||||
if flag.NArg() > 0 && flag.Arg(0) != "-" {
|
||||
var err error
|
||||
f, err = os.Open(flag.Arg(0))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
}
|
||||
|
||||
positions, err := readPositions(f)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
circuit := make([]int, len(positions))
|
||||
for i := range positions {
|
||||
circuit[i] = i
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
distances := computeDistances(positions)
|
||||
var last connection
|
||||
fmt.Println("distances computed in", time.Since(start))
|
||||
|
||||
start = time.Now()
|
||||
for i := 0; ; i++ {
|
||||
if *connections >= 0 && i >= *connections {
|
||||
break
|
||||
}
|
||||
c, ok := distances.FindMin()
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
bCircuit := circuit[c.B]
|
||||
for i := range circuit {
|
||||
if circuit[i] == bCircuit {
|
||||
circuit[i] = circuit[c.A]
|
||||
}
|
||||
}
|
||||
if *debug {
|
||||
fmt.Println("connect", positions[c.A], "and", positions[c.B])
|
||||
}
|
||||
if allEqual(circuit) {
|
||||
last = c
|
||||
break
|
||||
}
|
||||
delete(distances, c)
|
||||
}
|
||||
fmt.Println("connections computed in", time.Since(start))
|
||||
|
||||
countsMap := make(map[int]int)
|
||||
for _, c := range circuit {
|
||||
countsMap[c]++
|
||||
}
|
||||
counts := slices.Sorted(maps.Values(countsMap))
|
||||
// if *debug {
|
||||
// fmt.Println("counts:", counts)
|
||||
// }
|
||||
|
||||
ans := 1
|
||||
for _, c := range counts[max(0, len(counts)-3):] {
|
||||
ans *= c
|
||||
}
|
||||
fmt.Println("three largest mult:", ans)
|
||||
fmt.Println("last connection X mult:", positions[last.A].X*positions[last.B].X)
|
||||
}
|
||||
|
||||
type position struct {
|
||||
X, Y, Z int
|
||||
}
|
||||
|
||||
func (p position) String() string {
|
||||
return fmt.Sprintf("%d,%d,%d", p.X, p.Y, p.Z)
|
||||
}
|
||||
|
||||
func (p position) DistanceTo(p1 position) float64 {
|
||||
compX := float64((p.X - p1.X) * (p.X - p1.X))
|
||||
compY := float64((p.Y - p1.Y) * (p.Y - p1.Y))
|
||||
compZ := float64((p.Z - p1.Z) * (p.Z - p1.Z))
|
||||
return math.Sqrt(compX + compY + compZ)
|
||||
}
|
||||
|
||||
func readPositions(r io.Reader) ([]position, error) {
|
||||
var positions []position
|
||||
sc := bufio.NewScanner(r)
|
||||
for sc.Scan() {
|
||||
fields := strings.Split(sc.Text(), ",")
|
||||
if len(fields) != 3 {
|
||||
return nil, fmt.Errorf("position %q: unexpected number of fields", sc.Text())
|
||||
}
|
||||
x, err := strconv.Atoi(fields[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("position %q: x: %w", sc.Text(), err)
|
||||
}
|
||||
y, err := strconv.Atoi(fields[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("position %q: y: %w", sc.Text(), err)
|
||||
}
|
||||
z, err := strconv.Atoi(fields[2])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("position %q: z: %w", sc.Text(), err)
|
||||
}
|
||||
positions = append(positions, position{
|
||||
X: x,
|
||||
Y: y,
|
||||
Z: z,
|
||||
})
|
||||
}
|
||||
return positions, sc.Err()
|
||||
}
|
||||
|
||||
type connection struct {
|
||||
A, B int
|
||||
}
|
||||
|
||||
func (c connection) Reverse() connection {
|
||||
return connection{c.B, c.A}
|
||||
}
|
||||
|
||||
type distances map[connection]float64
|
||||
|
||||
func (d distances) Get(aIndex, bIndex int) float64 {
|
||||
c := connection{aIndex, bIndex}
|
||||
if dist, ok := d[c]; ok {
|
||||
return dist
|
||||
}
|
||||
return d[c.Reverse()]
|
||||
}
|
||||
|
||||
func (d distances) Set(aIndex, bIndex int, dist float64) {
|
||||
d[connection{aIndex, bIndex}] = dist
|
||||
}
|
||||
|
||||
func (d distances) FindMin() (c connection, ok bool) {
|
||||
for pair, dist := range d {
|
||||
if !ok || dist < d[c] {
|
||||
c = pair
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
func computeDistances(positions []position) distances {
|
||||
table := make(distances)
|
||||
for i, p := range positions {
|
||||
for j := i + 1; j < len(positions); j++ {
|
||||
dist := p.DistanceTo(positions[j])
|
||||
table.Set(i, j, dist)
|
||||
}
|
||||
}
|
||||
return table
|
||||
}
|
||||
|
||||
func allEqual(s []int) bool {
|
||||
if len(s) < 1 {
|
||||
return true
|
||||
}
|
||||
for _, v := range s[1:] {
|
||||
if v != s[0] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user