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 ( | 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
									
								
							
							
						
						
									
										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=<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 |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user