package aoc import ( "fmt" "math" "strings" ) type Coordinate struct { X, Y int } func NewCoordinate(x, y int) *Coordinate { return &Coordinate{x, y} } func (c Coordinate) Relative(t Coordinate) Coordinate { return Coordinate{X: c.X + t.X, Y: c.Y + t.Y} } func (c *Coordinate) MoveSouth() { c.Y++ } func (c *Coordinate) MoveNorth() { c.Y-- } func (c *Coordinate) MoveEast() { c.X++ } func (c *Coordinate) MoveWest() { c.X-- } func (c *Coordinate) MoveNE() { c.X++ c.Y-- } func (c *Coordinate) MoveSE() { c.X++ c.Y++ } func (c *Coordinate) MoveSW() { c.X-- c.Y++ } func (c *Coordinate) MoveNW() { c.X-- c.Y-- } func (c Coordinate) Sub(o Coordinate) Coordinate { return Coordinate{ X: c.X - o.X, Y: c.Y - o.Y, } } func (c Coordinate) Add(o Coordinate) Coordinate { return Coordinate{ X: c.X + o.X, Y: c.Y + o.Y, } } func (c Coordinate) Mul(by int) Coordinate { return Coordinate{ X: c.X * by, Y: c.Y * by, } } func (c Coordinate) North() Coordinate { return Coordinate{X: c.X, Y: c.Y - 1} } func (c Coordinate) East() Coordinate { return Coordinate{X: c.X + 1, Y: c.Y} } func (c Coordinate) South() Coordinate { return Coordinate{X: c.X, Y: c.Y + 1} } func (c Coordinate) West() Coordinate { return Coordinate{X: c.X - 1, Y: c.Y} } func (c *Coordinate) NW() Coordinate { return Coordinate{X: c.X - 1, Y: c.Y - 1} } func (c *Coordinate) NE() Coordinate { return Coordinate{X: c.X + 1, Y: c.Y - 1} } func (c *Coordinate) SW() Coordinate { return Coordinate{X: c.X - 1, Y: c.Y + 1} } func (c *Coordinate) SE() Coordinate { return Coordinate{X: c.X + 1, Y: c.Y + 1} } func (c *Coordinate) GetOrthNeighbors() []Coordinate { return []Coordinate{c.North(), c.East(), c.South(), c.West()} } func (c *Coordinate) GetAllNeighbors() []Coordinate { return []Coordinate{ c.North(), c.NE(), c.East(), c.SE(), c.South(), c.SW(), c.West(), c.NW(), } } func (c *Coordinate) GetNorthCoord() *Coordinate { return &Coordinate{ X: c.X, Y: c.Y - 1, } } func (c *Coordinate) GetEastCoord() *Coordinate { return &Coordinate{ X: c.X + 1, Y: c.Y, } } func (c *Coordinate) GetSouthCoord() *Coordinate { return &Coordinate{ X: c.X, Y: c.Y + 1, } } func (c *Coordinate) GetWestCoord() *Coordinate { return &Coordinate{ X: c.X - 1, Y: c.Y, } } func CoordinateFromString(str string) *Coordinate { c := Coordinate{} r := strings.NewReader(str) _, err := fmt.Fscanf(r, "[%d, %d]", &c.X, &c.Y) if err != nil { _, err = fmt.Fscanf(r, "%d,%d", &c.X, &c.Y) } if err != nil { panic(err) } return &c } func (c Coordinate) Angle(t Coordinate) float64 { ret := math.Atan2(float64(t.X-c.X), float64(c.Y-t.Y)) * 180 / math.Pi if ret < 0 { ret = ret + 360 } return ret } func (c Coordinate) String() string { return fmt.Sprintf("[%d, %d]", c.X, c.Y) } func (c Coordinate) Distance(t Coordinate) int { return ManhattanDistance(c.X, c.Y, t.X, t.Y) } func (c Coordinate) Equals(c2 Coordinate) bool { return c.X == c2.X && c.Y == c2.Y } func (c Coordinate) Adjacent(c2 Coordinate) bool { return c2.Equals(c.North()) || c2.Equals(c.NE()) || c2.Equals(c.East()) || c2.Equals(c.SE()) || c2.Equals(c.South()) || c2.Equals(c.SW()) || c2.Equals(c.West()) || c2.Equals(c.NW()) } func GetHighestY(list ...Coordinate) int { top := math.MinInt for i := range list { if list[i].Y > top { top = list[i].Y } } return top } func GetLowestY(list ...Coordinate) int { bot := math.MaxInt for i := range list { if list[i].Y < bot { bot = list[i].Y } } return bot } func GetLowestX(list ...Coordinate) int { bot := math.MaxInt for i := range list { if list[i].X < bot { bot = list[i].X } } return bot } func GetHighestX(list ...Coordinate) int { top := math.MinInt for i := range list { if list[i].X > top { top = list[i].X } } return top } func CoordListContains(needle Coordinate, haystack []Coordinate) bool { for _, chk := range haystack { if chk.Equals(needle) { return true } } return false }