204 lines
3.9 KiB
Plaintext
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...)
|
||
|
}
|
||
|
}
|