aoc-2018-python

Advent of Code 2018 Solutions in Python
git clone https://git.sinitax.com/sinitax/aoc-2018-python
Log | Files | Refs | README | sfeed.txt

solve.py (4504B)


      1import sys
      2sys.path.append("../common")
      3import aoc
      4
      5def parse_line(l):
      6    s = l.split(", ")
      7    if s[0].startswith("y="):
      8        s = s[::-1]
      9
     10    res = [[int(x) for x in v.split("=")[1].split("..")] for v in s]
     11    return res
     12
     13constraints = [parse_line(l) for l in aoc.data.split("\n")]
     14
     15xmin = min(c[0][0] for c in constraints)-1
     16xmax = max(c[0][-1] for c in constraints)+1
     17ymin = min(c[1][0] for c in constraints)
     18ymax = max(c[1][-1] for c in constraints)
     19xdif = xmax - xmin + 1
     20ydif = ymax - ymin + 1
     21
     22vmap = [[0 for x in range(xdif)] for y in range(ydif)]
     23
     24def set_map(x, y, v):
     25    global vmap
     26    if y < ymin or y > ymax or x < xmin or x > xmax:
     27        return
     28    vmap[y-ymin][x-xmin] = v
     29
     30def get_map(x, y):
     31    global vmap
     32    if x > xmax or x < xmin:
     33        return 1
     34    elif y > ymax:
     35        return 0
     36    return vmap[y-ymin][x-xmin]
     37
     38def drawWall(c):
     39    if len(c[0]) == 1:
     40        for y in range(c[1][0], c[1][1] + 1):
     41            set_map(c[0][0], y, 1)
     42    else:
     43        for x in range(c[0][0], c[0][1] + 1):
     44            set_map(x, c[1][0], 1)
     45
     46for c in constraints:
     47    drawWall(c)
     48
     49spring = (500, 0)
     50
     51
     52### SETUP END
     53
     54
     55def interpretChar(v):
     56    chars = [".", "#", "|", "~"]
     57    return chars[v]
     58
     59def drawMap():
     60    for y in range(ydif):
     61        aoc.debug("".join([interpretChar(v) for v in vmap[y]]))
     62
     63def fwriteMap():
     64    f = open("output","w+")
     65    for y in range(ydif):
     66        f.write("".join([interpretChar(v) for v in vmap[y]])+"\n")
     67    f.close()
     68
     69def isstatic(p):
     70    return get_map(p[0], p[1]) in (1, 3)
     71
     72def isfree(p):
     73    return get_map(p[0], p[1]) == 0
     74
     75def move(p):
     76    x = p[0]
     77    y = p[1]
     78    if isfree((x, y+1)):
     79        return (x, y+1)
     80    onblock = isstatic((x, y+1))
     81    if not onblock:
     82        return (x,y)
     83    npos = [(x + dir, y) for dir in [-1, 1]]
     84    npos = [np for np in npos if isfree(np) and onblock]
     85    if len(npos) > 1:
     86        return npos
     87    elif len(npos) == 1:
     88        return npos[0]
     89    return (x, y)
     90
     91def fillfloor(p):
     92    onblock = True
     93    isblock = False
     94    x = p[0]
     95    while onblock and not isblock and x >= xmin:
     96        x -= 1
     97        isblock = isstatic((x, p[1]))
     98        onblock = isstatic((x, p[1]+1))
     99    if not isblock:
    100        return None # edge
    101    lx = x+1
    102
    103    onblock = True
    104    isblock = False
    105    x = p[0]
    106    while onblock and not isblock and x <= xmax:
    107        x += 1
    108        isblock = isstatic((x, p[1]))
    109        onblock = isstatic((x, p[1]+1))
    110    if not isblock:
    111        return None
    112    rx = x-1
    113
    114    return [(i, p[1]) for i in range(lx, rx+1)]
    115
    116def count_w_flowing():
    117    water = 0
    118    for y in range(ymin, ymax+1):
    119        for x in range(xmin, xmax+1):
    120            if get_map(x,y) == 2:
    121                water += 1
    122    return water
    123
    124def count_w_static():
    125    water = 0
    126    for y in range(ymin, ymax+1):
    127        for x in range(xmin, xmax+1):
    128            if get_map(x,y) == 3:
    129                water += 1
    130    return water
    131
    132def simulate():
    133    heads = [spring]
    134    while len(heads) > 0:
    135        cp = heads[-1]
    136        if isstatic((cp[0], cp[1]+1)):
    137            # solid below => expand
    138            res = fillfloor(cp)
    139            if res:
    140                for p in res:
    141                    set_map(p[0], p[1], 3)
    142                nhead = None
    143                for x in range(res[0][0], res[-1][0]+1):
    144                    np = (x, res[0][1]-1)
    145                    if get_map(np[0], np[1]) == 2:
    146                        nhead = np
    147                        break
    148                if nhead == None: # head got trapped
    149                    heads.pop()
    150                else:
    151                    heads[-1] = nhead
    152                continue
    153
    154        res = move(cp)
    155        if type(res[0]) == tuple:
    156            heads.pop()
    157            heads += res
    158            for p in res:
    159                set_map(p[0], p[1], 2)
    160        else:
    161            if res != cp:
    162                if res[1] <= ymax:
    163                    set_map(res[0], res[1], 2)
    164                    heads[-1] = res
    165                else:
    166                    heads.pop()
    167            else:
    168                heads.pop()
    169
    170        if aoc.debug_lvl:
    171            aoc.debug(heads)
    172            input()
    173            fwriteMap()
    174
    175def solve1(args):
    176    simulate()
    177    return count_w_flowing() + count_w_static()
    178
    179def solve2(args):
    180    simulate()
    181    return count_w_static()
    182
    183aoc.run(solve1, solve2, sols=[39557, 32984])