Day 15 commit, not done
This commit is contained in:
203
2018/day15/day15-overthink
Normal file
203
2018/day15/day15-overthink
Normal file
@@ -0,0 +1,203 @@
|
||||
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...)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user