diff --git a/inputs/18_example.txt b/inputs/18_example.txt new file mode 100644 index 0000000..fc7612e --- /dev/null +++ b/inputs/18_example.txt @@ -0,0 +1,14 @@ +R 6 (#70c710) +D 5 (#0dc571) +L 2 (#5713f0) +D 2 (#d2c081) +R 2 (#59c680) +D 2 (#411b91) +L 5 (#8ceee2) +U 2 (#caa173) +L 1 (#1b58a2) +U 2 (#caa171) +R 2 (#7807d2) +U 3 (#a77fa3) +L 2 (#015232) +U 2 (#7a21e3) diff --git a/solutions/18_example.txt b/solutions/18_example.txt new file mode 100644 index 0000000..a0f8f97 --- /dev/null +++ b/solutions/18_example.txt @@ -0,0 +1,2 @@ +62 +952408144115 diff --git a/src/python/10_rk.py b/src/python/10_rk.py index c019f66..f681d95 100644 --- a/src/python/10_rk.py +++ b/src/python/10_rk.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import sys import collections +import util """ assuming there is loop @@ -150,37 +151,8 @@ def sol1(IN): continue m[IN[1][0]][IN[1][1]] = c + ninside = util.calculate_inside(l_loop, m) - ninside = 0 - for x, line in enumerate(l_loop): - boundary_start = "" - inside = False - # print(line) - for y, boundary in enumerate(line): - if boundary: - t = m[x][y] - # print(t) - if t == "|": - # print("flip") - inside = not inside - elif boundary_start == "": - # print("start with ", t) - # this can't be '-' - boundary_start = t - elif t != "-": - # skip over - - # print("end in", t) - # print(f"{boundary_start}{t}") - if f"{boundary_start}{t}" in ["FJ", "L7"]: - # print("flip") - # flip only in those cases - inside = not inside - boundary_start = "" - elif inside: - # print(x,y) - ninside += 1 - - pass # print(l_loop) # # initialize outtermost boundary first diff --git a/src/python/18_rk.py b/src/python/18_rk.py new file mode 100644 index 0000000..cf219ca --- /dev/null +++ b/src/python/18_rk.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python3 +import sys +import util +import math + +def parse(): + l = [] + with open(sys.argv[1], 'r') as infile: + for line in infile: + line = line.strip() + di, step, color = line.split() + color = color[2:-1] + l.append((di, int(step), color)) + return l + +def decode(color): + return int(color[:5], 16), util.diDecode[int(color[5])] + + +def getSign(prev_di, di): + if prev_di == "R" and di == "D" or prev_di == "U" and di == "L": + return "7" + elif prev_di == "R" and di == "U" or prev_di == "D" and di == "L": + return "J" + elif prev_di == "L" and di == "D" or prev_di == "U" and di == "R": + return "F" + elif prev_di == "L" and di == "U" or prev_di == "D" and di == "R": + return "L" + +def sol(l, sol1 = True): + maxr, maxc = -math.inf, -math.inf + minr, minc = math.inf, math.inf + output = 0 + pos = (0, 0) + for di, s, color in l: + if not sol1: + s, di = decode(color) + pos = util.tuple_add(pos, util.tuple_mul(util.direction_map[di], s)) + output += s + maxr = max(maxr, pos[0]) + maxc = max(maxc, pos[1]) + minr = min(minr, pos[0]) + minc = min(minc, pos[1]) + assert pos == (0, 0) + + nr = int(maxr-minr+1) + nc = int(maxc-minc+1) + + # a projection of (minr, minc) --> (0, 0) + + pos = (-minr, -minc) + + l_loop = util.matrix([[0 for j in range(nc)] for i in range(nr)]) + m = util.matrix([["." for j in range(nc)] for i in range(nr)]) + # print(l_loop, m, sep="\n") + + + # sort out the starting point first + prev_di = "" + for di, s, color in l: + if not sol1: + s, di = decode(color) + if prev_di != "": + m[pos] = getSign(prev_di, di) + for i in range(s): + pos = util.tuple_add(pos, util.direction_map[di]) + l_loop[pos] = 1 + + if di == "D" or di == "U": + m[pos] = "|" + elif di == "L" or di == "R": + m[pos] = "-" + + pass + prev_di = di + pass + m[pos] = getSign(l[-1][0], l[0][0]) + # print(pos, m[pos]) + + # print(l_loop, m, sep="\n") + + output += util.calculate_inside(l_loop, m) + return output + +def sol2(l, sol2=True): + maxr, maxc = -math.inf, -math.inf + minr, minc = math.inf, math.inf + l_boundary = {0:{}} + output = 0 + pos = (0, 0) + first_di = None + prev_di = None + for di, s, color in l: + if sol2: + s, di = decode(color) + if not first_di: + first_di = di + + # correct the turning point + if prev_di != "": + l_boundary[pos[0]][pos[1]] = getSign(prev_di, di) + + prev_di = di + if di == "U" or di == "D": + for i in range(s): + pos = util.tuple_add(pos, util.direction_map[di]) + if pos[0] in l_boundary: + l_boundary[pos[0]][pos[1]] = "|" + else: + l_boundary[pos[0]] = {pos[1]:"|"} + else: + pos = util.tuple_add(pos, util.tuple_mul(util.direction_map[di], s)) + pass + + output += s + maxr = max(maxr, pos[0]) + maxc = max(maxc, pos[1]) + minr = min(minr, pos[0]) + minc = min(minc, pos[1]) + pass + assert pos == (0, 0) + + l_boundary[0][0] = getSign(prev_di, first_di) + # print(l_boundary) + # print(l_boundary[0][0]) + + inside = False + s_prevline = 0 + l_prevline = None + for r in range(minr, maxr+1): + lb = sorted([(i, j) for i, j in l_boundary[r].items()], key = lambda x:x[0]) + # print(lb) + if l_prevline == lb: + output += s_prevline + continue + s_prevline = 0 + l_prevline = lb + + ib = 0 + l_group = [] + inside = False + true_next = False + prev_type_bound = None + prev_pos = None + for ib in range(len(lb)-1): + p1, s1 = lb[ib] + p2, s2 = lb[ib+1] + dist = p2-p1-1 + + if s1+s2 in ["F7", "LJ"]: + true_next = False + continue + elif s1 == "|" or true_next: + true_next = False + inside = not inside + elif s1+s2 in ["FJ", "L7"]: + true_next = True + continue + + if inside: + s_prevline += dist + output += s_prevline + # print(output, s_prevline) + return output + +def main(): + l = parse() + # print(l) + # print(sol(l)) + print(sol2(l, False)) + print(sol2(l)) + pass + +main() diff --git a/src/python/util.py b/src/python/util.py new file mode 100644 index 0000000..6041deb --- /dev/null +++ b/src/python/util.py @@ -0,0 +1,89 @@ +class matrix: + def __init__(self, l): + self._l = [[e for e in il] for il in l] + + def dim(self): + return len(self._l), len(self._l[0]) + + def __iter__(self): + for x in self._l: + yield x + + + def __getitem__(self, tup): + if type(tup) == type((0,0)): + return self._l[tup[0]][tup[1]] + else: + return self._l[tup] + + def __setitem__(self, tup, val): + self._l[tup[0]][tup[1]] = val + + def __str__(self): + s = "" + for l in self: + for e in l: + s += str(e) + s += "\n" + return s + +def tuple_add(a, b): + return (a[0]+b[0], a[1]+b[1]) + +def tuple_mul(a, b): + return (a[0]*b, a[1]*b) + +diDecode = [ + "R", "D", "L", "U" + ] + +direction_map = { + "r":(0, 1), + "d":(1, 0), + "l":(0, -1), + "u":(-1, 0), + + "R":(0, 1), + "D":(1, 0), + "L":(0, -1), + "U":(-1, 0), + } + + +# day 10 +def calculate_inside(l_loop, m): + """ + l_loop is the matrix where 1 is boundary, 0 is anything else + m is the whole matrix (list of list/str), but only boundary part will be accessed + """ + ninside = 0 + for x, line in enumerate(l_loop): + boundary_start = "" + inside = False + # print(line) + for y, boundary in enumerate(line): + if boundary: + t = m[x][y] + # print(t) + if t == "|": + # print("flip") + inside = not inside + elif boundary_start == "": + # print("start with ", t) + # this can't be '-' + boundary_start = t + elif t != "-": + # skip over - + # print("end in", t) + # print(f"{boundary_start}{t}") + if f"{boundary_start}{t}" in ["FJ", "L7"]: + # print("flip") + # flip only in those cases + inside = not inside + boundary_start = "" + elif inside: + # print(x,y) + ninside += 1 + + pass + return ninside