package aoc import ( "math" ) type GrowUpCoordByteMap struct { Field map[Coordinate]byte Height int Width int // The Top-Left-most X/Y // (Low X, High Y) TLX, TLY int // The Bottom-Right-most X/Y // (High X, Low Y) BRX, BRY int // Options for the 'String' method StringEmptyIsSpace bool StringEmptyByte byte } func NewGrowUpCoordByteMap() *GrowUpCoordByteMap { return &GrowUpCoordByteMap{ Field: make(map[Coordinate]byte), TLX: math.MaxInt, TLY: math.MinInt, BRX: math.MinInt, BRY: math.MaxInt, StringEmptyByte: ' ', } } func (m *GrowUpCoordByteMap) FindAll(b ...byte) []Coordinate { var ret []Coordinate for y := m.TLY; y >= m.BRY; y-- { for x := m.TLX; x <= m.BRX; x++ { c := Coordinate{X: x, Y: y} for i := range b { if m.Get(c) == b[i] { ret = append(ret, c) } } } } return ret } func (m *GrowUpCoordByteMap) Get(pos Coordinate) byte { if v, ok := m.Field[pos]; ok { return v } return 0 } func (m *GrowUpCoordByteMap) Opt(pos Coordinate, def byte) byte { if v, ok := m.Field[pos]; ok { return v } return def } func (m *GrowUpCoordByteMap) Put(pos Coordinate, val byte) { m.Field[pos] = val m.Measure() } func (m *GrowUpCoordByteMap) PutBytes(bytes [][]byte, at Coordinate) { for y := range bytes { for x := range bytes[y] { m.Put(Coordinate{X: at.X + x, Y: at.Y + y}, bytes[y][x]) } } m.Measure() } func (m *GrowUpCoordByteMap) Delete(pos Coordinate) { delete(m.Field, pos) m.Measure() } func (m *GrowUpCoordByteMap) Measure() { m.TLX, m.TLY = math.MaxInt, math.MinInt m.BRX, m.BRY = math.MinInt, math.MaxInt for c := range m.Field { if c.X < m.TLX { m.TLX = c.X } if c.Y < m.BRY { m.BRY = c.Y } if c.X > m.BRX { m.BRX = c.X } if c.Y > m.TLY { m.TLY = c.Y } m.Width = m.BRX - m.TLX + 1 m.Height = m.TLY - m.BRY + 1 } } func (m GrowUpCoordByteMap) String() string { var ret string for y := m.TLY; y >= m.BRY; y-- { for x := m.TLX; x <= m.BRX; x++ { if m.StringEmptyIsSpace { ret = ret + string(m.Opt(Coordinate{X: x, Y: y}, m.StringEmptyByte)) } else { ret = ret + string(m.Field[Coordinate{X: x, Y: y}]) } } if y > m.BRY { ret = ret + "\n" } } return ret }