from random import random from typing import Iterable from django.conf import settings from django.db import models from django.db.models import QuerySet from django.utils import timezone from .utils.doba import Doba class Stanoviste(models.Model): class Meta: db_table = "hra_stanoviste" verbose_name = "Stanoviště" verbose_name_plural = "Stanoviště" user = models.OneToOneField( settings.AUTH_USER_MODEL, blank=False, null=False, unique=True, verbose_name="uživatel", on_delete=models.PROTECT, help_text="Stanoviště musí být přihlášena, aby se nedala přepínat stanoviště", ) nazev = models.CharField( "název", max_length=256, blank=False, null=False, help_text="zobrazovaný název stanoviště", ) verejny_text = models.TextField( "veřejný text", max_length=256, blank=False, null=False, help_text="zobrazovaný název stanoviště", ) poradi = models.IntegerField( "pořadí", blank=False, null=False, help_text="číselné označení stanoviště (aby hráči věděli, že našli všechny)", ) template = models.CharField( "template", max_length=256, blank=False, null=False, default="base.html", help_text="template tohoto stanoviště (co vidí tým)", ) class Tym(models.Model): class Meta: db_table = "hra_tym" verbose_name = "Tým" verbose_name_plural = "Týmy" user = models.OneToOneField( settings.AUTH_USER_MODEL, blank=False, null=False, unique=True, verbose_name="uživatel", on_delete=models.PROTECT, ) nazev = models.CharField( "název týmu", max_length=256, blank=False, null=False, ) hraci = models.CharField( "hráči", max_length=256, blank=True, null=True, help_text="seznam hráčů v týmu", ) start = models.DateTimeField( "začátek hry", blank=False, null=False, default=timezone.now, help_text="čas, kdy tým začal", ) delta = models.FloatField( "přidaný čas", blank=False, null=False, default=0, help_text="čas (v hodinách), o který se tým posunul svými akcemi", ) def nastav_a_uloz(self, attr_name: str, value: object) -> "Tym": self.__setattr__(attr_name, value) self.save() return self @property def doba(self) -> Doba: return Doba((timezone.now() - self.start).total_seconds() / 60 * settings.TIME_SPEED + self.delta) def pricti_cas_a_uloz(self, cas: int) -> "Tym": self.delta += cas self.save() return self # Inventář tk_nalezena = models.FloatField( "čas nalezení třídní knihy", blank=True, null=True, default=None, help_text="čas (v hodinách), kdy tým nalezl třídní knihu (pro pořadí a rozhodnutí, zda ji tým už nalezl)", ) ma_penize = models.BooleanField( "má tým peníze", blank=False, null=False, default=False, help_text="zda si tým vzal peníze a neztratil je", ) ds_bad = models.FloatField( "čas chybného založení ds", blank=True, null=True, default=None, help_text="čas, kdy tým špatným způsobem požádal o datovou schránku", ) ma_ds = models.BooleanField( "má tým ds", blank=False, null=False, default=False, help_text="zda si tým založil datovou schránku", ) pocet_bananu = models.IntegerField( "počet banánů", blank=False, null=False, default=0, help_text="kolik vlastní tým bánánů", ) vi_o_zadosti = models.BooleanField( "ví tým o finální žádosti", blank=False, null=False, default=False, help_text="ví tým o tom, že potřebuje žádost o náhled do archivů", ) vi_o_mesici = models.BooleanField( "ví tým o svitu měsíce", blank=False, null=False, default=False, help_text="ví tým o tom, že žádost o náhled do archivů se může podávat pouze za svitu měsíce", ) vi_o_mase = models.BooleanField( "ví o tom, že v jídelně už není banán", blank=False, null=False, default=False, help_text="už se ptali v jídelně na další banán a zjistili, že je jen MaSo", ) @property def vyzvednute_zadosti(self) -> QuerySet["Zadost"]: return self.zadosti.filter(vyzvednuta=True) @property def vytistene_zadosti(self) -> QuerySet["Zadost"]: return self.zadosti.filter(vytistena=True) @property def nevyzvednute_zadosti(self) -> QuerySet["Zadost"]: return self.zadosti.filter(studijni__isnull=False, vyzvednuta=False) def ma_platnou_zadost(self, zadost_typ: str) -> bool: return self.vyzvednute_zadosti.filter(typ=zadost_typ, plati=True).count() > 0 @property def ma_platnou_zadost_o_banan(self) -> bool: """ Protože django templates jsou hloupé """ return self.vyzvednute_zadosti.filter(typ=Zadost.TYP_BANAN, plati=True).count() > 0 @property def ma_platnou_zadost_o_vege(self) -> bool: """ Protože django templates jsou hloupé """ return self.vyzvednute_zadosti.filter(typ=Zadost.TYP_VEGE, plati=True).count() > 0 def zadosti_na_internatu(self, doba: Doba) -> QuerySet["Zadost"]: return self.zadosti.filter(vyzvednuta=False, internat__isnull=False, internat__lte=doba) def zadosti_na_poste(self, doba: Doba) -> QuerySet["Zadost"]: return self.zadosti.filter(posta__isnull=False, posta__lte=doba, internat__isnull=False, internat__gt=doba) @staticmethod def studijni_otevreno_nejdrive(doba: Doba) -> Doba: if not ( # copy-paste z logika.py doba.cas < 8 or doba.cas > 15 or doba.den_v_tydnu >= 6 or (doba.den_v_tydnu == 5 and doba.cas > 13) ): return doba if doba.cas > 15 or (doba.den_v_tydnu == 5 and doba.cas > 13): doba += Doba.DEN - doba.cas + 8 else: doba = Doba(doba.den*Doba.DEN + 8) if doba.den_v_tydnu == 6: doba += 2*Doba.DEN elif doba.den_v_tydnu == 7: doba += Doba.DEN return doba @staticmethod def doruceni(doba: Doba) -> Doba: doba += Doba.DEN - doba.cas + 8 while True: if doba.den_v_tydnu == 6 or doba.den_v_tydnu == 7: doba += Doba.DEN else: if random() > 1/3: doba += Doba.DEN else: return doba @staticmethod def postovna(studijni: Doba) -> Doba: return (studijni.den + (settings.POSTOVNA_DEN_V_TYDNU - studijni.den_v_tydnu + 7) % 7) * Doba.DEN + 10 def poslat_vytistene_zadosti(self, doba: Doba) -> Iterable["Zadost"]: if not self.ma_penize: return () self.ma_penize = False self.save() zadosti = self.zadosti.filter(vytistena=True) for zadost in zadosti: zadost.vytistena = False studijni = self.doruceni(doba) zadost.studijni = studijni posta = Doba((studijni.den + (settings.POSTOVNA_DEN_V_TYDNU - studijni.den_v_tydnu + 7) % 7) * Doba.DEN + 10) zadost.posta = posta zadost.internat = self.doruceni(posta) if zadost.typ == Zadost.TYP_TK: zadost.plati = Zadost.plati_tk(doba) if zadost.typ == Zadost.TYP_ZADOST: zadost.plati = False zadost.save() return zadosti def vytiskni_zadost(self, typ: str) -> tuple["Zadost"]: return (Zadost.objects.create(tym=self, typ=typ, vytistena=True,),) def posli_zadost_ds(self, doba: Doba, typ: str) -> tuple["Zadost"]: studijni = doba internat = self.studijni_otevreno_nejdrive(doba) if typ == Zadost.TYP_TK: return (Zadost.objects.create(tym=self, typ=typ, studijni=studijni, internat=internat, plati=Zadost.plati_tk(doba)),) return (Zadost.objects.create( tym=self, typ=typ, studijni=studijni, internat=internat, plati=typ != Zadost.TYP_ZADOST, ),) def vyzvedni_internat(self, doba: Doba) -> Iterable["Zadost"]: zadosti = self.zadosti_na_internatu(doba) for zadost in zadosti: zadost.vyzvednuta = True zadost.save() if zadost.typ == Zadost.TYP_TK: self.vi_o_mesici = True self.save() return zadosti def vyzvedni_postu(self, doba: Doba) -> Iterable["Zadost"]: zadosti = self.zadosti_na_poste(doba) for zadost in zadosti: zadost.vyzvednuta = True zadost.save() if zadost.typ == Zadost.TYP_TK: self.vi_o_mesici = True self.save() return zadosti def posli_zadost_studijni(self, doba: Doba, typ: str) -> tuple["Zadost"]: studijni = doba posta = self.postovna(studijni) internat = self.doruceni(doba) return (Zadost.objects.create( tym=self, typ=typ, studijni=studijni, posta=posta, internat=internat, plati=typ != Zadost.TYP_TK and typ != Zadost.TYP_ZADOST, ),) ovesna_kase = models.IntegerField( blank=False, null=False, default=0, ) class Zadost(models.Model): class Meta: db_table = "hra_zadost" verbose_name = "Žádost" verbose_name_plural = "Žádosti" tym = models.ForeignKey(Tym, related_name="zadosti", blank=False, null=False, on_delete=models.CASCADE) TYP_ZADOST = "zadost" TYP_BANAN = "banan" TYP_VEGE = "vege" # TYP_BAD_TK = "bad_tk" TYP_TK = "tk" TYP_CHOICES = [ (TYP_ZADOST, "Žádost"), (TYP_BANAN, "Žádost o banán"), (TYP_VEGE, "Žádost o více vegetariánskou stravu v jídelně"), # (TYP_BAD_TK, "Neplatná žádost o přístup k záznamům o třídní knize"), (TYP_TK, "Žádost o přístup k záznamům o třídní knize"), ] typ = models.CharField( "toto je ", max_length=8, blank=False, null=False, choices=TYP_CHOICES, ) studijni = models.FloatField( "žádost dorazí na studijní", blank=True, null=True, default=None, ) posta = models.FloatField( "tým si může žádost vyzvednout na internátu od", blank=True, null=True, default=None, help_text="(do self.internat)", ) internat = models.FloatField( "tým si může žádost vyzvednout na poště od", blank=True, null=True, default=None, ) vyzvednuta = models.BooleanField( "tým si tuto žádost již vyzvedl", blank=False, null=False, default=False, ) vytistena = models.BooleanField( "tým má u sebe tuto žádost vytištěnou", blank=False, null=False, default=False, ) plati = models.BooleanField( "tato žádost platí", blank=False, null=False, default=True, help_text="Aktuálně má uplatnění pouze u Žádosti o přístup k záznamům o třídní knize", ) @staticmethod def plati_tk(doba: Doba) -> bool: return ( not doba.je_nov and doba.je_noc and doba.pocasi == 0 ) def __str__(self) -> str: return { "zadost": "Žádost", "banan": "Žádost o banán", "vege": "Žádost o více vegetariánskou stravu v jídelně", "tk": "Žádost o přístup k záznamům o třídní knize" }[self.typ]