import logging import datetime import lorem from .models import * from treenode.models import UlohaZadaniNode, TextNode, UlohaVzorakNode, CastNode, RocnikNode, CisloNode, TemaVCisleNode, MezicisloNode, ReseniNode from seminar.models.pomocne import Text from seminar.testutils import get_text from odevzdavatko.models import Reseni, Hodnoceni from treenode.testutils import otec_syn, add_first_child from treenode.treelib import all_children, insert_last_child, all_children_of_type, create_node_after from odevzdavatko.testutils import gen_reseni_ulohy logger = logging.getLogger(__name__) def gen_zadani_ulohy(rnd, cisla, organizatori, pocet_oboru, poradi_cisla, poradi_problemu): # Proměnné pro náhodné generování názvů a zadání. jaka = ["Šachová", "Černá", "Větrná", "Dlouhá", "Křehká", "Rychlá", "Zákeřná", "Fyzikální"] co = ["kostka", "smršť", "díra", "zrada", "toulka", "tyč", "úloha", "blecha"] sloveso = ["Najděte", "Spočítejte", "Zapište", "Změřte", "Odhadněte"] koho = ["délku", "počet", "množství", "dílky"] ceho = ["všech", "správných", "konstatních", "zelených"] jmeno = ["řešení", "tahů", "čísel", "kalhot", "koulí", "hadů"] kde = ["na zemi", "ve vesmíru", "ve vzduchu", "na šňůře", "v letadle"] obory = ["M", "F", "I", "O", "B"] p = Uloha.objects.create( # atributy třídy Problem nazev=" ".join([rnd.choice(jaka), rnd.choice(co)]), stav=Problem.STAV_ZADANY, zamereni=rnd.sample(obory, pocet_oboru), autor=rnd.choice(organizatori), garant=rnd.choice(organizatori), kod=str(poradi_problemu), # atributy třídy Uloha cislo_zadani=cisla[poradi_cisla-2-1], cislo_reseni=cisla[poradi_cisla-1], cislo_deadline=cisla[poradi_cisla-1], max_body=rnd.randint(1, 8) ) text = " ".join([ rnd.choice(sloveso), rnd.choice(koho), rnd.choice(ceho), rnd.choice(jmeno), rnd.choice(kde) ]) text_zadani = Text.objects.create( na_web=text, do_cisla=text, ) zad = TextNode.objects.create( text=text_zadani, root=p.cislo_zadani.rocnik.rocniknode, ) uloha_zadani = UlohaZadaniNode.objects.create( uloha=p, first_child=zad, root=p.cislo_zadani.rocnik.rocniknode, ) p.ulohazadaninode = uloha_zadani otec_syn(cisla[poradi_cisla-2-1].cislonode, uloha_zadani) return p def gen_vzoroveho_reseni_ulohy(rnd, organizatori, uloha, pocet_opravovatelu): reseni = ["to je přece jasné", "triviální", "omlouváme se, otevřený problém", "neřešitelné", "triviálně triviální", "použitím věty z prvního semestru na matfyzu", "jednoduše pomocí látky z druhého semestru na matfyzu", "netriviální aplikace diferenciálních rovnic", "zadání je vnitřně sporné", "nepopsatelně jednoduché", "pokud jste na to nepřišli, tak jste fakt hloupí"] # Generování vzorového řešení. obsah = rnd.choice(reseni) text_vzoraku = Text.objects.create( na_web=obsah, do_cisla=obsah ) vzorak = TextNode.objects.create( text=text_vzoraku, root=uloha.cislo_zadani.rocnik.rocniknode, ) uloha_vzorak = UlohaVzorakNode.objects.create( uloha=uloha, first_child=vzorak, root=uloha.cislo_zadani.rocnik.rocniknode, ) uloha.ulohavzoraknode = uloha_vzorak uloha.opravovatele.set(rnd.sample(organizatori, pocet_opravovatelu)) uloha.save() return uloha_vzorak def gen_ulohy_do_cisla(rnd, organizatori, resitele, rocnik_cisla, rocniky, size): logger.info('Generuji úlohy do čísla (size={})...'.format(size)) k = 0 for rocnik in rocniky: k += 1 print("Generuji {}. číslo.".format(k)) cisla = rocnik_cisla[k - 1] for ci in range(3, len(cisla) + 1): # pro všechna čísla resitele_size = round(7/8 * 30 * size) # očekáváný celkový počet řešitelů poc_res = rnd.randint(resitele_size//8, resitele_size//4) # dané číslo řeší něco mezi osminou a čtvrtinou všech řešitelů # (náhodná hausnumera, možno změnit) # účelem je, aby se řešení generovala z menší množiny řešitelů a tedy # bylo více řešení od jednoho řešitele daného čísla resitele_cisla = rnd.sample(resitele, poc_res) for pi in range(1, ((size + 1) // 2) + 1): # počet problémů poc_op = rnd.randint(1, 4) # počet opravovatelů poc_oboru = rnd.randint(1, 2) # Generování zadání úlohy a UlohaZadaniNode, # přivěšení pod dané číslo p = gen_zadani_ulohy(rnd, cisla, organizatori, poc_oboru, ci, pi) # Generování vzorového řešení uloha_vzorak = gen_vzoroveho_reseni_ulohy( rnd, organizatori, p, poc_op ) insert_last_child(cisla[ci-1].cislonode, uloha_vzorak) # Generování řešení a hodnocení k úloze gen_reseni_ulohy( rnd, cisla, p, poc_res, ci, resitele_cisla, resitele ) return def gen_rocniky(last_rocnik, size): logger.info('Generuji ročníky (size={})...'.format(size)) rocniky = [] node = None for ri in range(min(last_rocnik - size, 1), last_rocnik + 1): rocnik = Rocnik.objects.create(prvni_rok=1993 + ri, rocnik=ri) node2 = RocnikNode.objects.create(rocnik=rocnik, succ=node) rocnik.save() node = node2 rocniky.append(rocnik) return rocniky def gen_cisla(rnd, rocniky): logger.info('Generuji čísla...') rocnik_cisla = [] for rocnik in rocniky: otec = True cisla = [] cisel = rnd.randint(4, 8) node = None for ci in range(1, cisel + 1): # první číslo vydáváme typicky okolo prázdnin # (ci - 1)*2 zaručuje první číslo v červnu a všechna # další po dvou měsících (což je rozumná aproximace) mesic_vydani = (ci - 1)*2 + 6 # celociselné dělení mi řekne, jestli to je první nebo druhý rok ročníku vydano = datetime.date( rocnik.prvni_rok + mesic_vydani // 12, (mesic_vydani - 1) % 12 + 1, rnd.randint(1, 28) ) deadline = datetime.date( rocnik.prvni_rok + (mesic_vydani + 2) // 12, (mesic_vydani + 1) % 12 + 1, rnd.randint(1, 28), ) cislo = Cislo.objects.create( rocnik=rocnik, poradi=str(ci), datum_vydani=vydano, verejne_db=True, ) node2 = CisloNode.objects.get(cislo=cislo) node2.succ = node node2.root = rocnik.rocniknode cislo.save() deadline = Deadline.objects.create( cislo=cislo, deadline=deadline, typ=Deadline.TYP_CISLA, verejna_vysledkovka=True, ) deadline.save() node = node2 if otec: otec = False rocnik.rocniknode.first_child = node rocnik.save() cisla.append(cislo) rocnik_cisla.append(cisla) return rocnik_cisla def gen_dlouhe_tema(rnd, organizatori, rocnik, nazev, obor, kod): tema = Tema.objects.create( nazev=nazev, stav=Problem.STAV_ZADANY, zamereni="M", autor=rnd.choice(organizatori), garant=rnd.choice(organizatori), kod=str(kod), tema_typ=rnd.choice(Tema.TEMA_CHOICES)[0], rocnik=rocnik, abstrakt=lorem.paragraph() ) # Generování struktury k tématu cisla = sorted(rocnik.cisla.all(), key=lambda c: c.poradi) for cislo in cisla: # Přidáme TemaVCisleNode do daného čísla cislo_node = cislo.cislonode tema_cislo_node = TemaVCisleNode.objects.create( tema=tema, root=cislo_node.root, ) insert_last_child(cislo_node, tema_cislo_node) # Přidávání obsahu do čísla cast_node = CastNode.objects.create( nadpis="Příspěvek k číslu {}".format(cislo.kod), root=cislo_node.root, ) add_first_child(tema_cislo_node, cast_node) text_node = TextNode.objects.create(text=get_text(), root=cislo_node.root) add_first_child(cast_node, text_node) cast_node2 = CastNode.objects.create( nadpis="První podproblém", root=cislo_node.root, ) add_first_child(text_node, cast_node2) text_node2 = TextNode.objects.create(text=get_text(), root=cislo_node.root) add_first_child(cast_node2, text_node2) cast_node3 = CastNode.objects.create( nadpis="Druhý podproblém", root=cislo_node.root, ) add_first_child(text_node2, cast_node3) text_node3 = TextNode.objects.create(text=get_text(), root=cislo_node.root) add_first_child(cast_node3, text_node3) cast_node4 = CastNode.objects.create( nadpis="Třetí podproblém", root=cislo_node.root, ) add_first_child(text_node3, cast_node4) text_node4 = TextNode.objects.create(text=get_text(), root=cislo_node.root) add_first_child(cast_node3, text_node4) cast_node3a = CastNode.objects.create( nadpis="Podproblém paralelní s druhým podproblémem", root=cislo_node.root, ) cast_node3.succ = cast_node3a cast_node3.save() text_node3a = TextNode.objects.create(text=get_text(), root=cislo_node.root) add_first_child(cast_node3a, text_node3a) # Občas přidáme mezičíslo if rnd.randint(1, 3) == 1: create_node_after(cislo_node, MezicisloNode, root=cislo_node.root) mezicislo_node = cislo_node.succ cast_node_mezicislo = CastNode.objects.create( nadpis="Příspěvek k mezičíslu".format(cislo.kod), root=cislo_node.root, ) add_first_child(mezicislo_node, cast_node_mezicislo) odstavec = lorem.paragraph() text_mezicislo = Text.objects.create(na_web=odstavec, do_cisla=odstavec) text_node_mezicislo = TextNode.objects.create( text=text_mezicislo, root=cislo_node.root, ) add_first_child(cast_node_mezicislo, text_node_mezicislo) return tema def gen_temata(rnd, rocniky, rocnik_cisla, organizatori): logger.info('Generuji témata...') jake = ["Hravé", "Fyzikální", "Nejlepší", "Totálně masakrální", "Šokující", "Magnetické", "Modré", "Překvapivé", "Plasmatické", "Novoroční"] co = ["téma", "záření", "stavení", "jiskření", "jelito", "drama", "kuře", "moře", "klání", "proudění", "čekání"] poc_oboru = rnd.randint(1, 2) rocnik_temata = [] # Věříme, že rocnik_cisla je pole polí čísel podle ročníků, tak si necháme dát # vždycky jeden ročník a k němu příslušná čísla. for rocnik, cisla in zip(rocniky, rocnik_cisla): kod = 1 letosni_temata = [] # Do každého ročníku vymyslíme tři (zatím) témata, v každém z prvních čísel jedno for zacatek_tematu in range(1, 3): # Vygenerujeme téma t = Tema.objects.create( # atributy třídy Problem nazev=" ".join([rnd.choice(jake), rnd.choice(co)]), stav=Problem.STAV_ZADANY, zamereni=rnd.sample(["M", "F", "I", "O", "B"], poc_oboru), autor=rnd.choice(organizatori), garant=rnd.choice(organizatori), kod=str(kod), # atributy třídy Téma tema_typ=rnd.choice(Tema.TEMA_CHOICES)[0], rocnik=rocnik, abstrakt="Abstrakt tematka {}".format(kod) ) kod += 1 # Vymyslíme, kdy skončí konec_tematu = min(rnd.randint(zacatek_tematu, 7), len(cisla)) # Vyrobíme TemaVCisleNody pro obsah for i in range(zacatek_tematu, konec_tematu+1): node = TemaVCisleNode.objects.create(tema=t, root=rocnik.rocniknode) # FIXME: Není to off-by-one? otec = cisla[i-1].cislonode otec_syn(otec, node) # Vymyslíme, kdo to bude opravovat poc_opravovatelu = rnd.randint(1, 3) t.opravovatele.set(rnd.sample(organizatori, poc_opravovatelu)) # Uložíme všechno t.save() letosni_temata.append((zacatek_tematu, konec_tematu, t)) rocnik_temata.append(letosni_temata) return rocnik_temata def gen_ulohy_tematu(rnd, organizatori, resitele, tema, kod, cislo, cislo_se_vzorakem): """ Generování úlohy k danému tématu. """ # Proměnné pro náhodné generování názvů a zadání. jaka = ["Šachová", "Černá", "Větrná", "Dlouhá", "Křehká", "Rychlá", "Zákeřná", "Fyzikální"] co = ["kostka", "smršť", "díra", "zrada", "toulka", "tyč", "úloha", "blecha"] sloveso = ["Najděte", "Spočítejte", "Zapište", "Změřte", "Odhadněte"] koho = ["délku", "počet", "množství", "dílky"] ceho = ["všech", "správných", "konstatních", "zelených"] jmeno = ["řešení", "tahů", "čísel", "kalhot", "koulí", "hadů"] kde = ["na zemi", "ve vesmíru", "ve vzduchu", "na šňůře", "v letadle"] obory = ["M", "F", "I", "O", "B"] uloha = Uloha.objects.create( nazev=": ".join([tema.nazev, "úloha {}.".format(kod)]), nadproblem=tema, stav=Problem.STAV_ZADANY, zamereni=tema.zamereni, autor=tema.autor, garant=tema.garant, kod=str(kod), cislo_zadani=cislo, cislo_reseni=cislo_se_vzorakem, cislo_deadline=cislo_se_vzorakem, max_body=rnd.randint(1, 8) ) # Samotný obsah následně vzniklého Textu zadání obsah = " ".join([ rnd.choice(sloveso), rnd.choice(koho), rnd.choice(ceho), rnd.choice(jmeno), rnd.choice(kde), ]) text_zadani = Text.objects.create( na_web=obsah, do_cisla=obsah, ) zad = TextNode.objects.create( text=text_zadani, root=tema.temavcislenode_set.first().root, ) uloha_zadani = UlohaZadaniNode.objects.create( uloha=uloha, first_child=zad, root=tema.temavcislenode_set.first().root, ) uloha.ulohazadaninode = uloha_zadani # Generování řešení a hodnocení k úloze gen_reseni_ulohy( rnd, [cislo], uloha, len(resitele)//4, 1, resitele, resitele, ) return uloha, uloha_zadani def gen_ulohy_k_tematum(rnd, rocniky, rocnik_cisla, rocnik_temata, organizatori, resitele): logger.info('Generuji úlohy k tématům...') # Ke každému ročníku si vezmeme příslušná čísla a témata for rocnik, cisla, temata in zip(rocniky, rocnik_cisla, rocnik_temata): # Do každého čísla nagenerujeme ke každému témátku pár úložek for cislo in cisla: print("Generuji úložky do {}-tého čísla".format(cislo.poradi)) # Vzorák bude o dvě čísla dál cislo_se_vzorakem = Cislo.objects.filter( rocnik=rocnik, poradi=str(int(cislo.poradi) + 2), ) # Pokud není číslo pro vzorák, tak se dá do posledního čísla # (i kdyby tam mělo být zadání i řešení...) # Tohle sice umožňuje vygenerovat vzorák do čísla dávno po konci témátka, # ale to nám pro jednoduchost nevadí. if len(cislo_se_vzorakem) == 0: cislo_se_vzorakem = cisla[-1] else: cislo_se_vzorakem = cislo_se_vzorakem.first() for tema_node in all_children_of_type(cislo.cislonode, TemaVCisleNode): tema = tema_node.tema # Pokud už témátko skončilo, žádné úložky negenerujeme # FIXME: Bylo by hezčí, kdyby se čísla předávala jako Cislo a ne # jako int v té trojici (start, konec, tema) if not temata[int(tema.kod)-1][1] >= int(cislo_se_vzorakem.poradi): continue # Generujeme 1 až 4 úložky k tomuto témátku do tohoto čísla. for kod in range(1, rnd.randint(1, 4)): u, uz = gen_ulohy_tematu( rnd, organizatori, resitele, tema, kod, cislo, cislo_se_vzorakem, ) insert_last_child(tema_node, uz) poc_op = rnd.randint(1, 4) uvz = gen_vzoroveho_reseni_ulohy( rnd, organizatori, u, poc_op, ) # Najdeme správný TemaVCisleNode pro vložení vzoráku res_tema_node = None for node in all_children(cislo_se_vzorakem.cislonode): if isinstance(node, TemaVCisleNode): if node.tema == tema: res_tema_node = node if res_tema_node is None: raise LookupError("Nenalezen Node pro vložení vzoráku") insert_last_child(res_tema_node, uvz) u.save() return def gen_clanek(rnd, organizatori, resitele): logger.info("Generuji článek do čísla 22.2") clanek = Clanek.objects.create( nazev="Článek o Lorem ipsum", nadproblem=None, stav='vyreseny', zamereni=['I'], garant=rnd.choice(organizatori), kod='cl', ) clanek.save() reseni = Reseni.objects.create( zverejneno=True, ) reseni.resitele.add(rnd.choice(resitele)) reseni.save() cislo = Cislo.objects.get(rocnik__rocnik=22, poradi=2) cislonode = cislo.cislonode hodnoceni = Hodnoceni.objects.create( body=15.0, cislo_body=cislo, reseni=reseni, problem=clanek, ) hodnoceni.save() reseninode = ReseniNode.objects.create( reseni=reseni ) reseninode.save() # Bude to celý text reseni.text_cely = reseninode reseni.save() from treenode.treelib import insert_last_child, create_child insert_last_child(cislonode, reseninode) # Vyrobíme nějaký obsah # FIXME: Ten, kdo vymyslel TreeLib (mj. týž, kdo psal tenhle kód), # nevyrobil vhodnou funkci, takže to postavíme pozpátku pomocí create_child # (které vyrábí _prvního_ syna) create_child(reseninode, CastNode, nadpis="Lorem ipsum") # Taky ten člověk nevyrobil vracení nových věcí... castnode = reseninode.first_child # Úvodní odstaveček obsah = "Tohle je zamyšlení o textu lorem ipsum. Začneme a skončíme ukázkou." text = Text.objects.create( na_web=obsah, do_cisla=obsah, ) text.save() create_child(reseninode, TextNode, text=text) # Několik odstavců lorem ipsum for _ in range(rnd.randint(3, 7)): lipsum = lorem.paragraph() text = Text.objects.create( na_web=lipsum, do_cisla=lipsum, ) text.save() create_child(castnode, TextNode, text=text) logger.info(f"Článek vygenerován (reseni={reseni.id}, treenode={reseninode.id})")