2018 Day 15 Completed!
This commit is contained in:
144
2018/day15/unit.go
Normal file
144
2018/day15/unit.go
Normal file
@@ -0,0 +1,144 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type Unit struct {
|
||||
Kind int
|
||||
Hitpoints int
|
||||
Power int
|
||||
Tile *Tile
|
||||
}
|
||||
|
||||
const (
|
||||
defaultHitpoints = 200
|
||||
defaultPower = 3
|
||||
)
|
||||
|
||||
type SortableUnits []*Unit
|
||||
|
||||
func (s SortableUnits) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
func (s SortableUnits) Less(i, j int) bool {
|
||||
if s[i].Tile.Y == s[j].Tile.Y {
|
||||
return s[i].Tile.X < s[j].Tile.X
|
||||
}
|
||||
return s[i].Tile.Y < s[j].Tile.Y
|
||||
}
|
||||
|
||||
func (s SortableUnits) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
func NewUnit(tile *Tile, kind, elfPower int) *Unit {
|
||||
unit := &Unit{
|
||||
Kind: kind,
|
||||
Hitpoints: defaultHitpoints,
|
||||
Power: defaultPower,
|
||||
Tile: tile,
|
||||
}
|
||||
tile.Unit = unit
|
||||
if unit.Kind == KindElf {
|
||||
unit.Power = elfPower
|
||||
}
|
||||
return unit
|
||||
}
|
||||
|
||||
func (u Unit) Targets(c *Cave) bool {
|
||||
for _, unit := range c.Units {
|
||||
if unit.Kind != u.Kind && unit.Hitpoints > 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// NextTile returns the next tile to move to and the target tile (or nil if no target found)
|
||||
func (u *Unit) NextTile(c *Cave) (*Tile, *Tile) {
|
||||
var targets SortableTiles
|
||||
closestTargetDistance := math.MaxInt32
|
||||
distances, path := c.Map.FindWalkableTiles(u.Tile)
|
||||
enemies := u.Enemies(c)
|
||||
for _, enemy := range enemies {
|
||||
for _, target := range enemy.Tile.WalkableNeighbors() {
|
||||
if distance, ok := distances[target]; ok && distance <= closestTargetDistance {
|
||||
if distance < closestTargetDistance {
|
||||
closestTargetDistance = distance
|
||||
targets = SortableTiles{}
|
||||
}
|
||||
targets = append(targets, target)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Sort(targets)
|
||||
if len(targets) > 0 {
|
||||
target := targets[0]
|
||||
current := target
|
||||
for {
|
||||
if path[current] == u.Tile {
|
||||
return current, target
|
||||
}
|
||||
current = path[current]
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Enemies returns enemy units sorted by map position in reading order
|
||||
func (u *Unit) Enemies(c *Cave) SortableUnits {
|
||||
var enemies SortableUnits
|
||||
for _, unit := range c.Units {
|
||||
if unit.Kind != u.Kind && unit.Hitpoints > 0 {
|
||||
enemies = append(enemies, unit)
|
||||
}
|
||||
}
|
||||
sort.Sort(enemies)
|
||||
return enemies
|
||||
}
|
||||
|
||||
func (u *Unit) EnemyNeighbor(c *Cave) *Unit {
|
||||
var target *Unit
|
||||
for _, offset := range offsets {
|
||||
if t := c.Map.Tile(u.Tile.X+offset.X, u.Tile.Y+offset.Y); t != nil && t.Unit != nil && t.Unit.Kind != u.Kind && t.Unit.Hitpoints > 0 {
|
||||
if target == nil || t.Unit.Hitpoints < target.Hitpoints {
|
||||
target = t.Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
return target
|
||||
}
|
||||
|
||||
func (u *Unit) Move(c *Cave) {
|
||||
if u.EnemyNeighbor(c) != nil {
|
||||
return
|
||||
}
|
||||
next, _ := u.NextTile(c)
|
||||
if next != nil {
|
||||
next.Unit = u
|
||||
next.Kind = u.Kind
|
||||
u.Tile.Kind = KindSpace
|
||||
u.Tile.Unit = nil
|
||||
u.Tile = next
|
||||
}
|
||||
}
|
||||
|
||||
func (u *Unit) Attack(c *Cave) bool {
|
||||
enemy := u.EnemyNeighbor(c)
|
||||
if enemy != nil {
|
||||
killed := enemy.Damage(c, u.Power)
|
||||
return killed && enemy.Kind == KindElf
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (u *Unit) Damage(c *Cave, damage int) bool {
|
||||
u.Hitpoints = u.Hitpoints - damage
|
||||
if u.Hitpoints <= 0 {
|
||||
c.RemoveUnit(u)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user