package aoc import "fmt" type CoordByteMap struct { Field map[Coordinate]byte Height int Width int // The Top-Left-most X/Y TLX, TLY int // The Bottom-Right-most X/Y BRX, BRY int } func NewCoordByteMap() CoordByteMap { return CoordByteMap{ Field: make(map[Coordinate]byte), } } func StringSliceToCoordByteMap(input []string) CoordByteMap { ret := CoordByteMap{ Field: make(map[Coordinate]byte), Height: len(input), } for y := range input { for x := range input[y] { ret.Put(Coordinate{X: x, Y: y}, input[y][x]) } } return ret } func (m *CoordByteMap) Count(b byte) int { var ret int for y := m.TLY; y <= m.BRY; y++ { for x := m.TLX; x <= m.BRX; x++ { if m.Get(Coordinate{X: x, Y: y}) == b { ret++ } } } return ret } func (m *CoordByteMap) Get(pos Coordinate) byte { if v, ok := m.Field[pos]; ok { return v } return 0 } func (m *CoordByteMap) Opt(pos Coordinate, def byte) byte { if v, ok := m.Field[pos]; ok { return v } return def } func (m *CoordByteMap) Put(pos Coordinate, val byte) { if pos.X < m.TLX { m.TLX = pos.X } if pos.Y < m.TLY { m.TLY = pos.Y } if pos.X > m.BRX { m.BRX = pos.X } if pos.Y > m.BRY { m.BRY = pos.Y } m.Field[pos] = val if pos.X+1 > m.Width { m.Width = m.BRX - m.TLX + 1 } if pos.Y+1 > m.Height { m.Height = m.BRY - m.TLY + 1 } } func (m *CoordByteMap) GrowNorth(size int, val byte) { tlY := m.TLY - 1 for x := m.TLX; x <= m.BRX; x++ { m.Put(Coordinate{X: x, Y: tlY}, val) } } func (m *CoordByteMap) GrowEast(size int, val byte) { brX := m.BRX + 1 for y := m.TLY; y <= m.BRY; y++ { m.Put(Coordinate{X: brX, Y: y}, val) } } func (m *CoordByteMap) GrowSouth(size int, val byte) { tlY := m.BRY + 1 for x := m.TLX; x <= m.BRX; x++ { m.Put(Coordinate{X: x, Y: tlY}, val) } } func (m *CoordByteMap) GrowWest(size int, val byte) { brX := m.TLX - 1 for y := m.TLY; y <= m.BRY; y++ { m.Put(Coordinate{X: brX, Y: y}, val) } } // This grows the map in all directions func (m *CoordByteMap) Grow(size int, val byte) { m.GrowNorth(size, val) m.GrowEast(size, val) m.GrowSouth(size, val) m.GrowWest(size, val) } // Runs the passed function on every point in the map // returning a new bytemap func (m CoordByteMap) Map(l func(c Coordinate, in byte) byte) CoordByteMap { i := m for y := m.TLY; y <= m.BRY; y++ { for x := m.TLX; x <= m.BRX; x++ { c := Coordinate{X: x, Y: y} nV := l(c, m.Get(c)) fmt.Println("MAP: Putting", string(nV), "at", c) i.Put(c, l(c, m.Get(c))) } } return i } func (m CoordByteMap) String() string { var ret string for y := m.TLY; y <= m.BRY; y++ { for x := m.TLX; x <= m.BRX; x++ { ret = ret + string(m.Field[Coordinate{X: x, Y: y}]) } ret = ret + "\n" } return ret } // And the 3d Version type Coord3dByteMap struct { Field map[Coordinate3d]byte MinX, MaxX int MinY, MaxY int MinZ, MaxZ int } func StringSliceToCoord3dByteMap(input []string) Coord3dByteMap { ret := Coord3dByteMap{ Field: make(map[Coordinate3d]byte), } for y := range input { for x := range input[y] { ret.Put(Coordinate3d{X: x, Y: y, Z: 0}, input[y][x]) } } return ret } func (m *Coord3dByteMap) Copy() Coord3dByteMap { ret := Coord3dByteMap{ Field: make(map[Coordinate3d]byte), MinX: m.MinX, MaxX: m.MaxX, MinY: m.MinY, MaxY: m.MaxY, MinZ: m.MinZ, MaxZ: m.MaxZ, } for z := m.MinZ; z <= m.MaxZ; z++ { for y := m.MinY; y <= m.MaxY; y++ { for x := m.MinX; x <= m.MaxX; x++ { c := Coordinate3d{X: x, Y: y, Z: z} ret.Field[c] = m.Get(c) } } } return ret } func (m *Coord3dByteMap) Get(pos Coordinate3d) byte { if _, ok := m.Field[pos]; !ok { return 0 } return m.Field[pos] } func (m *Coord3dByteMap) Opt(pos Coordinate3d, def byte) byte { if v, ok := m.Field[pos]; ok { return v } return def } func (m *Coord3dByteMap) Put(pos Coordinate3d, val byte) { m.Field[pos] = val if pos.X < m.MinX { m.MinX = pos.X } if pos.X > m.MaxX { m.MaxX = pos.X } if pos.Y < m.MinY { m.MinY = pos.X } if pos.Y > m.MaxY { m.MaxY = pos.Y } if pos.Z < m.MinZ { m.MinZ = pos.Z } if pos.Z > m.MaxZ { m.MaxZ = pos.Z } } func (m *Coord3dByteMap) CountNeighbors(pos Coordinate3d, val byte) int { var res int for z := pos.Z - 1; z <= pos.Z+1; z++ { for y := pos.Y - 1; y <= pos.Y+1; y++ { for x := pos.X - 1; x <= pos.X+1; x++ { if m.Get(Coordinate3d{X: x, Y: y, Z: z}) == val { res++ } } } } return res } func (m Coord3dByteMap) Count(val byte) int { var ret int for z := m.MinZ; z <= m.MaxZ; z++ { for y := m.MinY; y <= m.MaxY; y++ { for x := m.MinX; x <= m.MaxX; x++ { if m.Get(Coordinate3d{X: x, Y: y, Z: z}) == val { ret++ } } } } return ret } func (m Coord3dByteMap) String() string { var ret string for z := m.MinZ; z <= m.MaxZ; z++ { for y := m.MinY; y <= m.MaxY; y++ { for x := m.MinX; x <= m.MaxX; x++ { ret = ret + string(m.Field[Coordinate3d{X: x, Y: y, Z: z}]) } ret = ret + "\n" } ret = ret + "\n\n" } return ret }