from re import match import matplotlib.pyplot as plt from matplotlib.patches import Arc EMPTY = -1 WIRE = 0 SOURCE = 1 SINK = 2 NORTH = 0 EAST = 1 SOUTH = 2 WEST = 3 ############ SCALE = 1 WIDTH = .25 CIRCRAD = .25 ############ HLF = WIDTH/2 LW = 50 * WIDTH * SCALE def parseDirs(dirs): if dirs == '': return [] return list(map(["North","East","South","West"].index,dirs.split(','))) def parse(s:str): s = ''.join(s.split()) s = match(r'\[(.*)\]',s).group(1) lines = s.split(']],') #objs = [l.split('],') for l in lines] tiles = [] for l in lines: currline= [] ts = l.split('],') for t in ts: t = t.strip('[]') if r:=match(r'Wire\[?(.*)',t): currline.append((WIRE,parseDirs(r.group(1)))) elif r:=match(r'Source\[?(.*)',t): currline.append((SOURCE,parseDirs(r.group(1)))) elif r:=match(r'Sink\[?(.*)',t): currline.append((SINK,parseDirs(r.group(1)))) else: raise Exception("didnt work :/") tiles.append(currline) tiles.reverse() #print(tiles) return tiles def join(xs,ys): return [x + [(EMPTY,[])] + y for x,y in zip(xs,ys)] def rectpos(x, y, d): return [((x - HLF, y), WIDTH, .5), ((x, y - HLF), .5, WIDTH), ((x - HLF, y - .5), WIDTH, .5), ((x - .5, y - HLF), .5, WIDTH)][d] def mktile(tile, pos, wirevalid=True, circlevalid=True, wirevalidcolor='green', wireinvalidcolor='red', circlevalidcolor='green', circleinvalidcolor='red' ): wirecolor = wirevalidcolor if wirevalid else wireinvalidcolor circlecolor = circlevalidcolor if circlevalid else circleinvalidcolor tiletype,ds = tile x,y = pos if tiletype == EMPTY: return box = plt.Rectangle((x-.5,y-.5),1,1,color='grey',fill=False, zorder=2) plt.gca().add_patch(box) if not (wirevalid and circlevalid): plt.gca().add_patch(plt.Rectangle((x-.5,y-.5),1,1,color='red',fill=False, zorder=3, lw=1)) # if line is a right angle draw an arc if tiletype == WIRE and len(ds) == 2 and (ds[0] - ds[1]) % 2 == 1: ds = sorted(ds) if ds == [0,3]: plt.gca().add_patch(Arc((x-.5,y+.5),1,1,theta1=270,theta2=360,color=wirecolor, lw=LW)) elif ds[0] == 0: plt.gca().add_patch(Arc((x+.5,y+.5),1,1,theta1=180,theta2=270,color=wirecolor, lw=LW)) elif ds[0] == 1: plt.gca().add_patch(Arc((x+.5,y-.5),1,1,theta1=90,theta2=180,color=wirecolor, lw=LW)) elif ds[0] == 2: plt.gca().add_patch(Arc((x-.5,y-.5),1,1,theta1=0,theta2=90,color=wirecolor, lw=LW)) else: if len(ds) == 1: circ = plt.Circle((x,y),HLF,color=wirecolor) plt.gca().add_patch(circ) for d in ds: rect = plt.Rectangle(*rectpos(x,y,d),color=wirecolor) plt.gca().add_patch(rect) if tiletype > 0: circ = plt.Circle((x,y),CIRCRAD,color=circlecolor) plt.gca().add_patch(circ) if tiletype == 2: circ = plt.Circle((x,y),CIRCRAD/2,color='white') plt.gca().add_patch(circ) def mkgrid(grid): for y,l in enumerate(grid): for x,t in enumerate(l): if t[0] > WIRE: mktile(t,(x,y), isWireConnected(grid,x,y), sinksource(grid,x,y)) else: mktile(t,(x,y), isWireConnected(grid,x,y)) directions = [(0,1),(1,0),(0,-1),(-1,0)] def isWireConnected(puzzle,x,y): _,ds = puzzle[y][x] drs= [directions[d] for d in ds] return all(0 <= y+dy < len(puzzle) and 0 <= x+dx < len(puzzle[y+dy]) and (d+2)%4 in puzzle[y+dy][x+dx][1] for d,(dx,dy) in zip(ds, drs)) def neighbours(puzzle,x,y): _,ds = puzzle[y][x] for d in ds: dx,dy = directions[d] if 0 <= y+dy < len(puzzle) and 0 <= x+dx < len(puzzle[y+dy]): yield (x+dx,y+dy) def sinksource(puzzle,x,y): ttype,_ = puzzle[y][x] found = [(x,y)] ttype2 = SINK if ttype == SOURCE else SOURCE assert ttype in [SOURCE,SINK] flag = True while flag: flag = False for (x1,y1) in found.copy(): for (x2,y2) in neighbours(puzzle,x1,y1): if (x2,y2) in found: continue found.append((x2,y2)) flag = True if puzzle[y2][x2][0] == ttype2: return True return False def joined(puzzle,x1,y1,x2,y2): # is there a wire connecting the tiles at x1,y1 and x2,y2 _,ds = puzzle[y1][x1] _,ds2 = puzzle[y2][x2] diff = (x2-x1,y2-y1) if diff not in [(0,1),(1,0),(0,-1),(-1,0)]: return False d = directions.index(diff) return (d+2)%4 in ds2 and d in ds def setup(p, show_axes=False): plt.figure(figsize=(len(p[0])*SCALE,len(p)*SCALE)) plt.axes().set_aspect('equal') plt.gca().xaxis.set_major_locator(plt.MultipleLocator(1)) plt.gca().yaxis.set_major_locator(plt.MultipleLocator(1)) plt.gca().get_xaxis().set_visible(show_axes) plt.gca().get_yaxis().set_visible(show_axes) mkgrid(p) plt.axis('scaled') def fig(p): setup(p) return plt def show(p, show_axes=False): setup(p, show_axes) plt.show() def main(): inp = input(">>>") while inp != "": show(parse(inp)) inp = input(">>>") if __name__ == '__main__': main()