No completion yet, blegh
This commit is contained in:
parent
0b74f11b8e
commit
c18758c166
5 changed files with 367 additions and 42 deletions
220
day16/dijsktra.go.disabled
Normal file
220
day16/dijsktra.go.disabled
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"slices"
|
||||||
|
|
||||||
|
"git.mstar.dev/mstar/aoc24/util"
|
||||||
|
"git.mstar.dev/mstar/goutils/sliceutils"
|
||||||
|
"github.com/RyanCarrier/dijkstra/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NodeType int
|
||||||
|
|
||||||
|
// A crossing is a path location with 3 or 4 other paths next to it
|
||||||
|
type Node struct {
|
||||||
|
At util.Vec2
|
||||||
|
Type NodeType
|
||||||
|
Dirs []util.Vec2
|
||||||
|
Index int
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
NodeInvalid NodeType = iota
|
||||||
|
NodeCrossing
|
||||||
|
NodeCorner
|
||||||
|
NodeDeadEnd
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
DirUp = util.Vec2{X: 0, Y: -1}
|
||||||
|
DirRight = util.Vec2{X: 1, Y: 0}
|
||||||
|
DirDown = util.Vec2{X: 0, Y: 1}
|
||||||
|
DirLeft = util.Vec2{X: -1, Y: 0}
|
||||||
|
)
|
||||||
|
|
||||||
|
var startDir = DirRight
|
||||||
|
|
||||||
|
// Get the size of the bord
|
||||||
|
func getSize(lines []string) util.Vec2 {
|
||||||
|
return util.Vec2{X: int64(len(lines[0])), Y: int64(len(lines))}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count the paths next to a given positon
|
||||||
|
func countPathsAt(lines [][]rune, at util.Vec2) []util.Vec2 {
|
||||||
|
center := lines[at.Y][at.X]
|
||||||
|
paths := []util.Vec2{}
|
||||||
|
if center == '#' {
|
||||||
|
return paths
|
||||||
|
}
|
||||||
|
if util.SafeGet(lines, at.Up()) != '#' {
|
||||||
|
paths = append(paths, DirUp)
|
||||||
|
}
|
||||||
|
if util.SafeGet(lines, at.Down()) != '#' {
|
||||||
|
paths = append(paths, DirDown)
|
||||||
|
}
|
||||||
|
if util.SafeGet(lines, at.Left()) != '#' {
|
||||||
|
paths = append(paths, DirLeft)
|
||||||
|
}
|
||||||
|
if util.SafeGet(lines, at.Right()) != '#' {
|
||||||
|
paths = append(paths, DirRight)
|
||||||
|
}
|
||||||
|
return paths
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCrossingsAndCornerPositions(lines [][]rune) []Node {
|
||||||
|
out := []Node{}
|
||||||
|
|
||||||
|
for iy, line := range lines {
|
||||||
|
for ix, char := range line {
|
||||||
|
if char == '#' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pos := util.Vec2{X: int64(ix), Y: int64(iy)}
|
||||||
|
dirs := countPathsAt(lines, pos)
|
||||||
|
// Crossings have 3 or more paths out
|
||||||
|
if len(dirs) >= 3 {
|
||||||
|
out = append(out, Node{pos, NodeCrossing, dirs, len(out)})
|
||||||
|
}
|
||||||
|
// Also include dead ends
|
||||||
|
if len(dirs) == 1 {
|
||||||
|
out = append(out, Node{pos, NodeDeadEnd, dirs, len(out)})
|
||||||
|
}
|
||||||
|
// Location is a corner if the paths are not opposite each other
|
||||||
|
if len(dirs) == 2 {
|
||||||
|
if !dirs[0].Mult(-1).Eq(dirs[1]) {
|
||||||
|
out = append(out, Node{pos, NodeCorner, dirs, len(out)})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNeighbourNodes(nodes []Node, index int) []int {
|
||||||
|
target := nodes[index]
|
||||||
|
|
||||||
|
potential := sliceutils.Filter(nodes, func(t Node) bool {
|
||||||
|
return t.Index != index && (t.At.X == target.At.X || t.At.Y == target.At.Y)
|
||||||
|
})
|
||||||
|
|
||||||
|
hits := []Node{}
|
||||||
|
for _, dir := range target.Dirs {
|
||||||
|
switch dir {
|
||||||
|
case DirUp:
|
||||||
|
hits = append(hits, slices.MinFunc(potential, func(a, b Node) int {
|
||||||
|
if a.At.X != target.At.X || a.At.Y > target.At.Y {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if b.At.X != target.At.X || b.At.Y > target.At.Y {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return util.AbsI(
|
||||||
|
int(target.At.Y)-int(a.At.Y),
|
||||||
|
) - util.AbsI(
|
||||||
|
int(target.At.Y)-int(b.At.Y),
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
case DirDown:
|
||||||
|
hits = append(hits, slices.MinFunc(potential, func(a, b Node) int {
|
||||||
|
if a.At.X != target.At.X || a.At.Y < target.At.Y {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if b.At.X != target.At.X || b.At.Y < target.At.Y {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return util.AbsI(
|
||||||
|
int(target.At.Y)-int(a.At.Y),
|
||||||
|
) - util.AbsI(
|
||||||
|
int(target.At.Y)-int(b.At.Y),
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
case DirLeft:
|
||||||
|
hits = append(hits, slices.MinFunc(potential, func(a, b Node) int {
|
||||||
|
if a.At.Y != target.At.Y || a.At.X > target.At.X {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if b.At.Y != target.At.Y || b.At.X > target.At.X {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return util.AbsI(
|
||||||
|
int(target.At.X)-int(a.At.X),
|
||||||
|
) - util.AbsI(
|
||||||
|
int(target.At.X)-int(b.At.X),
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
case DirRight:
|
||||||
|
hits = append(hits, slices.MinFunc(potential, func(a, b Node) int {
|
||||||
|
if a.At.Y != target.At.Y || a.At.X > target.At.X {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if b.At.Y != target.At.Y || b.At.X > target.At.X {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return util.AbsI(
|
||||||
|
int(target.At.X)-int(a.At.X),
|
||||||
|
) - util.AbsI(
|
||||||
|
int(target.At.X)-int(b.At.X),
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
default:
|
||||||
|
panic("Unknown dir")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sliceutils.Map(hits, func(t Node) int { return t.Index })
|
||||||
|
}
|
||||||
|
|
||||||
|
func addNodesToGraph(nodes []Node, graph *dijkstra.Graph) {
|
||||||
|
for i := range len(nodes) {
|
||||||
|
if err := graph.AddEmptyVertex(i); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, node := range nodes {
|
||||||
|
for _, n := range getNeighbourNodes(nodes, node.Index) {
|
||||||
|
if err := graph.AddArc(node.Index, n, node.At.Add(nodes[n].At.Mult(-1)).LenSquared()); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func findEnd(lines [][]rune) util.Vec2 {
|
||||||
|
for iy, line := range lines {
|
||||||
|
for ix, char := range line {
|
||||||
|
if char == 'E' {
|
||||||
|
return util.Vec2{X: int64(ix), Y: int64(iy)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return util.Vec2{X: -1, Y: -1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func findStart(lines [][]rune) util.Vec2 {
|
||||||
|
for iy, line := range lines {
|
||||||
|
for ix, char := range line {
|
||||||
|
if char == 'S' {
|
||||||
|
return util.Vec2{X: int64(ix), Y: int64(iy)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return util.Vec2{X: -1, Y: -1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
inputLines := util.FileContentToNonEmptyLines(util.LoadFileFromArgs())
|
||||||
|
// size := getSize(inputLines)
|
||||||
|
inputLineChars := sliceutils.Map(inputLines, func(t string) []rune { return []rune(t) })
|
||||||
|
nodes := getCrossingsAndCornerPositions(inputLineChars)
|
||||||
|
// fmt.Println(nodes)
|
||||||
|
// slices.MaxFunc(x S, cmp func(a E, b E) int)
|
||||||
|
graph := dijkstra.NewGraph()
|
||||||
|
addNodesToGraph(nodes, &graph)
|
||||||
|
startVec := findStart(inputLineChars)
|
||||||
|
endVec := findEnd(inputLineChars)
|
||||||
|
startI := slices.IndexFunc(nodes, func(e Node) bool { return e.At == startVec })
|
||||||
|
endI := slices.IndexFunc(nodes, func(e Node) bool { return e.At == endVec })
|
||||||
|
|
||||||
|
path, err := graph.Shortest(startI, endI)
|
||||||
|
fmt.Println(path, err)
|
||||||
|
}
|
164
day16/main.go
164
day16/main.go
|
@ -1,7 +1,10 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"git.mstar.dev/mstar/goutils/sliceutils"
|
"git.mstar.dev/mstar/goutils/sliceutils"
|
||||||
|
|
||||||
|
@ -12,7 +15,14 @@ import (
|
||||||
type Crossing struct {
|
type Crossing struct {
|
||||||
At util.Vec2
|
At util.Vec2
|
||||||
LowestScore int
|
LowestScore int
|
||||||
LowestFrom int // Index into list of crossings
|
LowestFrom util.Vec2 // Index into list of crossings
|
||||||
|
Neighbours []util.Vec2 // Directions where a path is
|
||||||
|
}
|
||||||
|
|
||||||
|
type Area map[int64]map[int64]*Crossing
|
||||||
|
|
||||||
|
type Wrapper struct {
|
||||||
|
A Area
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -30,52 +40,50 @@ func getSize(lines []string) util.Vec2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count the paths next to a given positon
|
// Count the paths next to a given positon
|
||||||
func countPathsAt(lines [][]rune, at util.Vec2) int {
|
func countPathsAt(lines [][]rune, at util.Vec2) []util.Vec2 {
|
||||||
center := lines[at.Y][at.X]
|
center := lines[at.Y][at.X]
|
||||||
|
paths := []util.Vec2{}
|
||||||
if center == '#' {
|
if center == '#' {
|
||||||
return 0
|
return paths
|
||||||
}
|
}
|
||||||
if center == 'E' {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
if center == 'S' {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
acc := 0
|
|
||||||
if util.SafeGet(lines, at.Up()) != '#' {
|
if util.SafeGet(lines, at.Up()) != '#' {
|
||||||
acc++
|
paths = append(paths, at.Up())
|
||||||
}
|
}
|
||||||
if util.SafeGet(lines, at.Down()) != '#' {
|
if util.SafeGet(lines, at.Down()) != '#' {
|
||||||
acc++
|
paths = append(paths, at.Down())
|
||||||
}
|
}
|
||||||
if util.SafeGet(lines, at.Left()) != '#' {
|
if util.SafeGet(lines, at.Left()) != '#' {
|
||||||
acc++
|
paths = append(paths, at.Left())
|
||||||
}
|
}
|
||||||
if util.SafeGet(lines, at.Right()) != '#' {
|
if util.SafeGet(lines, at.Right()) != '#' {
|
||||||
acc++
|
paths = append(paths, at.Right())
|
||||||
}
|
}
|
||||||
return acc
|
return paths
|
||||||
}
|
}
|
||||||
|
|
||||||
func findAllCrossings(lines [][]rune) []Crossing {
|
func linesToMap(lines [][]rune, size util.Vec2) Area {
|
||||||
out := []Crossing{}
|
area := Area{}
|
||||||
|
// Ensure area has full maps
|
||||||
|
for i := range size.Y {
|
||||||
|
area[i] = map[int64]*Crossing{}
|
||||||
|
}
|
||||||
for iy, line := range lines {
|
for iy, line := range lines {
|
||||||
for ix := range line {
|
for ix, char := range line {
|
||||||
vec := util.Vec2{X: int64(ix), Y: int64(iy)}
|
pos := util.Vec2{X: int64(ix), Y: int64(iy)}
|
||||||
pathCount := countPathsAt(lines, vec)
|
switch char {
|
||||||
if pathCount >= 3 {
|
case '.', 'E', 'S':
|
||||||
out = append(out, Crossing{At: vec, LowestScore: math.MaxInt, LowestFrom: -1})
|
dirs := countPathsAt(lines, pos)
|
||||||
|
area[int64(ix)][int64(iy)] = &Crossing{
|
||||||
|
At: pos,
|
||||||
|
LowestScore: math.MaxInt64,
|
||||||
|
LowestFrom: util.Vec2{X: -1, Y: -1},
|
||||||
|
Neighbours: dirs,
|
||||||
|
}
|
||||||
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return area
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert a list of crossings into x y map of pointers to those crossings
|
|
||||||
func crossingListToPointerMap(crossings []Crossing) map[int64]map[int64]*Crossing {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func findStart(lines [][]rune) util.Vec2 {
|
func findStart(lines [][]rune) util.Vec2 {
|
||||||
|
@ -102,28 +110,100 @@ func findEnd(lines [][]rune) util.Vec2 {
|
||||||
return util.Vec2{X: -1, Y: -1}
|
return util.Vec2{X: -1, Y: -1}
|
||||||
}
|
}
|
||||||
|
|
||||||
func walk(area [][]rune, from util.Vec2, dir util.Vec2) {
|
func walk(
|
||||||
|
area *Wrapper,
|
||||||
|
from util.Vec2,
|
||||||
|
dir util.Vec2,
|
||||||
|
score int,
|
||||||
|
) {
|
||||||
// Idea: walk forward from start until crossing or wall
|
// Idea: walk forward from start until crossing or wall
|
||||||
// At crossing, defer a walker for both sides (if not walled off) but prioritise forwards
|
// At crossing, defer a walker for both sides (if not walled off) but prioritise forwards
|
||||||
// Keep track of current score, one crossing = 1 point
|
|
||||||
// walking length doesn't matter because negligable compared to turn cost
|
|
||||||
// At crossing, check if own score is lower than current score
|
// At crossing, check if own score is lower than current score
|
||||||
// If it is, update score and set own origin
|
// If it is, update score and set own origin
|
||||||
|
// Else if crossing has a lower score than self, abort
|
||||||
|
|
||||||
// Special case:
|
// Special case:
|
||||||
// If at end, update end "crossing" following the earlier rules
|
// If at end, update end "crossing" following the earlier rules
|
||||||
|
|
||||||
|
// Walk forward in dir until no node found
|
||||||
|
type WalkTarget struct {
|
||||||
|
Pos, Dir util.Vec2
|
||||||
|
Score int
|
||||||
|
}
|
||||||
|
// targets := []WalkTarget{}
|
||||||
|
defer fmt.Println("Deffered done", from)
|
||||||
|
fmt.Println("Starting", from)
|
||||||
|
prev := from
|
||||||
|
for pos := from.Add(dir); area.A[pos.X][pos.Y] != nil; pos = pos.Add(dir) {
|
||||||
|
score++
|
||||||
|
node := area.A[pos.X][pos.Y]
|
||||||
|
if node.LowestScore <= score {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
node.LowestScore = score
|
||||||
|
node.LowestFrom = prev
|
||||||
|
// node.LowestFrom = pos.Add(dir.Mult(-1))
|
||||||
|
fmt.Println("Setting node", pos, score, node.LowestFrom)
|
||||||
|
// Get all directions that don't match current walking direction (and reverse)
|
||||||
|
filtered := sliceutils.Filter(node.Neighbours, func(t util.Vec2) bool {
|
||||||
|
return !t.Add(pos.Mult(-1)).Eq(dir) && !t.Add(pos.Mult(-1)).Eq(dir.Mult(-1))
|
||||||
|
})
|
||||||
|
// fmt.Println("Filtered neighbours of node", filtered)
|
||||||
|
for _, neighbour := range filtered {
|
||||||
|
fmt.Println("Adding target", neighbour)
|
||||||
|
// targets = append(targets, WalkTarget{
|
||||||
|
// neighbour, neighbour.Add(pos.Mult(-1)), score + 1001,
|
||||||
|
// })
|
||||||
|
defer walk(area, neighbour, neighbour.Add(pos.Mult(-1)), score+1001)
|
||||||
|
}
|
||||||
|
fmt.Println("Stepping", dir)
|
||||||
|
prev = pos
|
||||||
|
}
|
||||||
|
// fmt.Println("Hitting stored targets", from)
|
||||||
|
// for _, target := range targets {
|
||||||
|
// walk(area, target.Pos, target.Dir, target.Score)
|
||||||
|
// }
|
||||||
|
fmt.Println("Done, walking deferred", from)
|
||||||
|
}
|
||||||
|
|
||||||
|
func visualisePath(area Area, endPos, size util.Vec2, inputLineRunes [][]rune) string {
|
||||||
|
lineCopy := [][]rune{}
|
||||||
|
for _, line := range inputLineRunes {
|
||||||
|
lineCopy = append(lineCopy, slices.Clone(line))
|
||||||
|
}
|
||||||
|
for pos := endPos; pos.IsInBounds(size); pos = area[pos.X][pos.Y].LowestFrom {
|
||||||
|
fmt.Println("Path elem", pos)
|
||||||
|
lineCopy[pos.Y][pos.X] = 'x'
|
||||||
|
}
|
||||||
|
builder := strings.Builder{}
|
||||||
|
for _, line := range lineCopy {
|
||||||
|
for _, char := range line {
|
||||||
|
builder.WriteRune(char)
|
||||||
|
}
|
||||||
|
builder.WriteRune('\n')
|
||||||
|
}
|
||||||
|
return builder.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
inputLines := util.FileContentToNonEmptyLines(util.LoadFileFromArgs())
|
inputLines := util.FileContentToNonEmptyLines(util.LoadFileFromArgs())
|
||||||
// size := getSize(inputLines)
|
size := getSize(inputLines)
|
||||||
area := sliceutils.Map(inputLines, func(t string) []rune { return []rune(t) })
|
inputLineChars := sliceutils.Map(inputLines, func(t string) []rune { return []rune(t) })
|
||||||
crossings := findAllCrossings(area)
|
area := linesToMap(inputLineChars, size)
|
||||||
|
|
||||||
start := findStart(area)
|
start := findStart(inputLineChars)
|
||||||
// Start always has the lowest score
|
end := findEnd(inputLineChars)
|
||||||
crossings = append(crossings, Crossing{At: start, LowestScore: math.MinInt, LowestFrom: -1})
|
// Fill entire map
|
||||||
end := findEnd(area)
|
fmt.Println("Filling right")
|
||||||
// While end is just another "crossing"
|
wrapped := Wrapper{area}
|
||||||
crossings = append(crossings, Crossing{At: end, LowestScore: math.MaxInt, LowestFrom: -1})
|
walk(&wrapped, start, DirRight, 0)
|
||||||
|
fmt.Println("Filling up")
|
||||||
|
walk(&wrapped, start, DirUp, 1000)
|
||||||
|
fmt.Println("Filling down")
|
||||||
|
walk(&wrapped, start, DirDown, 1000)
|
||||||
|
fmt.Println("Filling left")
|
||||||
|
walk(&wrapped, start, DirLeft, 2000)
|
||||||
|
fmt.Printf("%#v\n", area[start.X][start.Y])
|
||||||
|
fmt.Printf("Task 1: %d\n", area[end.X][end.Y].LowestScore)
|
||||||
|
fmt.Println(visualisePath(area, end, size, inputLineChars))
|
||||||
}
|
}
|
||||||
|
|
5
go.mod
5
go.mod
|
@ -3,3 +3,8 @@ module git.mstar.dev/mstar/aoc24
|
||||||
go 1.23.3
|
go 1.23.3
|
||||||
|
|
||||||
require git.mstar.dev/mstar/goutils v1.5.4
|
require git.mstar.dev/mstar/goutils v1.5.4
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/RyanCarrier/dijkstra v1.4.0 // indirect
|
||||||
|
github.com/RyanCarrier/dijkstra/v2 v2.0.2 // indirect
|
||||||
|
)
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -1,2 +1,6 @@
|
||||||
git.mstar.dev/mstar/goutils v1.5.4 h1:l/4oQe/fBk9zyXplQkGXbmQndnm0aRdHuy4wgQfNrFo=
|
git.mstar.dev/mstar/goutils v1.5.4 h1:l/4oQe/fBk9zyXplQkGXbmQndnm0aRdHuy4wgQfNrFo=
|
||||||
git.mstar.dev/mstar/goutils v1.5.4/go.mod h1:juxY0eZEMnA95fedRp2LVXvUBgEjz66nE8SEdGKcxMA=
|
git.mstar.dev/mstar/goutils v1.5.4/go.mod h1:juxY0eZEMnA95fedRp2LVXvUBgEjz66nE8SEdGKcxMA=
|
||||||
|
github.com/RyanCarrier/dijkstra v1.4.0 h1:wkEVdTBLUiXjeBvDrSuagr72pOt36rUQoIfnnGxFYoQ=
|
||||||
|
github.com/RyanCarrier/dijkstra v1.4.0/go.mod h1:9egjhC7eVsfREX6NrYS+1wHzk9C/9v2Cz26/bqpjjTc=
|
||||||
|
github.com/RyanCarrier/dijkstra/v2 v2.0.2 h1:DIOg/a7XDR+KmlDkNSX9ggDY6sNLrG+EBGvZUjfgi+A=
|
||||||
|
github.com/RyanCarrier/dijkstra/v2 v2.0.2/go.mod h1:XwpYN7nC1LPwL3HkaavzB+VGaHRndSsZy/whsFy1AEI=
|
||||||
|
|
16
util/vec.go
16
util/vec.go
|
@ -31,3 +31,19 @@ func (v Vec2) Left() Vec2 {
|
||||||
func (v Vec2) Right() Vec2 {
|
func (v Vec2) Right() Vec2 {
|
||||||
return v.Add(Vec2{1, 0})
|
return v.Add(Vec2{1, 0})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v Vec2) RotateCounterClock() Vec2 {
|
||||||
|
return Vec2{v.Y, -v.X}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Vec2) RotateClock() Vec2 {
|
||||||
|
return Vec2{-v.Y, v.X}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Vec2) LenSquared() uint64 {
|
||||||
|
return uint64(v.X*v.X + v.Y*v.Y)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Vec2) IsInBounds(bounds Vec2) bool {
|
||||||
|
return v.X >= 0 && v.X < bounds.X && v.Y >= 0 && v.Y < bounds.Y
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue