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:
		
							
								
								
									
										31
									
								
								2018/day23/bots.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								2018/day23/bots.go
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										18
									
								
								2018/day23/coord.go
									
									
									
									
									
										Normal 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
 | 
			
		||||
}
 | 
			
		||||
@@ -3,88 +3,86 @@ package main
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"log"
 | 
			
		||||
	"math"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var collective *Collective
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	input := stdinToStringSlice()
 | 
			
		||||
 | 
			
		||||
	collective = &Collective{}
 | 
			
		||||
	for _, v := range input {
 | 
			
		||||
		collective.bots = append(collective.bots, NewBot(v))
 | 
			
		||||
	}
 | 
			
		||||
	part1()
 | 
			
		||||
	inp := StdinToStringSlice()
 | 
			
		||||
	fmt.Printf("# Part 1\nIn Range of Strongest: %d\n", StrongestReachable(NewBots(inp)))
 | 
			
		||||
	// Part 2: 94270682 is too low
 | 
			
		||||
	// 				 94481123 is too low
 | 
			
		||||
	fmt.Printf("# Part 2\nClosest Success: %d\n", ClosestSuccess(NewBots(inp)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func part1() {
 | 
			
		||||
	s := collective.strongest()
 | 
			
		||||
	fmt.Println("= Part 1 =")
 | 
			
		||||
	fmt.Println(len(collective.inRange(s)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func part2() {
 | 
			
		||||
	finder := &Bot{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
func StrongestReachable(bots Bots) int {
 | 
			
		||||
	var largestRadius, count int
 | 
			
		||||
	var largestPos Coordinate
 | 
			
		||||
	for c, rs := range bots {
 | 
			
		||||
		for _, r := range rs {
 | 
			
		||||
			if r > largestRadius {
 | 
			
		||||
				largestPos = c
 | 
			
		||||
				largestRadius = r
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	return ret
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Collective) strongest() *Bot {
 | 
			
		||||
	strongest := c.bots[0]
 | 
			
		||||
	for _, v := range c.bots {
 | 
			
		||||
		if v.radius > strongest.radius {
 | 
			
		||||
			strongest = v
 | 
			
		||||
	}
 | 
			
		||||
	for c, rs := range bots {
 | 
			
		||||
		if largestPos.Distance(c) <= largestRadius {
 | 
			
		||||
			count += len(rs)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return strongest
 | 
			
		||||
	return count
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Collective) distance(b1, b2 *Bot) int {
 | 
			
		||||
	xs := math.Abs(float64(b1.x) - float64(b2.x))
 | 
			
		||||
	ys := math.Abs(float64(b1.y) - float64(b2.y))
 | 
			
		||||
	zs := math.Abs(float64(b1.z) - float64(b2.z))
 | 
			
		||||
	return int(xs + ys + zs)
 | 
			
		||||
}
 | 
			
		||||
func ClosestSuccess(bots Bots) int {
 | 
			
		||||
	var cur, topLeft, bottomRight Coordinate
 | 
			
		||||
	zoom := 1 << (strconv.IntSize - 2)
 | 
			
		||||
 | 
			
		||||
type Bot struct {
 | 
			
		||||
	x, y, z int
 | 
			
		||||
	radius  int
 | 
			
		||||
}
 | 
			
		||||
	for {
 | 
			
		||||
		zoomedBots := make(Bots)
 | 
			
		||||
		best := struct {
 | 
			
		||||
			pos   Coordinate
 | 
			
		||||
			count int
 | 
			
		||||
		}{}
 | 
			
		||||
 | 
			
		||||
func NewBot(args string) *Bot {
 | 
			
		||||
	pts := strings.Split(args, ", ")
 | 
			
		||||
	pos := strings.Split(pts[0][5:len(pts[0])-1], ",")
 | 
			
		||||
	r := strings.Split(pts[1], "=")[1]
 | 
			
		||||
	return &Bot{
 | 
			
		||||
		x:      atoi(pos[0]),
 | 
			
		||||
		y:      atoi(pos[1]),
 | 
			
		||||
		z:      atoi(pos[2]),
 | 
			
		||||
		radius: atoi(r),
 | 
			
		||||
		for c, rs := range bots {
 | 
			
		||||
			for _, r := range rs {
 | 
			
		||||
				zc := Coordinate{c.X / zoom, c.Y / zoom, c.Z / zoom}
 | 
			
		||||
				zoomedBots[zc] = append(zoomedBots[zc], r/zoom)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for cur.X = topLeft.X; cur.X <= bottomRight.X; cur.X++ {
 | 
			
		||||
			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 {
 | 
			
		||||
	return fmt.Sprintf("(%d,%d,%d : %d)", b.x, b.y, b.z, b.radius)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func stdinToStringSlice() []string {
 | 
			
		||||
func StdinToStringSlice() []string {
 | 
			
		||||
	var input []string
 | 
			
		||||
	scanner := bufio.NewScanner(os.Stdin)
 | 
			
		||||
	for scanner.Scan() {
 | 
			
		||||
@@ -92,12 +90,3 @@ func stdinToStringSlice() []string {
 | 
			
		||||
	}
 | 
			
		||||
	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
									
								
							
							
						
						
									
										81
									
								
								2018/day23/day23.py
									
									
									
									
									
										Executable 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
									
								
							
							
						
						
									
										1000
									
								
								2018/day23/day23.txt
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,9 +1,6 @@
 | 
			
		||||
pos=<0,0,0>, r=4
 | 
			
		||||
pos=<1,0,0>, r=1
 | 
			
		||||
pos=<4,0,0>, r=3
 | 
			
		||||
pos=<0,2,0>, r=1
 | 
			
		||||
pos=<0,5,0>, r=3
 | 
			
		||||
pos=<0,0,3>, r=1
 | 
			
		||||
pos=<1,1,1>, r=1
 | 
			
		||||
pos=<1,1,2>, r=1
 | 
			
		||||
pos=<1,3,1>, r=1
 | 
			
		||||
pos=<10,12,12>, r=2
 | 
			
		||||
pos=<12,14,12>, r=2
 | 
			
		||||
pos=<16,12,12>, r=4
 | 
			
		||||
pos=<14,14,14>, r=6
 | 
			
		||||
pos=<50,50,50>, r=200
 | 
			
		||||
pos=<10,10,10>, r=5
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user