hask-cw / visual.py
sloast's picture
add files
f3a39f8
raw
history blame
5.45 kB
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()