# FIXME vypreparovat treenode import datetime import lorem import django.contrib.auth import logging from .models import Rocnik, Cislo, Deadline, Problem, Tema, Uloha, Clanek from odevzdavatko.models import Reseni, Hodnoceni # TODO zbavit se treenodů do treenode.testutils (ty pak klidně volat odtud) from treenode.models import TextNode, UlohaZadaniNode, UlohaVzorakNode, RocnikNode, CisloNode, TemaVCisleNode, CastNode, MezicisloNode, ReseniNode from treenode.models import Text 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__) User = django.contrib.auth.get_user_model() 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 add_first_child(node, child): node.first_child = child node.save() return def get_text(): odstavec = lorem.paragraph() return Text.objects.create(na_web = odstavec, do_cisla = odstavec) 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 cislo: cislo.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 otec_syn(otec, syn): bratr = otec.first_child syn.succ = bratr otec.first_child = syn syn.save() otec.save() 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})")