adventofcode/2018/day15/day15-overthink

204 lines
3.9 KiB
Plaintext

package overthink
import (
"bufio"
"fmt"
"math"
"os"
"sort"
"time"
)
const (
UseEmoji = false
MaxInt = int(^uint(0) >> 1)
ClearScreen = "\033[H\033[2J"
DIR_N = -1i
DIR_E = 1
DIR_S = 1i
DIR_W = -1
)
var width int
var input []byte
var elves []*complex64
var goblins []*complex64
var allChars []*complex64
var charMap map[complex64]*Character
func main() {
stdinToByteSlice()
setupBattle()
part1()
}
func part1() {
//for {
sortCharacters()
printBattleField()
for _, c := range allChars {
charMap[*c].tick()
}
time.Sleep(time.Millisecond * 250)
printBattleField()
//}
fmt.Println("")
}
func sortCharacters() {
sort.Sort(ByPos(allChars))
sort.Sort(ByPos(elves))
sort.Sort(ByPos(goblins))
}
type Character struct {
tp byte
pos complex64
power int
health int
}
func (c *Character) tick() {
// If we're already in range of a target, don't look for a new one
var alreadyAtTarget bool
var chosenTarget *complex64
lowestTargetHp := MaxInt
for _, v := range elves {
if c.isAdjacentTo(*v) {
if charMap[*v].health < lowestTargetHp {
chosenTarget = v
}
alreadyAtTarget = true
}
}
if alreadyAtTarget {
// Attack the target
charMap[*chosenTarget].health -= c.power
} else {
// Looking for a target
if c.tp == 'G' {
// First identify all possible targets (elves that have an open adjacent space)
for _, v := range elves {
}
} else {
// First identify all possible targets (goblins that have an open adjacent space)
for _, v := range goblins {
}
}
}
}
func (c *Character) isAdjacentTo(p complex64) bool {
return c.pos+DIR_N == p || c.pos+DIR_E == p ||
c.pos+DIR_S == p || c.pos+DIR_W == p
}
func (c *Character) hasOpenFlank() bool {
}
// Not sure if we'll use this...
func manhattanDistance(p1, p2 complex64) int {
x1, y1, x2, y2 := real(p1), imag(p1), real(p2), imag(p2)
return int(math.Abs(float64(x1)-float64(x2)) + math.Abs(float64(y1)-float64(y2)))
}
// We have to sort the characters on each tick by y,x position
// y is the imaginary part, x is the real part
type ByPos []*complex64
func (c ByPos) Len() int { return len(c) }
func (c ByPos) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c ByPos) Less(i, j int) bool {
return imag(*c[i]) < imag(*c[j]) ||
(imag(*c[i]) == imag(*c[j]) && real(*c[i]) < real(*c[j]))
}
// getByte pulls a byte from the given position in the input
func getByte(pos complex64) byte {
return input[int(real(pos))+int(imag(pos))*width]
}
func setByte(pos complex64, b byte) {
input[int(real(pos))+int(imag(pos))*width] = b
}
func getPosFromInt(i int) complex64 {
return complex(float32(i%width), float32(i/width))
}
func printBattleField() {
fmt.Print(ClearScreen)
for i := 0; i < len(input); i++ {
pos := getPosFromInt(i)
var bt byte
if c, ok := charMap[pos]; ok {
if UseEmoji {
switch c.tp {
case 'G':
if UseEmoji {
fmt.Print("👺")
}
case 'E':
fmt.Print("😃")
}
} else {
fmt.Print(string(c.tp))
}
bt = c.tp
} else {
bt = getByte(pos)
if UseEmoji {
if bt == '#' {
fmt.Print("🏿")
} else {
fmt.Print(" ")
}
} else {
fmt.Print(string(bt))
}
}
if i%width == width-1 {
fmt.Println("")
}
}
}
func setupBattle() {
charMap = make(map[complex64]*Character)
for i := 0; i < len(input); i++ {
pos := complex(float32(i%width), float32(i/width))
bt := getByte(pos)
if bt == 'G' || bt == 'E' {
charMap[pos] = &Character{
tp: bt,
pos: pos,
power: 3,
health: 200,
}
setByte(pos, '.')
allChars = append(allChars, &charMap[pos].pos)
switch bt {
case 'G':
goblins = append(goblins, &charMap[pos].pos)
case 'E':
elves = append(elves, &charMap[pos].pos)
}
}
}
}
func stdinToByteSlice() {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
data := scanner.Bytes()
if width == 0 {
width = len(data)
}
input = append(input, data...)
}
}