2018 Day 15 Completed!
This commit is contained in:
153
2018/day15/cave.go
Normal file
153
2018/day15/cave.go
Normal file
@@ -0,0 +1,153 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Cave struct {
|
||||
Units SortableUnits
|
||||
Map Map
|
||||
}
|
||||
|
||||
const (
|
||||
KindSpace = 1 << iota
|
||||
KindElf
|
||||
KindGoblin
|
||||
KindWall
|
||||
KindHighlight
|
||||
)
|
||||
|
||||
var KindRunes = map[int]rune{
|
||||
KindSpace: '.',
|
||||
KindElf: 'E',
|
||||
KindGoblin: 'G',
|
||||
KindWall: '#',
|
||||
KindHighlight: '@',
|
||||
}
|
||||
|
||||
var RuneKinds = map[rune]int{
|
||||
'.': KindSpace,
|
||||
'E': KindElf,
|
||||
'G': KindGoblin,
|
||||
'#': KindWall,
|
||||
}
|
||||
|
||||
func IsUnit(bit int) bool {
|
||||
return (KindElf|KindGoblin)&bit != 0
|
||||
}
|
||||
|
||||
func NewCave(input []string, elfPower int) *Cave {
|
||||
c := &Cave{}
|
||||
c.ParseMap(input, elfPower)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Cave) ParseMap(input []string, elfPower int) {
|
||||
m := make(Map)
|
||||
|
||||
for y, row := range input {
|
||||
for x, col := range row {
|
||||
kind, ok := RuneKinds[col]
|
||||
if !ok {
|
||||
kind = KindWall
|
||||
}
|
||||
tile := &Tile{Kind: kind}
|
||||
if IsUnit(kind) {
|
||||
c.Units = append(c.Units, NewUnit(tile, kind, elfPower))
|
||||
}
|
||||
m.SetTile(tile, x, y)
|
||||
}
|
||||
}
|
||||
c.Map = m
|
||||
}
|
||||
|
||||
func (c Cave) PrintMap(highlight *Tile) {
|
||||
for y := 0; y < len(c.Map); y++ {
|
||||
var units []string
|
||||
for x := 0; x < len(c.Map[y]); x++ {
|
||||
t := c.Map.Tile(x, y)
|
||||
if t == highlight {
|
||||
fmt.Print(string(KindRunes[KindHighlight]))
|
||||
} else {
|
||||
fmt.Print(string(KindRunes[t.Kind]))
|
||||
}
|
||||
if t.Unit != nil {
|
||||
units = append(units, fmt.Sprintf("%c(%d)", KindRunes[t.Unit.Kind], t.Unit.Hitpoints))
|
||||
}
|
||||
}
|
||||
if len(units) > 0 {
|
||||
fmt.Print(" ", strings.Join(units, ", "))
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
func (c Cave) PrintDistance(t *Tile) {
|
||||
distances, _ := c.Map.FindWalkableTiles(t)
|
||||
for y := 0; y < len(c.Map); y++ {
|
||||
for x := 0; x < len(c.Map[y]); x++ {
|
||||
curT := c.Map.Tile(x, y)
|
||||
if d, ok := distances[curT]; ok && curT != t {
|
||||
fmt.Print(d)
|
||||
} else {
|
||||
fmt.Print(string(KindRunes[curT.Kind]))
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
func (c Cave) Status() (int, bool) {
|
||||
var elves, goblins bool
|
||||
var hp int
|
||||
|
||||
for _, u := range c.Units {
|
||||
if u.Hitpoints <= 0 {
|
||||
continue
|
||||
}
|
||||
if u.Kind == KindElf {
|
||||
elves = true
|
||||
} else {
|
||||
goblins = true
|
||||
}
|
||||
hp = hp + u.Hitpoints
|
||||
}
|
||||
return hp, elves && goblins
|
||||
}
|
||||
|
||||
func (c *Cave) RemoveTheDead() {
|
||||
var newUnits SortableUnits
|
||||
for _, unit := range c.Units {
|
||||
if unit.Hitpoints > 0 {
|
||||
newUnits = append(newUnits, unit)
|
||||
}
|
||||
}
|
||||
c.Units = newUnits
|
||||
}
|
||||
|
||||
func (c *Cave) RemoveUnit(u *Unit) {
|
||||
u.Tile.Kind = KindSpace
|
||||
u.Tile.Unit = nil
|
||||
u.Tile = nil
|
||||
}
|
||||
|
||||
// Tick returns false if combat ended during the round, and whether or not an elf has died this round
|
||||
func (c *Cave) Tick(stopOnElfDeath bool) (bool, bool) {
|
||||
c.RemoveTheDead()
|
||||
sort.Sort(c.Units)
|
||||
for _, unit := range c.Units {
|
||||
if unit.Hitpoints <= 0 {
|
||||
continue
|
||||
}
|
||||
if !unit.Targets(c) {
|
||||
return false, false
|
||||
}
|
||||
unit.Move(c)
|
||||
if unit.Attack(c) && stopOnElfDeath {
|
||||
return false, true
|
||||
}
|
||||
}
|
||||
return true, false
|
||||
}
|
||||
Reference in New Issue
Block a user