removing input from git
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
||||
a.out
|
||||
input
|
||||
|
||||
@@ -15,6 +15,11 @@ std::vector<std::string> read_input_file() {
|
||||
return data;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T peek_back(T it) {
|
||||
return --it;
|
||||
}
|
||||
|
||||
int parse_id(std::string ticket) {
|
||||
std::replace(ticket.begin(), ticket.end(), 'F', '0');
|
||||
std::replace(ticket.begin(), ticket.end(), 'L', '0');
|
||||
@@ -28,8 +33,7 @@ int solve_a(const std::set<int> &ids) { return *ids.rbegin(); }
|
||||
|
||||
int solve_b(const std::set<int> &ids) {
|
||||
for(auto it = ++ids.begin(); it != ids.end(); it++){
|
||||
auto prev = it; --prev;
|
||||
if(*prev + 2 == *it) return *it - 1;
|
||||
if(*peek_back(it) + 2 == *it) return *it - 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
449
2020/day_5/visual.py
Normal file
449
2020/day_5/visual.py
Normal file
@@ -0,0 +1,449 @@
|
||||
|
||||
# Sorry, all out of meatballs, but the spaghetti in here is good nonetheless
|
||||
|
||||
import curses
|
||||
import itertools
|
||||
import random
|
||||
from time import sleep
|
||||
import threading
|
||||
|
||||
BOX_URD = 0x251C
|
||||
BOX_UDL = 0x2524
|
||||
BOX_LR = 0x2500
|
||||
BOX_UD = 0x2502
|
||||
BOX_UR = 0x2514
|
||||
|
||||
TOTAL_SIZE = (132, 20)
|
||||
|
||||
PLANE_FRAME = ((0, 0), (132, 14))
|
||||
ACTIVE_FRAME = ((0, 13), (66, 5))
|
||||
RESULT_FRAME = ((66, 13), (66, 5))
|
||||
STATUS_FRAME = ((0, 18), (100, 2))
|
||||
|
||||
SPEC_SCROLLER_OFFSETX = 15
|
||||
ACTIVE_INFO_NUM_FIELD = 16
|
||||
ACTIVE_POST_NUM_FIELD = 24
|
||||
ACTIVE_INFO_KEY_OFFSETX = 32
|
||||
ACTIVE_INFO_VALUE_OFFSETX = 42
|
||||
RESULT_VALUE_OFFSETX = 16
|
||||
ACTIVE_INFO_VALUE_MAXLN = ACTIVE_FRAME[1][0] - ACTIVE_INFO_VALUE_OFFSETX - 3
|
||||
RESULT_VALUE_MAXLN = RESULT_FRAME[1][0] - RESULT_VALUE_OFFSETX - 3
|
||||
STATUS_MAXLN = STATUS_FRAME[1][0] - 4
|
||||
|
||||
COLOR_LIGHT_GREEN = 0xa
|
||||
COLOR_LIGHT_AQUA = 0xb
|
||||
COLOR_LIGHT_YELLOW = 0xe
|
||||
COLOR_WHITE = 7
|
||||
COLOR_GRAY = 8
|
||||
COLOR_FULLWHITE = 0xF
|
||||
|
||||
VISUALIZE_BIN_SEARCH_FIRST = 16
|
||||
|
||||
class StatusThread(threading.Thread):
|
||||
ANIM_LENGTH = 7
|
||||
|
||||
def __init__(self, status_win):
|
||||
super().__init__()
|
||||
self.status_win = status_win
|
||||
self._stlen = 0
|
||||
self.draw_anim = False
|
||||
self.stop_flag = threading.Event()
|
||||
self.animcycler = itertools.cycle(
|
||||
(" ▙█", " █▟", " █▙", " █▛", " █▜", " ▛█", " ▜█", " ▟█")
|
||||
)
|
||||
|
||||
def set_status(self, status, draw_anim=True):
|
||||
self.draw_anim = draw_anim
|
||||
self._stlen = min(len(status), STATUS_MAXLN - self.ANIM_LENGTH)
|
||||
self.status_win.addstr(0, 2, f"{status: <{STATUS_MAXLN}}")
|
||||
self.status_win.refresh()
|
||||
|
||||
def join(self):
|
||||
self.stop_flag.set()
|
||||
super().join()
|
||||
|
||||
def run(self):
|
||||
while not self.stop_flag.is_set():
|
||||
if self.draw_anim:
|
||||
self.status_win.addstr(0, 2 + self._stlen, next(self.animcycler))
|
||||
self.status_win.refresh()
|
||||
sleep(.2)
|
||||
|
||||
|
||||
def new_border_and_win(ws):
|
||||
"""
|
||||
Returns two curses windows, one serving as the border, the other as the
|
||||
inside from these *_FRAME tuples above.
|
||||
"""
|
||||
return (
|
||||
curses.newwin(ws[1][1], ws[1][0], ws[0][1], ws[0][0]),
|
||||
curses.newwin(ws[1][1] - 2, ws[1][0] - 2, ws[0][1] + 1, ws[0][0] + 1),
|
||||
)
|
||||
|
||||
def new_win(tup):
|
||||
"""
|
||||
Returns a curses window made from the (x,y),(w,h) tuples above
|
||||
"""
|
||||
return curses.newwin(tup[1][1], tup[1][0], tup[0][1], tup[0][0])
|
||||
|
||||
class PlaneVisualization():
|
||||
def __init__(self, input_):
|
||||
self.seat_specs = input_.splitlines()
|
||||
|
||||
def run(self):
|
||||
self.init_curses()
|
||||
my, mx = self.screen.getmaxyx()
|
||||
if (mx, my) < TOTAL_SIZE:
|
||||
self.screen.addstr("Terminal too small!")
|
||||
self.screen.refresh()
|
||||
sleep(1)
|
||||
self.stop_curses()
|
||||
return
|
||||
|
||||
self.setup_windows()
|
||||
|
||||
self.visualize()
|
||||
|
||||
self.stop_curses()
|
||||
|
||||
def init_curses(self):
|
||||
self.screen = curses.initscr()
|
||||
curses.start_color()
|
||||
curses.init_pair(1, COLOR_GRAY, curses.COLOR_BLACK) # Darkest non-black color on black bg
|
||||
curses.init_pair(2, COLOR_FULLWHITE, curses.COLOR_BLACK) # Full white on black bg
|
||||
curses.init_pair(3, COLOR_WHITE, COLOR_GRAY) # Full white on black bg
|
||||
curses.init_pair(4, COLOR_LIGHT_GREEN, curses.COLOR_BLACK) # Green on black bg
|
||||
curses.init_pair(5, COLOR_LIGHT_AQUA, curses.COLOR_BLUE ) # aqua on black bg, used to highlight max
|
||||
curses.init_pair(6, COLOR_LIGHT_YELLOW,curses.COLOR_BLACK)
|
||||
curses.init_pair(7, curses.COLOR_RED, curses.COLOR_BLACK)
|
||||
curses.noecho()
|
||||
curses.cbreak()
|
||||
curses.curs_set(0)
|
||||
|
||||
def stop_curses(self):
|
||||
curses.curs_set(1)
|
||||
curses.nocbreak()
|
||||
curses.echo()
|
||||
curses.endwin()
|
||||
|
||||
def setup_windows(self):
|
||||
## Frame creation
|
||||
plane_b, self.plane_win = new_border_and_win(PLANE_FRAME)
|
||||
active_b, self.active_win = new_border_and_win(ACTIVE_FRAME)
|
||||
result_b, self.result_win = new_border_and_win(RESULT_FRAME)
|
||||
self.status_win = new_win(STATUS_FRAME)
|
||||
|
||||
## Borders
|
||||
plane_b.border()
|
||||
active_b.border(0, 0, 0, 0, BOX_URD, 0, BOX_URD, 0)
|
||||
result_b.border(0, 0, 0, 0, 0, BOX_UDL, 0, 0)
|
||||
self.status_win.addstr(0, 0, "│")
|
||||
self.status_win.addstr(1, 0, "└")
|
||||
self.status_win.addstr(1, 1, "─"*98)
|
||||
|
||||
for win in (plane_b, active_b, result_b, self.status_win):
|
||||
win.refresh()
|
||||
|
||||
@staticmethod
|
||||
def seat_to_screen_pos(row, col):
|
||||
"""
|
||||
Given a seat coordinate from 0, 0 (x, y) -> (row, col),
|
||||
returns actual screen coordinate corresponding to the seat in
|
||||
self.plane_win
|
||||
"""
|
||||
return (1 + row, 1 + col + (col > 2) + (col > 4))
|
||||
|
||||
def vis_seat_search(self, seat_ids):
|
||||
"""
|
||||
Takes existing/occupied seat_ids as a set, returns the free seat or
|
||||
None if not locatable. Also visualizations.
|
||||
"""
|
||||
for seat_id in range(128*8):
|
||||
prev = seat_id - 1
|
||||
next_ = seat_id + 1
|
||||
|
||||
# Draw C, N, P markers
|
||||
x, y = self.seat_to_screen_pos(seat_id >> 3, seat_id & 7)
|
||||
self.plane_win.addstr(y, x, "C", curses.color_pair(5))
|
||||
|
||||
if prev >= 0:
|
||||
x, y = self.seat_to_screen_pos(prev >> 3, prev & 7)
|
||||
self.plane_win.addstr(y, x, "P", curses.color_pair(6))
|
||||
|
||||
if next_ < 1024:
|
||||
x, y = self.seat_to_screen_pos(next_ >> 3, next_ & 7)
|
||||
self.plane_win.addstr(y, x, "N", curses.color_pair(6))
|
||||
|
||||
self.plane_win.refresh()
|
||||
|
||||
self.active_win.addstr(0, ACTIVE_INFO_NUM_FIELD, f"{seat_id: >5}")
|
||||
self.active_win.addstr(1, ACTIVE_INFO_NUM_FIELD, f"{prev: >5}")
|
||||
self.active_win.addstr(2, ACTIVE_INFO_NUM_FIELD, f"{next_: >5}")
|
||||
|
||||
for i, seat_id_ in enumerate((seat_id, prev, next_)):
|
||||
if seat_id_ in seat_ids:
|
||||
self.active_win.addstr(
|
||||
i, ACTIVE_POST_NUM_FIELD, "Exists ",
|
||||
curses.color_pair(7 if i == 0 else 4)
|
||||
)
|
||||
else:
|
||||
self.active_win.addstr(
|
||||
i, ACTIVE_POST_NUM_FIELD, "Does not exist",
|
||||
curses.color_pair(4 if i == 0 else 7)
|
||||
)
|
||||
|
||||
self.active_win.refresh()
|
||||
|
||||
if seat_id not in seat_ids and (prev in seat_ids) and (next_ in seat_ids):
|
||||
return seat_id
|
||||
|
||||
# Reset P marker
|
||||
if prev >= 0:
|
||||
x, y = self.seat_to_screen_pos(prev >> 3, prev & 7)
|
||||
self.plane_win.addstr(y, x, "[" if prev in seat_ids else " ", curses.color_pair(1))
|
||||
|
||||
sleep(1.01 - (seat_id/1024)**.005)
|
||||
|
||||
return None
|
||||
|
||||
def vis_binsearch(self, iter, spec, _pos_remember, cmax):
|
||||
"""
|
||||
This function sucks, but works
|
||||
"""
|
||||
#Draw initial binsearch rect
|
||||
delay = .25 - ((iter/VISUALIZE_BIN_SEARCH_FIRST)**.2)*.24
|
||||
for i in range(8):
|
||||
self.plane_win.chgat(
|
||||
self.seat_to_screen_pos(-1, i)[1],
|
||||
1, 128, curses.color_pair(3)
|
||||
)
|
||||
self.plane_win.refresh()
|
||||
if iter == 0:
|
||||
sleep(5)
|
||||
|
||||
# Binsearch rows
|
||||
row_min = 0
|
||||
row_max = 127
|
||||
step = 64
|
||||
for i, c in enumerate(spec[:7]):
|
||||
if c == "F":
|
||||
row_max -= step
|
||||
else:
|
||||
row_min += step
|
||||
for j in range(10):
|
||||
self.plane_win.chgat(
|
||||
1 + j,
|
||||
1 + (row_max + 1 if c == "F" else row_min - step),
|
||||
step,
|
||||
curses.color_pair(1),
|
||||
)
|
||||
for x, y in _pos_remember:
|
||||
self.plane_win.chgat(y, x, 1, curses.color_pair(2))
|
||||
if cmax is not None:
|
||||
self.plane_win.chgat(cmax[1], cmax[0], 1, curses.color_pair(5))
|
||||
self.active_win.chgat(1, SPEC_SCROLLER_OFFSETX + 2 + i, 1, curses.color_pair(4))
|
||||
self.plane_win.refresh()
|
||||
self.active_win.refresh()
|
||||
step //= 2
|
||||
sleep(delay)
|
||||
row = row_min
|
||||
|
||||
# Binsearch columns
|
||||
col_min = 0
|
||||
col_max = 7
|
||||
step = 4
|
||||
for i, c in enumerate(spec[7:]):
|
||||
if c == "L":
|
||||
col_max -= step
|
||||
else:
|
||||
col_min += step
|
||||
offset = col_max + 1 if c == "L" else col_min - step
|
||||
for j in range(step):
|
||||
tx, ty = self.seat_to_screen_pos(row, offset + j)
|
||||
self.plane_win.chgat(ty, tx, 1, curses.color_pair(1))
|
||||
for x, y in _pos_remember:
|
||||
self.plane_win.chgat(y, x, 1, curses.color_pair(2))
|
||||
if cmax is not None:
|
||||
self.plane_win.chgat(cmax[1], cmax[0], 1, curses.color_pair(5))
|
||||
self.active_win.chgat(1, SPEC_SCROLLER_OFFSETX + 2 + 7 + i, 1, curses.color_pair(4))
|
||||
self.plane_win.refresh()
|
||||
self.active_win.refresh()
|
||||
step //= 2
|
||||
sleep(delay)
|
||||
col = col_min
|
||||
_pos_remember.append(self.seat_to_screen_pos(row, col))
|
||||
|
||||
def visualize(self):
|
||||
## Text for Part 1
|
||||
self.active_win.addstr(0, 1, f"{0: ^{SPEC_SCROLLER_OFFSETX - 2}}")
|
||||
self.active_win.addstr(0, SPEC_SCROLLER_OFFSETX, "| |")
|
||||
self.active_win.addstr(1, 1, "Current seat: > <")
|
||||
self.active_win.addstr(2, 1, f"{len(self.seat_specs): ^{SPEC_SCROLLER_OFFSETX - 2}}")
|
||||
self.active_win.addstr(2, SPEC_SCROLLER_OFFSETX, "| |")
|
||||
self.active_win.addstr(0, ACTIVE_INFO_KEY_OFFSETX, "Row:")
|
||||
self.active_win.addstr(1, ACTIVE_INFO_KEY_OFFSETX, "Column:")
|
||||
self.active_win.addstr(2, ACTIVE_INFO_KEY_OFFSETX, "Id:")
|
||||
self.result_win.addstr(1, 1, "Current max:")
|
||||
|
||||
## Seats
|
||||
self.plane_win.attron(curses.color_pair(1))
|
||||
for line in range(8):
|
||||
self.plane_win.addstr(
|
||||
self.seat_to_screen_pos(-1, line)[1],
|
||||
1, "["*128, curses.color_pair(1)
|
||||
)
|
||||
self.plane_win.refresh()
|
||||
self.plane_win.attron(curses.color_pair(0))
|
||||
|
||||
status_thread = StatusThread(self.status_win)
|
||||
status_thread.start()
|
||||
|
||||
# Begin
|
||||
# Part 1
|
||||
SPEC_AMT = len(self.seat_specs)
|
||||
# Holds position of the first VISUALIZE_BIN_SEARCH_FIRST seats so they
|
||||
# are properly redrawn during binary search.
|
||||
seat_ids = set()
|
||||
_pos_remember = []
|
||||
cmax = cmax_pos = row = col = seat_id = None
|
||||
|
||||
self.active_win.addstr(0, ACTIVE_INFO_VALUE_OFFSETX, str(row))
|
||||
self.active_win.addstr(1, ACTIVE_INFO_VALUE_OFFSETX, str(col))
|
||||
self.active_win.addstr(2, ACTIVE_INFO_VALUE_OFFSETX, str(seat_id))
|
||||
self.result_win.addstr(1, RESULT_VALUE_OFFSETX, str(cmax))
|
||||
self.active_win.refresh()
|
||||
self.result_win.refresh()
|
||||
|
||||
status_thread.set_status("Part 1: Finding maximum seat id")
|
||||
for i, spec in enumerate(self.seat_specs):
|
||||
# Draw Seat Specs
|
||||
if i != 0:
|
||||
self.active_win.addstr(
|
||||
0, SPEC_SCROLLER_OFFSETX + 2,
|
||||
self.seat_specs[i - 1], curses.color_pair(1)
|
||||
)
|
||||
self.active_win.addstr(1, SPEC_SCROLLER_OFFSETX + 2, spec)
|
||||
if i != SPEC_AMT - 1:
|
||||
self.active_win.addstr(
|
||||
2, SPEC_SCROLLER_OFFSETX + 2,
|
||||
self.seat_specs[i + 1], curses.color_pair(1)
|
||||
)
|
||||
else:
|
||||
self.active_win.addstr(2, SPEC_SCROLLER_OFFSETX + 2, " ")
|
||||
# Draw current index
|
||||
self.active_win.addstr(0, 1, f"{i: ^{SPEC_SCROLLER_OFFSETX - 2}}")
|
||||
self.active_win.refresh()
|
||||
|
||||
# Visualize binary subdivision for first three specs
|
||||
if i < VISUALIZE_BIN_SEARCH_FIRST:
|
||||
self.vis_binsearch(i, spec, _pos_remember, cmax_pos)
|
||||
|
||||
# Mega cheap, get seat_id, row and col
|
||||
seat_id = int(spec.replace("F", "0").replace("B", "1").replace("L", "0").replace("R", "1"), 2)
|
||||
row, col = seat_id >> 3, seat_id & 7
|
||||
|
||||
seat_ids.add(seat_id)
|
||||
|
||||
# Color current seat in brighter color
|
||||
tx, ty = self.seat_to_screen_pos(row, col)
|
||||
self.plane_win.chgat(ty, tx, 1, curses.color_pair(2))
|
||||
self.plane_win.refresh()
|
||||
|
||||
# New maximum id?
|
||||
if cmax is None or seat_id > cmax:
|
||||
cmax = seat_id
|
||||
# Decolor old maximum seat
|
||||
if cmax_pos is not None:
|
||||
self.plane_win.chgat(cmax_pos[1], cmax_pos[0], 1, curses.color_pair(2))
|
||||
cmax_pos = self.seat_to_screen_pos(row, col)
|
||||
self.plane_win.chgat(cmax_pos[1], cmax_pos[0], 1, curses.color_pair(5))
|
||||
self.result_win.addstr(1, 1, f"Current max: {cmax: <{RESULT_VALUE_MAXLN}}")
|
||||
self.result_win.refresh()
|
||||
self.plane_win.refresh()
|
||||
|
||||
self.active_win.addstr(0, ACTIVE_INFO_VALUE_OFFSETX, f"{row: <{ACTIVE_INFO_VALUE_MAXLN}}")
|
||||
self.active_win.addstr(1, ACTIVE_INFO_VALUE_OFFSETX, f"{col: <{ACTIVE_INFO_VALUE_MAXLN}}")
|
||||
self.active_win.addstr(2, ACTIVE_INFO_VALUE_OFFSETX, f"{seat_id: <{ACTIVE_INFO_VALUE_MAXLN}}")
|
||||
self.active_win.refresh()
|
||||
|
||||
sleep(.008)
|
||||
|
||||
status_thread.set_status("Maximum found!", False)
|
||||
|
||||
# Blink max repeatedly
|
||||
for _ in range(5):
|
||||
self.result_win.addstr(
|
||||
1, 1, f"Current max: {cmax: <{RESULT_VALUE_MAXLN}}", curses.color_pair(4))
|
||||
self.result_win.refresh()
|
||||
sleep(.4)
|
||||
self.result_win.addstr(
|
||||
1, 1, f"Current max: {' ': <{RESULT_VALUE_MAXLN}}",)
|
||||
self.result_win.refresh()
|
||||
sleep(.3)
|
||||
|
||||
# Purge info windows
|
||||
self.result_win.clear()
|
||||
self.active_win.clear()
|
||||
self.result_win.refresh()
|
||||
self.active_win.refresh()
|
||||
|
||||
status_thread.set_status("Removing seats")
|
||||
BACKDRAG = 8
|
||||
# Thanos snap seats
|
||||
for x in range(128 + BACKDRAG):
|
||||
for y in range(8):
|
||||
for t in range(BACKDRAG):
|
||||
tx, ty = self.seat_to_screen_pos(x - t, y)
|
||||
if 0 < tx < 129 and random.randint(1, BACKDRAG*10-10) < t*10+1:
|
||||
self.plane_win.addstr(ty, tx, " ")
|
||||
self.plane_win.refresh()
|
||||
sleep(.006 + x/6000)
|
||||
|
||||
status_thread.set_status("Drawing existing seats")
|
||||
# Part 2
|
||||
# Add new text fields to lower windows
|
||||
self.active_win.addstr(0, 1, "Current seat [ ]: ")
|
||||
self.active_win.addstr(1, 1, "Previous seat [ ]: ")
|
||||
self.active_win.addstr(2, 1, "Next seat [ ]: ")
|
||||
self.result_win.addstr(1, 1, "Your seat: ?")
|
||||
|
||||
self.active_win.refresh()
|
||||
self.result_win.refresh()
|
||||
|
||||
# Draw all existing seats
|
||||
for i, seat_id in enumerate(seat_ids):
|
||||
row, col = seat_id >> 3, seat_id & 7
|
||||
x, y = self.seat_to_screen_pos(row, col)
|
||||
self.plane_win.addstr(y, x, "[", curses.color_pair(1))
|
||||
self.plane_win.refresh()
|
||||
sleep(.001)
|
||||
|
||||
status_thread.set_status("Part 2: Searching for own seat")
|
||||
own_seat = self.vis_seat_search(seat_ids)
|
||||
|
||||
if own_seat is None:
|
||||
status_thread.set_status("Failed to find seat!", False)
|
||||
else:
|
||||
# Blink seat number repeatedly
|
||||
status_thread.set_status("Seat found!", False)
|
||||
for _ in range(5):
|
||||
self.result_win.addstr(
|
||||
1, 1, f"Your seat: {own_seat: <{RESULT_VALUE_MAXLN}}", curses.color_pair(4))
|
||||
self.result_win.refresh()
|
||||
sleep(.4)
|
||||
self.result_win.addstr(
|
||||
1, 1, f"Your seat: {' ': <{RESULT_VALUE_MAXLN}}",)
|
||||
self.result_win.refresh()
|
||||
sleep(.3)
|
||||
|
||||
sleep(1)
|
||||
|
||||
status_thread.join()
|
||||
|
||||
pz_in = open('input').read()
|
||||
pv = PlaneVisualization(pz_in)
|
||||
try:
|
||||
pv.run()
|
||||
except Exception as e:
|
||||
PlaneVisualization.stop_curses(None)
|
||||
raise e from None
|
||||
Reference in New Issue
Block a user