123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 |
- #!/usr/bin/python3
- import sys
- from collections import deque
- def boundary(elves):
- minx = miny = sys.maxsize
- maxx = maxy = 0
- for ex, ey in elves:
- minx = min(minx, ex)
- miny = min(miny, ey)
- maxx = max(maxx, ex)
- maxy = max(maxy, ey)
- return minx, miny, maxx, maxy
- def print_locations(elves):
- minx, miny, maxx, maxy = boundary(elves)
- for y in range(miny, maxy + 1):
- for x in range(minx, maxx + 1):
- print('#' if (x, y) in elves else '.', end='')
- print()
- def count_ground_tiles(elves):
- minx, miny, maxx, maxy = boundary(elves)
- count = 0
- for y in range(miny, maxy + 1):
- for x in range(minx, maxx + 1):
- count += 1 if (x, y) not in elves else 0
- return count
- def solution(endless=True, rounds=None):
- elves = set()
- y = 0
- for line in sys.stdin:
- stripped = line.strip()
- if len(stripped) == 0: continue
- [elves.add((x, y)) for x in range(len(stripped)) if stripped[x] == '#']
- y += 1
- print(elves)
- #print_locations(elves)
- NW = lambda pair: (pair[0] - 1, pair[1] - 1)
- NO = lambda pair: (pair[0], pair[1] - 1)
- NE = lambda pair: (pair[0] + 1, pair[1] - 1)
- SW = lambda pair: (pair[0] - 1, pair[1] + 1)
- SO = lambda pair: (pair[0], pair[1] + 1)
- SE = lambda pair: (pair[0] + 1, pair[1] + 1)
- WE = lambda pair: (pair[0] - 1, pair[1])
- EA = lambda pair: (pair[0] + 1, pair[1])
- considerations = deque([(NW, NO, NE), (SW, SO, SE), (NW, WE, SW), (NE, EA, SE)])
- r = 1
- while True:
- proposals = []
- proposal_count = {}
- for elf in elves:
- alone = True
- for rules in considerations:
- for subrules in rules:
- if subrules(elf) in elves:
- alone = False
- if alone:
- #print(elf, 'alone')
- continue
- for rules in considerations:
- #print(elf, 'looking at', rules[0](elf), rules[1](elf), rules[2](elf))
- p0 = rules[0](elf)
- p1 = rules[1](elf)
- p2 = rules[2](elf)
- if p0 not in elves and p1 not in elves and p2 not in elves:
- #print(elf, 'proposing', rules[1](elf))
- proposals.append((elf, p1))
- if p1 not in proposal_count:
- proposal_count[p1] = 1
- else:
- proposal_count[p1] += 1
- break
- #print(len(proposals), 'proposals')
- #print(proposal_count)
- moves = 0
- considerations.rotate(-1)
- for proposal in proposals:
- elf, next_elf = proposal
- if proposal_count[next_elf] == 1:
- elves.remove(elf)
- elves.add(next_elf)
- moves += 1
- print_locations(elves)
- print(f'{moves} elves moved')
- print(f'found {count_ground_tiles(elves)} ground tiles (round {r})')
- r += 1
- if not endless and r > rounds: break
- if moves == 0: break
- if sys.argv[1] in '1':
- solution(endless=False, rounds=10)
- else:
- solution()
|