2018 Day 23*

Had to find someone else's python solution to get an answer.
Need to pull it apart and figure out what's wrong with my solution.
This commit is contained in:
Brian Buller 2019-11-07 15:43:14 -06:00
parent 7c9742fb73
commit 1ec6280623
6 changed files with 1198 additions and 82 deletions

31
2018/day23/bots.go Normal file
View File

@ -0,0 +1,31 @@
package main
import "fmt"
type Bots map[Coordinate][]int
func NewBots(input []string) Bots {
m := make(Bots)
for _, data := range input {
var r int
var c Coordinate
_, err := fmt.Sscanf(data, "pos=<%d,%d,%d>, r=%d", &c.X, &c.Y, &c.Z, &r)
if err != nil {
panic(err)
}
m[c] = append(m[c], r)
}
return m
}
func (m Bots) HaveInRange(pos Coordinate) int {
var sum int
for c, rs := range m {
for _, r := range rs {
if pos.Distance(c) <= r {
sum++
}
}
}
return sum
}

18
2018/day23/coord.go Normal file
View File

@ -0,0 +1,18 @@
package main
type Coordinate struct {
X, Y, Z int
}
var Zero = Coordinate{X: 0, Y: 0, Z: 0}
func (c Coordinate) Distance(a Coordinate) int {
return abs(c.X-a.X) + abs(c.Y-a.Y) + abs(c.Z-a.Z)
}
func abs(v int) int {
if v < 0 {
return v * -1
}
return v
}

View File

@ -3,88 +3,86 @@ package main
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"log"
"math"
"os" "os"
"strconv" "strconv"
"strings"
) )
var collective *Collective
func main() { func main() {
input := stdinToStringSlice() inp := StdinToStringSlice()
fmt.Printf("# Part 1\nIn Range of Strongest: %d\n", StrongestReachable(NewBots(inp)))
collective = &Collective{} // Part 2: 94270682 is too low
for _, v := range input { // 94481123 is too low
collective.bots = append(collective.bots, NewBot(v)) fmt.Printf("# Part 2\nClosest Success: %d\n", ClosestSuccess(NewBots(inp)))
}
part1()
} }
func part1() { func StrongestReachable(bots Bots) int {
s := collective.strongest() var largestRadius, count int
fmt.Println("= Part 1 =") var largestPos Coordinate
fmt.Println(len(collective.inRange(s))) for c, rs := range bots {
} for _, r := range rs {
if r > largestRadius {
func part2() { largestPos = c
finder := &Bot{} largestRadius = r
} }
type Collective struct {
bots []*Bot
}
func (c *Collective) inRange(b *Bot) []*Bot {
var ret []*Bot
for _, v := range c.bots {
if c.distance(b, v) <= b.radius {
ret = append(ret, v)
} }
} }
return ret for c, rs := range bots {
} if largestPos.Distance(c) <= largestRadius {
count += len(rs)
func (c *Collective) strongest() *Bot {
strongest := c.bots[0]
for _, v := range c.bots {
if v.radius > strongest.radius {
strongest = v
} }
} }
return strongest return count
} }
func (c *Collective) distance(b1, b2 *Bot) int { func ClosestSuccess(bots Bots) int {
xs := math.Abs(float64(b1.x) - float64(b2.x)) var cur, topLeft, bottomRight Coordinate
ys := math.Abs(float64(b1.y) - float64(b2.y)) zoom := 1 << (strconv.IntSize - 2)
zs := math.Abs(float64(b1.z) - float64(b2.z))
return int(xs + ys + zs)
}
type Bot struct { for {
x, y, z int zoomedBots := make(Bots)
radius int best := struct {
} pos Coordinate
count int
}{}
func NewBot(args string) *Bot { for c, rs := range bots {
pts := strings.Split(args, ", ") for _, r := range rs {
pos := strings.Split(pts[0][5:len(pts[0])-1], ",") zc := Coordinate{c.X / zoom, c.Y / zoom, c.Z / zoom}
r := strings.Split(pts[1], "=")[1] zoomedBots[zc] = append(zoomedBots[zc], r/zoom)
return &Bot{ }
x: atoi(pos[0]), }
y: atoi(pos[1]),
z: atoi(pos[2]), for cur.X = topLeft.X; cur.X <= bottomRight.X; cur.X++ {
radius: atoi(r), for cur.Y = topLeft.Y; cur.Y <= bottomRight.Y; cur.Y++ {
for cur.Z = topLeft.Z; cur.Z <= bottomRight.Z; cur.Z++ {
c := zoomedBots.HaveInRange(cur)
// skip less bots
if c < best.count {
continue
}
// skip same amount of bots but Distance from Zero is the same or more
if c == best.count && Zero.Distance(cur) >= Zero.Distance(best.pos) {
continue
}
// more bots or same and closer to Zero
best.pos, best.count = cur, c
}
}
}
// zoom in
topLeft.X, topLeft.Y, topLeft.Z = (best.pos.X-1)<<1, (best.pos.Y-1)<<1, (best.pos.Z-1)<<1
bottomRight.X, bottomRight.Y, bottomRight.Z = (best.pos.X+1)<<1, (best.pos.Y+1)<<1, (best.pos.Z+1)<<1
zoom >>= 1
if zoom == 0 {
return Zero.Distance(best.pos)
}
} }
} }
func (b *Bot) string() string { func StdinToStringSlice() []string {
return fmt.Sprintf("(%d,%d,%d : %d)", b.x, b.y, b.z, b.radius)
}
func stdinToStringSlice() []string {
var input []string var input []string
scanner := bufio.NewScanner(os.Stdin) scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() { for scanner.Scan() {
@ -92,12 +90,3 @@ func stdinToStringSlice() []string {
} }
return input return input
} }
func atoi(i string) int {
var ret int
var err error
if ret, err = strconv.Atoi(i); err != nil {
log.Fatal("Invalid Atoi")
}
return ret
}

81
2018/day23/day23.py Executable file
View File

@ -0,0 +1,81 @@
#!/usr/bin/python
from collections import OrderedDict, defaultdict, namedtuple
from functools import total_ordering
from heapq import heappop, heappush
from itertools import chain
import re
Bot = namedtuple('Bot', 'x y z r')
with open('day23.txt') as puzzle_file:
pattern = re.compile(r'pos=<(-?\d+),(-?\d+),(-?\d+)>, r=(\d+)')
bots = [Bot(*map(int, pattern.match(line).groups())) for line in puzzle_file]
max_r = max(bot.r for bot in bots)
print(
max(
sum(abs(b.x - a.x) + abs(b.y - a.y) + abs(b.z - a.z) <= a.r for b in bots) for a in bots
if a.r == max_r))
@total_ordering
class Octa_ordering(object):
def __lt__(self, other):
return self.min < other.min or self.min == other.min and other.max < self.max
class Octa(Octa_ordering, namedtuple('Octa', ('min', 'max'))):
def __new__(cls, *args, **kwargs):
if 'bot' in kwargs:
x, y, z, r = kwargs['bot']
t, u, v, w = x + y + z, x + y - z, x - y - z, x - y + z
return super(Octa, cls).__new__(cls, (t - r, u - r, v - r, w - r),
(t + r, u + r, v + r, w + r))
return super(Octa, cls).__new__(cls, *args, **kwargs)
def intersect(self, other):
c, d, e, f = self.min
g, h, i, j = other.min
k, l, m, n = self.max
o, p, q, r = other.max
s, t, u, v = max(c, g), max(d, h), max(e, i), max(f, j)
w, x, y, z = min(k, o), min(l, p), min(m, q), min(n, r)
return None if s > w or t > x or u > y or v > z else Octa((s, t, u, v), (w, x, y, z))
def distance_to_origin(self):
o, p, q, r = self.min
s, t, u, v = self.max
if o < s and p < t and q < u and r < v:
w = min(abs(o), abs(s)) if o * s >= 0 else 0
x = min(abs(p), abs(t)) if p * t >= 0 else 0
y = min(abs(q), abs(u)) if q * u >= 0 else 0
z = min(abs(r), abs(v)) if r * v >= 0 else 0
return max(w, x, y, z)
return min(
abs((x + z) // 2) + abs((y - z) // 2) + abs((x - y) // 2)
for x in range(o, s + 1) for y in range(p + ((p ^ x) & 1), t + 1, 2)
for z in range(q + ((q ^ x) & 1), u + 1, 2) if r <= x - y + z <= v)
best_count = 0
octs = defaultdict(set)
for i, bot in enumerate(bots):
octs[Octa(bot=bot)].add(i)
queue = [(0, (), OrderedDict((k, octs[k]) for k in sorted(octs)))]
while queue:
n, _, rest = heappop(queue)
if -n < best_count:
break
octa, n = rest.popitem()
sub = defaultdict(set)
for octa2, m in rest.items():
octa3 = octa.intersect(octa2)
if octa3 is not None:
(n if octa == octa3 else sub[octa3]).update(m)
if len(n) > best_count:
best_count, best_distance = len(n), [octa]
elif len(n) == best_count:
best_distance.append(octa)
m = frozenset(chain.from_iterable(rest.values()))
heappush(queue, (-len(m), m, rest))
rest = OrderedDict((k, sub[k].union(n)) for k in sorted(sub))
m = frozenset(chain.from_iterable(rest.values()))
heappush(queue, (-len(m), m, rest))
print(min(octa.distance_to_origin() for octa in best_distance))

1000
2018/day23/day23.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,6 @@
pos=<0,0,0>, r=4 pos=<10,12,12>, r=2
pos=<1,0,0>, r=1 pos=<12,14,12>, r=2
pos=<4,0,0>, r=3 pos=<16,12,12>, r=4
pos=<0,2,0>, r=1 pos=<14,14,14>, r=6
pos=<0,5,0>, r=3 pos=<50,50,50>, r=200
pos=<0,0,3>, r=1 pos=<10,10,10>, r=5
pos=<1,1,1>, r=1
pos=<1,1,2>, r=1
pos=<1,3,1>, r=1