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...) } }