2018 Day 19 part 1 complete
This commit is contained in:
@@ -20,8 +20,8 @@ var charSlice []*complex64
|
||||
var turnCount int
|
||||
|
||||
const (
|
||||
ClearScreen = "\033[H\033[2J"
|
||||
MaxInt = int(^uint(0) >> 1)
|
||||
CLEAR_SCREEN = "\033[H\033[2J"
|
||||
MAX_INT = int(^uint(0) >> 1)
|
||||
|
||||
DIR_N = -1i
|
||||
DIR_E = 1
|
||||
@@ -38,6 +38,7 @@ func main() {
|
||||
|
||||
func part1() {
|
||||
for {
|
||||
// Sort the players on the field
|
||||
charSlice = charSlice[0:0]
|
||||
for i := 0; i < len(input); i++ {
|
||||
pos := getPosFromInt(i)
|
||||
@@ -47,8 +48,8 @@ func part1() {
|
||||
}
|
||||
}
|
||||
sort.Sort(ByPos(charSlice))
|
||||
fmt.Printf("= Turn %d =\n", turnCount)
|
||||
printBattlefield()
|
||||
|
||||
// Tick every player
|
||||
for _, v := range charSlice {
|
||||
if char, ok := characters[*v]; ok {
|
||||
if !char.tick() {
|
||||
@@ -56,11 +57,11 @@ func part1() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if false {
|
||||
if true {
|
||||
time.Sleep(time.Millisecond * 250)
|
||||
printBattlefield()
|
||||
fmt.Println()
|
||||
}
|
||||
printBattlefield()
|
||||
if checkBattleOver() {
|
||||
break
|
||||
}
|
||||
@@ -110,95 +111,63 @@ func (c *Character) hasEnemies() bool {
|
||||
}
|
||||
|
||||
func (c *Character) tick() bool {
|
||||
// If we're already in range of a target, don't look for a new one
|
||||
if tPos, err := c.easiestAdjacentTarget(); err == nil {
|
||||
c.attack(tPos)
|
||||
return c.hasEnemies()
|
||||
// Check if this character has any enemies on the field
|
||||
if !c.hasEnemies() {
|
||||
fmt.Println(c.string(), "is unopposed")
|
||||
return false
|
||||
}
|
||||
// If we have no open sides, we can't more
|
||||
if !c.hasOpenFlank() {
|
||||
fmt.Println(c.string(), "blocked in")
|
||||
return true
|
||||
}
|
||||
// Otherwise, find a target
|
||||
var opportunities []complex64
|
||||
for _, oppPos := range charSlice {
|
||||
if v, ok := characters[*oppPos]; ok {
|
||||
if v.tp != c.tp {
|
||||
opportunities = append(opportunities, *oppPos)
|
||||
}
|
||||
// Now move/attack
|
||||
if _, err := c.easiestAdjacentTarget(); err != nil {
|
||||
// Ok, figure out a move
|
||||
nxt, tgt := c.findMove()
|
||||
if nxt != nil {
|
||||
fmt.Println(c.string(), "is moving to", *nxt, "(", *tgt, ")")
|
||||
c.moveTo(*nxt)
|
||||
}
|
||||
}
|
||||
/*
|
||||
var opportunities []complex64
|
||||
for _, oppPos := range charSlice {
|
||||
if v, ok := characters[*oppPos]; ok {
|
||||
if v.tp != c.tp {
|
||||
fmt.Println(c.string(), "checking:", v.string())
|
||||
opportunities = append(opportunities, v.getOpenSides()...)
|
||||
}
|
||||
}
|
||||
}
|
||||
closestDistance := MaxInt
|
||||
var closestPos complex64
|
||||
for _, v := range opportunities {
|
||||
if distance(c.pos, v) < closestDistance {
|
||||
closestDistance = distance(c.pos, v)
|
||||
closestPos = v
|
||||
}
|
||||
}
|
||||
*/
|
||||
// If there are no opportunities, we're done
|
||||
if len(opportunities) == 0 {
|
||||
fmt.Println(c.string(), "sees no opportunities")
|
||||
return true
|
||||
}
|
||||
var bestOpportunities []*complex64
|
||||
moves := make(map[complex64]complex64)
|
||||
bestDist := MaxInt
|
||||
for _, opp := range opportunities {
|
||||
paths := append([]pathPoint{}, pathPoint{
|
||||
pos: opp,
|
||||
count: 0,
|
||||
})
|
||||
move, length := findMove(c.pos, paths)
|
||||
if length < bestDist {
|
||||
bestOpportunities = append([]*complex64{}, &opp)
|
||||
for k := range moves {
|
||||
delete(moves, k)
|
||||
}
|
||||
moves[opp] = move
|
||||
bestDist = length
|
||||
} else if length == bestDist {
|
||||
bestOpportunities = append(bestOpportunities, &opp)
|
||||
moves[opp] = move
|
||||
}
|
||||
}
|
||||
sort.Sort(ByPos(bestOpportunities))
|
||||
//paths := append([]pathPoint{}, pathPoint{
|
||||
// pos: closestPos,
|
||||
// count: 0,
|
||||
//})
|
||||
//move := findMove(c.pos, paths)
|
||||
if len(bestOpportunities) > 0 {
|
||||
goWith := bestOpportunities[0]
|
||||
fmt.Println(c.string(),
|
||||
"moving to",
|
||||
getCoordString(moves[*goWith]),
|
||||
"(->",
|
||||
getCoordString(*goWith),
|
||||
bestDist, ")")
|
||||
c.moveTo(*goWith)
|
||||
} else {
|
||||
fmt.Println(c.string(), "can't find a path")
|
||||
}
|
||||
// After moving, check for an attack
|
||||
if tPos, err := c.easiestAdjacentTarget(); err == nil {
|
||||
c.attack(tPos)
|
||||
}
|
||||
return c.hasEnemies()
|
||||
}
|
||||
|
||||
// findMove returns the position this character should move to and the position
|
||||
// that is it's ultimate target
|
||||
func (c *Character) findMove() (*complex64, *complex64) {
|
||||
var opps []*complex64
|
||||
closestTargetDistance := MAX_INT
|
||||
dist, path := findAllPaths(&c.pos)
|
||||
|
||||
for _, v := range characters {
|
||||
if v.health <= 0 {
|
||||
continue
|
||||
}
|
||||
if v.tp != c.tp {
|
||||
for _, t := range v.getOpenSides() {
|
||||
if d, ok := dist[t]; ok && d <= closestTargetDistance {
|
||||
if d < closestTargetDistance {
|
||||
closestTargetDistance = d
|
||||
opps = []*complex64{}
|
||||
}
|
||||
opps = append(opps, &t)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Sort(ByPos(opps))
|
||||
if len(opps) > 0 {
|
||||
t := opps[0]
|
||||
curr := *t
|
||||
for {
|
||||
if pv == c.pos {
|
||||
return &curr, t
|
||||
}
|
||||
curr = pv
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *Character) string() string {
|
||||
return fmt.Sprintf("[%s%s:%d]", string(c.tp), getCoordString(c.pos), c.health)
|
||||
}
|
||||
@@ -263,18 +232,6 @@ func (c *Character) hasOpenFlank() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *Character) move(dir complex64) bool {
|
||||
if getByte(c.pos+dir) != '.' {
|
||||
return false
|
||||
}
|
||||
delete(characters, c.pos)
|
||||
setByte(c.pos, '.')
|
||||
c.pos += dir
|
||||
characters[c.pos] = c
|
||||
setByte(c.pos, c.tp)
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *Character) moveTo(pos complex64) bool {
|
||||
if getByte(pos) != '.' {
|
||||
return false
|
||||
@@ -287,8 +244,39 @@ func (c *Character) moveTo(pos complex64) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func getOpenSides(c complex64) []complex64 {
|
||||
var ret []complex64
|
||||
for _, d := range []complex64{DIR_N, DIR_E, DIR_S, DIR_W} {
|
||||
if getByte(c+d) == '.' {
|
||||
ret = append(ret, c+d)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// findAllPaths returns a map of all distances and a map of all paths
|
||||
func findAllPaths(start *complex64) (map[complex64]int, map[complex64]complex64) {
|
||||
all := []complex64{*start}
|
||||
dist := map[complex64]int{*start: 0}
|
||||
prev := map[complex64]complex64{*start: 0}
|
||||
|
||||
for len(all) > 0 {
|
||||
c := all[0]
|
||||
all = all[1:]
|
||||
for _, n := range getOpenSides(c) {
|
||||
if _, ok := dist[n]; !ok {
|
||||
all = append(all, n)
|
||||
dist[n] = dist[c] + 1
|
||||
prev[n] = c
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dist, prev
|
||||
}
|
||||
|
||||
func printBattlefield() {
|
||||
//fmt.Print(ClearScreen)
|
||||
//fmt.Print(CLEAR_SCREEN)
|
||||
for i := 0; i < len(input)/width; i++ {
|
||||
fmt.Println(string(input[i*width : (i+1)*width]))
|
||||
}
|
||||
@@ -357,7 +345,7 @@ func findMove(p1 complex64, paths []pathPoint) (complex64, int) {
|
||||
// First check if p1 has _any_ possible moves
|
||||
lowest := pathPoint{
|
||||
pos: 0 - 1i,
|
||||
count: MaxInt,
|
||||
count: MAX_INT,
|
||||
}
|
||||
for _, v := range paths {
|
||||
for _, d := range []complex64{DIR_N, DIR_E, DIR_S, DIR_W} {
|
||||
@@ -390,7 +378,7 @@ func findMove(p1 complex64, paths []pathPoint) (complex64, int) {
|
||||
paths = append(paths, wrkPt)
|
||||
}
|
||||
}
|
||||
if len(paths) != pathCount && lowest.count == MaxInt {
|
||||
if len(paths) != pathCount && lowest.count == MAX_INT {
|
||||
return findMove(p1, paths)
|
||||
}
|
||||
// We hit the end, return the lowest part
|
||||
|
Reference in New Issue
Block a user