Attachment 'contest_86.n.py'

Download

   1 #!/usr/bin/env python3
   2 ClDt='''
   3 02_Conditionals 2017-10-13
   4 03_DataTypes 2017-10-20
   5 04_Functions 2017-10-27
   6 05_Lists 2017-11-03
   7 06_Strings 2017-11-10
   8 07_Dicts 2017-11-17
   9 08_Classes 2017-11-24
  10 09_Overload 2017-12-01
  11 10_InheritanceDescriptors 2017-12-08
  12 11_Exceptions 2017-12-15
  13 '''
  14 
  15 ClTs='''
  16 02_Conditionals HelloWorld
  17 02_Conditionals AndOr
  18 02_Conditionals DotsInCircle
  19 02_Conditionals IntPalindrome
  20 02_Conditionals AnyPower
  21 03_DataTypes ParallelSegments
  22 03_DataTypes SectionShuffle
  23 03_DataTypes SecondMax
  24 03_DataTypes PaidStairs
  25 04_Functions Det4x4
  26 04_Functions EvalFunction
  27 04_Functions IterPi
  28 04_Functions GenTriseq
  29 05_Lists FilterList
  30 05_Lists LookSay
  31 05_Lists DodgsonDet
  32 05_Lists SpiralDigits
  33 06_Strings YieldFrom
  34 06_Strings MaxInt
  35 06_Strings PatternFind
  36 07_Dicts ThreeSquares
  37 07_Dicts MostPopular
  38 07_Dicts DungeonMap
  39 07_Dicts FarGalaxy
  40 08_Classes DummyClass
  41 08_Classes CountInt
  42 08_Classes SharedBrain
  43 08_Classes NormalDouble
  44 09_Overload SimpleVector
  45 09_Overload StrangeDots
  46 09_Overload UnaryNumber
  47 09_Overload TrianglesCmp
  48 10_InheritanceDescriptors MegaStroka
  49 10_InheritanceDescriptors GuessABC
  50 10_InheritanceDescriptors SemDescriptor
  51 11_Exceptions BoldCalc
  52 '''
  53 # ~/Загрузки/contest_86_20171219131616.tgz
  54 # argv: ~/Загрузки/contest_86_20171221183309.tgz
  55 
  56 # Run selection
  57 #	Download all runs
  58 #	Download selected runs (20)
  59 # X	Download OK runs
  60 #	Download OK and PR runs
  61 #	Download OK, PR, RJ, IG, PD, DQ runs
  62 #File name pattern
  63 #	Use Contest Id
  64 # X	Use run number
  65 #	Use user Id
  66 # X	Use user Login
  67 #	Use user Name
  68 # X	Use problem short name
  69 #	Use programming language short name
  70 # X	Use submit time
  71 # X	Use source language or content type suffix
  72 
  73 import time
  74 def mkt(st):
  75     return time.mktime(time.strptime(st,"%Y%m%d%H%M%S"))
  76 
  77 ClDt = {l:mkt(d[:4]+d[5:7]+d[8:10]+"000000") for l,d in (s.split() for s in ClDt.split("\n") if s)}
  78 TsCl = {t:l for l,t in (s.split() for s in ClTs.split('\n') if s)}
  79 TsDt = {t:ClDt[l] for t,l in TsCl.items()}
  80 
  81 import sys
  82 import os
  83 import pickle
  84 from collections import defaultdict as table
  85 
  86 def table_list(): return table(list)
  87 def table_dict(): return table(dict)
  88 def table_set(): return table(set)
  89 
  90 CF = sys.argv[1]
  91 for sfx in sys.argv[2:]:
  92     CFDELETE = "{}.{}.tmp".format(CF,sfx)
  93     if os.path.isfile(CFDELETE):
  94         os.unlink(CFDELETE)
  95 
  96 CFRes = CF+".All.tmp"
  97 if os.path.isfile(CFRes):
  98     with open(CFRes,"rb") as f:
  99         Res = pickle.load(f)
 100 else:
 101     import tarfile
 102     Res = table(set)
 103     with tarfile.open(CF,"r") as f:
 104         for o in f:
 105             if o.isfile():
 106                 s = o.name
 107                 # contest_86_20171219131616/000064-Nikscorp-HelloWorld-20170930113002.py
 108                 ID, *Nick, Task, Date = s.split("/")[-1][:-3].split("-")
 109                 Nick = "-".join(Nick)
 110                 Res[Nick].add(Task)
 111     with open(CFRes,"wb") as f:
 112         pickle.dump(Res,f)
 113 Users = {N for N,V in Res.items() if 3*len(V)>2*len(TsDt)}
 114 print("# Users: {} total / {} allowed".format(len(Res), len(Users)))
 115 
 116 CFSrc = CF+".Source.tmp"
 117 if os.path.isfile(CFSrc):
 118     with open(CFSrc,"rb") as f:
 119         IDs = pickle.load(f)
 120         Src = pickle.load(f)
 121         Tab = pickle.load(f)
 122 else:
 123     import tarfile
 124     Src = {}
 125     IDs = {}
 126     with tarfile.open(CF,"r") as f:
 127         for o in f:
 128             if o.isfile():
 129                 s = o.name
 130                 # contest_86_20171219131616/000064-Nikscorp-HelloWorld-20170930113002.py
 131                 ID, *Nick, Task, Date = s.split("/")[-1][:-3].split("-")
 132                 Nick, ID, Date = "-".join(Nick), int(ID), mkt(Date)
 133                 if Nick not in Users: continue
 134                 with f.extractfile(o) as df:
 135                     txt = df.read().decode()
 136                 Src[ID], IDs[ID] = txt, (Nick, Task, Date)
 137     Tab = table(table_set)
 138     for ID, (Nick, Task, Date) in IDs.items():
 139         Tab[Task][Nick].add(ID)
 140 
 141     with open(CFSrc,"wb") as f:
 142         pickle.dump(IDs,f)
 143         pickle.dump(Src,f)
 144         pickle.dump(Tab,f)
 145 print("# Tasks: {}/{}".format(len(IDs),max(IDs)))
 146 
 147 CFPrep = CF+".Prep.tmp"
 148 if os.path.isfile(CFPrep):
 149     with open(CFPrep,"rb") as f:
 150         Prep = pickle.load(f)
 151 else:
 152     import ast
 153     import re
 154     import autopep8
 155     ra=re.compile(r"'[^']*'")
 156     rb=re.compile(r"[\[\]\{\}\(\)\,\ ]+")
 157     AstK = ['None ']+[s+' ' for s in dir(ast) if s[0].isalpha()]
 158     Prep = {}
 159     c, M = -1, int(max(IDs))
 160     for ID in sorted(Src):
 161         src = Src[ID]
 162         if c != int(ID)//100:
 163             print(ID)
 164             c = int(ID)//100
 165         prep = rb.sub(" ",ra.sub("@",ast.dump(ast.parse(src,"ex.py"),annotate_fields=False)))
 166         txt = autopep8.fix_code(src)
 167         for i,p in enumerate(AstK):
 168             prep = prep.replace(p,chr(i+0x21)+" ")
 169         Prep[ID] = txt, prep.replace(" ","")
 170     with open(CFPrep,"wb") as f:
 171         pickle.dump(Prep,f)
 172 print("# Total code/prepared: {}/{}".format(sum(len(t) for t,p in Prep.values()), sum(len(p) for t,p in Prep.values())))
 173 
 174 def getdist(id1, id2):
 175     return editdistance.eval(Prep[id1][1], Prep[id2][1])*2/(len(Prep[id1][1])+len(Prep[id2][1]))
 176 
 177 def cluster(Heap):
 178     l=-1
 179     while l!=len(Heap):
 180         l = len(Heap)
 181         Heap={frozenset.union(*(b for b in Heap if a&b)) for a in Heap}
 182     return Heap
 183 
 184 CFPaste = CF+".Paste.tmp"
 185 cPaste = 0.01
 186 cRew = 0.1
 187 minCommon = 7
 188 if os.path.isfile(CFPaste):
 189     with open(CFPaste,"rb") as f:
 190         Paste = pickle.load(f)
 191 else:
 192     import editdistance
 193     Paste = {}
 194     for T in Tab:
 195         print(T)
 196         Us = sorted(Tab[T])
 197         P = set()
 198         for i in range(len(Us)-1):
 199             for j in range(i+1,len(Us)):
 200                 for ID1 in Tab[T][Us[i]]:
 201                     for ID2 in Tab[T][Us[j]]:
 202                         ID1, ID2 = sorted((ID1, ID2))
 203                         dist = getdist(ID1, ID2)
 204                         if dist<cPaste:
 205                             P.add((ID1, ID2, dist))
 206         #Paste[T] = {i:min((i1,d) for i1,i2,d in P if i2==i) for i in {j2 for j1,j2,dd in P }}
 207         Paste[T] = P,cluster({ frozenset({ i, j }) for i, j, d in P })
 208     with open(CFPaste,"wb") as f:
 209         pickle.dump(Paste,f)
 210 
 211 def tpasters(T):
 212     P = {}
 213     for C in Paste[T][1]:
 214         H, *L = sorted(C)
 215         U, L = IDs[H][0], {IDs[l][0] for l in L if IDs[l][0]!=IDs[H][0]}
 216         if not L: continue
 217         if len(L) >= minCommon:
 218             return None
 219         P[(U,H)] = L
 220     else:
 221         return P
 222 
 223 def ftpasters(T):
 224     P = {}
 225     for C in Paste[T][1]:
 226         H, *L = sorted(C)
 227         if {IDs[l][0] for l in L} == {IDs[H][0]}:
 228             continue
 229         if len(L) >= minCommon:
 230             return {}
 231         P[(IDs[H][0],H)] = [(IDs[l][0],l) for l in L if IDs[l][0]!=IDs[H][0]]
 232     return P
 233 
 234 def fpasters(T):
 235     P = {}
 236     for C in Paste[T][1]:
 237         H, *L = sorted(C)
 238         if {IDs[l][0] for l in L} == {IDs[H][0]}:
 239             continue
 240         P[(IDs[H][0],H)] = [(IDs[l][0],l) for l in L]
 241     return P
 242 
 243 print("# Pasters:")
 244 
 245 #{"HelloWorld","DummyClass", "NormalDouble","YieldFrom","SharedBrain","SectionShuffle","ParallelSegments","EvalFunction","CountInt","AndOr","DotsInCircle"}:
 246 
 247 import difflib
 248 import editdistance
 249 
 250 def shortest(T,U1,U2):
 251     I1 = {int(U1)} if U1.isdigit() else Tab[T][U1]
 252     I2 = {int(U2)} if U2.isdigit() else Tab[T][U2]
 253     I1,I2 = min(((i1,i2) for i1 in I1 for i2 in I2), key=lambda a: getdist(*a))
 254     U1, U2 = IDs[I1][0], IDs[I2][0]
 255     return (I1,U1),(I2,U2),getdist(I1,I2)
 256 
 257 def Allpasters():
 258     for T in sorted(Paste):
 259         P = tpasters(T)
 260         print("## {}: {}{}".format(T,sum(len(s) for s in Paste[T][1]),P and "." or "!"))
 261         if P:
 262             for (U,H),L in sorted(P.items()):
 263                 print("{} ({}): {}".format(U,H," ".join(L)))
 264 
 265 def Taskpasters(T):
 266     for (U,H),L in fpasters(T).items():
 267         LL = " ".join("{}({})".format(*l) for l in L)
 268         print("{}({}): {}".format(U,H,LL))
 269 
 270 def Taskids(T,U=None):
 271     UU = [U] if U else Tab[T]
 272     print("#  {}: {}".format(T, " ".join("{}({})".format(u,i) for i,u in sorted((i,IDs[i][0]) for U in UU for i in Tab[T][U]))))
 273 
 274 def Userpastes(UU,TT=None):
 275     for T in ([TT] if TT else Paste):
 276         if not tpasters(T): continue
 277         for (U,H),L in fpasters(T).items():
 278             for u,i in L:
 279                 if UU == u:
 280                     print("{} {}: {}({}) → {}({})".format(T,getdist(H,i),U,H,u,i))
 281 
 282 def Usertasks(U):
 283     print(" ".join(sorted(T for T in Tab if Tab[T][U])))
 284 
 285 def Diffsrc(T,U1,U2):
 286     (I1,U1),(I2,U2),d = shortest(T,U1,U2)
 287     print("{} ({}) / {} ({}): {}\n".format(U1,I1,U2,I2,d),"\n".join(difflib.ndiff(Src[I1].splitlines(),Src[I2].splitlines())))
 288 
 289 AuthIDs = set()
 290 TaskExs = set()
 291 def Mkpenalty(TaskEx=set(), addAUI=set()):
 292     Pen = {}
 293     AIDs = AuthIDs | addAUI
 294     for T in Tab:
 295         if T in TaskEx | TaskExs:
 296             Pen[T] = {}
 297             continue
 298         FP = ftpasters(T)
 299         #print(*(i for U,I in FP for u,i in FP[U,I] if u!=U))
 300         Pen[T]=set(i for U,I in FP for u,i in FP[U,I])
 301     return Pen
 302 Penalty = Mkpenalty()
 303 
 304 UP,MD,LW = 4,2,1
 305 Div =  (24*60*60,UP), (7*24*60*60,MD), (14*24*60*60,LW),
 306 def score(ID):
 307     U, T, D = IDs[ID]
 308     if ID in Penalty[T]: return LW
 309     for dd, sc in Div:
 310         if TsDt[T]+dd>=D:
 311             break
 312     return sc
 313 
 314 def Userscore(U):
 315     scores = [max(score(i) for i in Tab[T][U]) for T in Tab if Tab[T][U]]
 316     All = len(scores)
 317     Full = scores.count(4)
 318     return sum(scores), All, Full
 319 
 320 Mx = UP*len(Tab)
 321 Mn = Mx * 2 // 3
 322 def grade(M, g=("Отл","Хор","Удовл")):
 323     if M<=Mn: return ""
 324     return g[int((Mx-M)*len(g)/(Mx-Mn))]
 325 
 326 def isID(i):
 327     if type(i) is int and i in IDs or type(i) is str and i.isdigit() and int(i) in IDs:
 328         return int(i)
 329     else:
 330         return None
 331 
 332 import os
 333 import readline
 334 import atexit
 335 
 336 C = []
 337 
 338 def dumpargs(*ap, **an):
 339     print("##",ap,an)
 340 
 341 def completer(text, state):
 342     U = [u for u in Users if u.startswith(text)]
 343     return U[state] if len(U)>state else None
 344 
 345 def lister(st, matches, maxlen):
 346     w = os.get_terminal_size().columns-2-len(prompt)
 347     sub = readline.get_line_buffer()
 348     res = " ".join(matches)[len(st):w+len(st)-1]
 349     print(" ".join(matches)[len(st):],prompt+sub,sep="\n",end="")
 350     sys.stdout.flush()
 351 
 352 def DoCalc():
 353     if "/" in C:
 354         Mkpenalty(set(C[1:C.index("/")]),set(C[C.index("/")+1:]))
 355     else:
 356         Mkpenalty(set(C[1:]))
 357 
 358 def DoTable():
 359     print("|| № || '''Ник''' || '''Всего''' || '''Вовремя''' || '''Баллы''' || '''Оценка''' ||")
 360     Res = sorted(((Userscore(U),U) for U in Users),reverse=1)
 361     for i,((sc, a, f),U) in enumerate(Res,1):
 362         print("|| {} || {} || {} || {} || {} || {} ||".format(i,U,a,f,sc,grade(sc)))
 363 
 364 def UserCalc():
 365     sc, a, f = Userscore(C[1])
 366     print("{}: ({}/{}) {} = {}".format(C[1],a,f,sc,grade(sc) or "Неуд"))
 367 
 368 def DoTaskpasters():
 369     Taskpasters(C[0])
 370 
 371 def DoUserpastes():
 372     if len(C)<2:
 373         Userpastes(C[0])
 374     else:
 375         Userpastes(C[1], C[0])
 376 
 377 def ShowSource():
 378     print("{}({}):".format(*IDs[int(C[0])][:2]))
 379     print(Src[int(C[0])])
 380 
 381 def DoDiffsrc():
 382     Diffsrc(*C)
 383 
 384 def DoUsertasks():
 385     Usertasks(C[1])
 386 
 387 def DoTaskids():
 388     if len(C)<3:
 389         Taskids(C[1])
 390     else:
 391         Taskids(C[1],C[2])
 392 
 393 def DoUsage():
 394     print("Usage: {? [user] | ! [task] | id | user | task [user] | task user-or-id-1 user-or-id2}")
 395 
 396 readline.set_completer(completer)
 397 readline.set_completion_display_matches_hook(lister)
 398 
 399 HFile =  CF+"history.tmp"
 400 if os.path.isfile(HFile):
 401     readline.read_history_file(HFile)
 402 atexit.register(readline.write_history_file, HFile)
 403 cmd, prompt = "/", "GRR> "
 404 while True:
 405     C[:] = cmd.split()
 406     if len(C)>0 and C[0]=="/":
 407         DoCalc()
 408     elif len(C)==1 and C[0]=="!":
 409         Allpasters()
 410     elif len(C)==1 and C[0]=="?":
 411         DoTable()
 412     elif len(C)==2 and C[0]=="?" and C[1] in Users:
 413         UserCalc()
 414     elif len(C)==1 and C[0] in Tab:
 415         DoTaskpasters()
 416     elif len(C)==1 and C[0] in Users:
 417         DoUserpastes()
 418     elif len(C)==2 and C[0] in Tab and C[1] in Users:
 419         DoUserpastes()
 420     elif len(C)==1 and isID(C[0]):
 421         ShowSource()
 422     elif len(C)==3 and C[0] in Tab:
 423         DoDiffsrc()
 424     elif len(C)==2 and C[0]=="!" and C[1] in Users:
 425         DoUsertasks()
 426     elif len(C)==2 and C[0]=="!" and C[1] in Tab:
 427         DoTaskids()
 428     elif len(C)==3 and C[0]=="!" and C[1] in Tab and C[2] in Users:
 429         DoTaskids()
 430     elif C:
 431         DoUsage()
 432     try:
 433         cmd = input(prompt)
 434     except EOFError:
 435         break

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.

You are not allowed to attach a file to this page.