Reguły symulacji

Dokumentacja wszystkich reguł zachowania mieszkańców.


1. Architektura — DES (Discrete Event Simulation)

Symulator nie iteruje po sekundach, lecz przeskakuje do momentów gdy „coś się dzieje". Dzięki temu na nowoczesnym sprzęcie jest w stanie symulować aktywność nawet dziesiątek milionów osób.

  • Każda osoba ma w schedulerze dokładnie 1 oczekujące zdarzenie w formie: _„O czasie T osoba P zaczyna aktywność A"_.
  • Gdy zdarzenie odpala się (T ≤ sim_time):

1. oblicz czas trwania A → czas_końca = T + duration(A) 2. oblicz następną aktywność B = next_activity(A) 3. zapisz do logu: {T, czas_końca, osoba, A, origin, dest} 4. zaktualizuj stan osoby 5. wstaw do schedulera: "O czas_końca osoba zaczyna B"

  • Łańcuch jest samo-zasilający się i nigdy się nie urywa.

1a. Dni tygodnia — weekendy

day_of_week(d) zwraca 0=pon … 5=sob, 6=ndz na podstawie wzoru (d/86400 + 3) % 7.

W soboty i niedziele aktywny jest oddzielny harmonogram weekendowy (patrz sekcja 15). Godziny pobudki i śniadania są takie same jak w dni robocze.


2. Deterministyczna pseudolosowość

prand(person_id, day_epoch, salt)

Zwraca uint32_t z dobrym rozkładem. Algorytm: XOR-Shift Hash z mnożeniem przez stałe Knutha.

  • Nie ma globalnego stanu → bezpieczne wątkowo.
  • Ta sama kombinacja (person_id, day_epoch, salt) zawsze daje ten sam wynik → powtarzalność dla tego samego seeda.
  • day_epoch = timestamp początku dnia (00:00:00 UTC), różnicuje tę samą osobę w różnych dniach.
  • salt rozróżnia różne zastosowania tej samej osoby tego samego dnia (np. salt=0: godzina wstania, salt=2: czas śniadania).

variance(person_id, day, salt, range)

Zwraca losowe odchylenie z przedziału [-range, +range] sekund. Używane wszędzie tam, gdzie do czasu bazowego dodawana jest wariacja.


3. Godziny wstania

Status osobyBazowa godzina wstaniaWariacja
Pracujący (STATUS_EMPLOYED)6:30±30 min
Uczeń (STATUS_STUDENT)7:00±30 min
Student wyższej uczelni (STATUS_HIGHER_EDU)7:00±30 min
Dziecko (STATUS_CHILD)7:30±30 min
Bezrobotny (STATUS_UNEMPLOYED)8:00±30 min
Emeryt (STATUS_RETIRED)8:00±30 min

Wariacja używa salt=0. Wynik to sekundy od północy — może przekroczyć 24h, co jest obsługiwane w activity_duration(EVT_SLEEP).


4. Maszyna stanów — harmonogram dnia

4.1 Rytm poranny (wszyscy)

SLEEP → [MORNING_SEX →] WAKEUP → BREAKFAST → (patrz 4.2–4.4)

MORNING_SEX jest opcjonalnym krokiem przed WAKEUP. Warunki wystąpienia:

  • Para kohabitująca (partner w tym samym lokalu, home_unit_id identyczne)
  • Wiek mężczyzny: 20–35 lat
  • Oboje należą do tej samej grupy godzin wstania (patrz tabela poniżej)
  • Prawdopodobieństwo: 15% dziennie

Grupy godzin wstania (same_wakeup_group):

GrupaStatusyGodzina bazowa
0EMPLOYED6:30
1STUDENT, HIGHER_EDU7:00
2CHILD7:30
3UNEMPLOYED, RETIRED8:00

Symetria: decyzja opiera się na shared_id = min(A.id, B.id) i salt 77 — oboje obliczają identyczną wartość prand(), więc albo oboje wchodzą w zdarzenie, albo żadne.

Czas trwania: 5–15 minut (M(5) + prand(id, dzien, 78) % (M(10)+1)). Lokalizacja: home_unit_id (własny lokal). Następna aktywność: EVT_WAKEUP.

4.2 Ścieżka pracującego

BREAKFAST → COMMUTE_TO_WORK → WORK_* → WORK_BREAK → WORK_* → COMMUTE_FROM_WORK
          → (80%) HOME_REST / (20%) GROCERY_SHOPPING → HOME_REST → ...
  • Po przyjeździe do pracy typ aktywności zależy od typu organizacji pracodawcy:
Typ budynku pracodawcyAktywność
BTYPE_INDUSTRIALEVT_WORK_FACTORY
BTYPE_SHOP_GROCERY, BTYPE_SHOP_OTHEREVT_WORK_SHOP
BTYPE_SERVICE, BTYPE_MEDICALEVT_WORK_SERVICE
PozostałeEVT_WORK_OFFICE
  • Pierwszy blok pracy kończy się przed 12:00 → następuje przerwa (EVT_WORK_BREAK).
  • Drugi blok pracy kończy się po 12:00 → następuje powrót do domu (EVT_COMMUTE_FROM_WORK).
  • Po powrocie z pracy: 20% szans na zakupy (EVT_GROCERY_SHOPPING), reszta → EVT_HOME_REST. Decyduje prand(id, dzien, salt=20) % 5 == 0.

4.3 Ścieżka ucznia / studenta

BREAKFAST → COMMUTE_TO_SCHOOL → SCHOOL_CLASS/UNIVERSITY_CLASS
          → SCHOOL_BREAK → SCHOOL_CLASS → COMMUTE_FROM_SCHOOL → HOME_LEARNING → HOME_REST → ...
  • Student wyższej uczelni (STATUS_HIGHER_EDU) → EVT_UNIVERSITY_CLASS zamiast EVT_SCHOOL_CLASS.
  • Przerwa szkolna odpala się przed 11:00 (dla uczniów) lub przed 12:00 (dla studentów).
  • Po powrocie ze szkoły: zawsze EVT_HOME_LEARNING (odrabianie lekcji) → potem EVT_HOME_REST.

4.4 Ścieżka dzieci, bezrobotnych, emerytów

BREAKFAST → HOME_REST → (wieczorem) DINNER → WATCH_TV (em./bezr.) lub HOME_REST → FALLING_ASLEEP → SLEEP

4.5 Wieczorny rytm (wszyscy)

HOME_REST → DINNER → HOME_REST (lub WATCH_TV) → FALLING_ASLEEP → SLEEP
  • Emeryci i bezrobotni: zawsze EVT_WATCH_TV. Pozostali (pracujący, studenci, dzieci w wieku ≥ 12 lat): 65% → EVT_WATCH_TV, 35% → EVT_HOME_REST (salt=79).
  • EVT_FALLING_ASLEEP trwa stałe 20 minut, potem EVT_SLEEP.

5. Czasy trwania aktywności

AktywnośćCzas bazowyWariacjaSalt
EVT_WAKEUP15 min±5 min1
EVT_BREAKFAST30 min±10 min2
EVT_WORK_OFFICE/FACTORY/SHOP/SERVICE4 h±20 min4
EVT_WORK_BREAK45 min±10 min5
EVT_SCHOOL_CLASS2 h 30 min±15 min6
EVT_SCHOOL_BREAK15 min——
EVT_UNIVERSITY_CLASS2 h±15 min7
EVT_HOME_LEARNING2 h±30 min8
EVT_GROCERY_SHOPPING30 min±10 min9
EVT_DINNER45 min±10 min10
EVT_FALLING_ASLEEP20 min——

Dojazdy

Czas dojazdu oblicza travel_time(miasto, unit_A, unit_B) — na podstawie odległości euklidesowej między lokalami. Minimum: 3 min, maksimum: 60 min.

Sen (EVT_SLEEP)

Trwa od t do następnej godziny wstania:

  • Jeśli godzina wstania jest jeszcze dziś → czas_wstania_dzis - t.
  • Jeśli godzina wstania już minęła → czas_wstania_jutro - t.

HOME_REST

Czas do najwcześniejszego z:

  • godziny kolacji: 18:00 ± 30 min (salt=11)
  • godziny snu: 22:30 ± 30 min (salt=12)
  • jeśli obie minęły: 5 minut

Jeśli osoba ma zaplanowane spotkanie (plans[id].meet_time > 0):

  • PLAN_COHABIT / PLAN_HOST: czekamy do meet_time (skrócenie jeśli krótsze od normalnego).
  • PLAN_GUEST: wychodzimy wcześniej o czas dojazdu do lokalu partnera.

WATCH_TV

Trwa do godziny snu (22:30 ± 30 min, salt=13). Jeśli poza planem snu → 5 minut. Skracane do meet_time jeśli jest plan spotkania.


6. Seks — czas trwania

Czas trwania zależy od wieku i charakteru relacji.

WiekZ partnerem / kochankąZ małżonkiem (REL_SPOUSE)
< 30 lat30–45 min25–40 min
30–39 lat25–35 min20–30 min
40–49 lat20–30 min15–25 min
50–59 lat15–25 min10–20 min
≥ 60 lat10–20 min5–15 min

Reguły kwalifikacji:

  • EVT_SEX_HOME + rel_type == REL_SPOUSE → czas z małżonkiem.
  • EVT_SEX_AWAY → zawsze czas z partnerem / kochanką (niezależnie od rel_type).
  • EVT_SEX_HOME + inne rel_type → czas z partnerem.

Salty: 30 (SEX_HOME), 31 (SEX_AWAY), 32 (SEX_HOST), 33 (SEX_GUEST). EVT_SEX_HOST i EVT_SEX_GUEST używają tych samych przedziałów co SEX_HOME/AWAY.


7. Planowanie dziennych spotkań (plan_daily_meeting)

Wywoływane przy EVT_WAKEUP. Planuje spotkanie seksualne na dany dzień.

7.1 Wybór partnera

  1. Romans (affair_partner_id != 0) ma priorytet przed stałym partnerem.
  2. Fallback: stały partner (partner_id).
  3. Brak partnera → brak planu.

7.2 Rola: COHABIT / HOST / GUEST / AWAY

  • COHABIT: oboje mieszkają pod tym samym adresem (home_unit_id identyczne) i brak romansu.
  • HOST / GUEST (inny dom lub romans):
  • Jeśli kobieta jest uczennicą/studentką → mężczyzna zawsze gospodarzem (PLAN_HOST).
  • W pozostałych przypadkach: losowo wg prand(min(A.id, B.id), d, salt=43) % 2.
  • AWAY (hotel/klub) — nadpisuje HOST/GUEST w dwóch scenariuszach (patrz 7.6).

7.3 Wspólny seed

Oboje partnerzy niezależnie obliczają plan. Używają shared_id = min(osoba->id, partner->id), dzięki czemu wyliczają identyczny meet_time i meet_loc bez żadnej komunikacji.

7.4 Czas spotkania — reguły wg statusu mężczyzny w parze

WarunekPrzedział czasu
Mężczyzna: uczeń/student < 24 lat11:00–17:00
Mężczyzna: uczeń/student ≥ 24 lat14:00–22:00
Romans + mężczyzna żonaty (REL_SPOUSE)17:00–22:00
Mężczyzna żonaty (spotkanie z żoną)20:00–23:00
Pozostałe19:00–22:00

Czas dokładny: d + meet_start + prand(shared_id, d, salt=44) % meet_range.

7.5 Lokal spotkania

  • COHABIT: własny dom (home_unit_id inicjatora).
  • HOST: własny dom gospodarza.
  • GUEST: dom gospodarza (meet_loc = gospodarz->home_unit_id).
  • AWAY: meet_loc = 0 (placeholder; docelowo id hotelu/klubu).

7.6 Seks w hotelu/klubie (PLAN_AWAY / EVT_SEX_AWAY)

Oboje partnerzy wyjeżdżają do miejsca neutralnego i wracają zaraz po seksie (nigdy nie nocują).

Scenariusz A — romans między małżonkami: romans (is_affair == 1), oboje mają współmałżonka i z nim mieszkają (rel_type == REL_SPOUSE + home_unit_id == partner_home). Dom żadnej ze stron nie jest dostępny → hotel obowiązkowy.

Scenariusz B — casual dating młodych: brak romansu, oboje < 26 lat, rel_type == REL_NONE u obojga. Prawdopodobieństwo hotelu: 25% pn–pt, 50% sob–ndz (prand(shared_id, d, salt=62) % 100). Jeśli nie wylosowano hotelu → standardowy HOST/GUEST.

Łańcuch stanów dla każdej strony:

HOME_REST → EVT_TRAVEL_TO_PARTNER → EVT_SEX_AWAY → EVT_MORNING_RETURN → EVT_HOME_REST

Czas trwania EVT_TRAVEL_TO_PARTNER: travel_time(home, meet_loc=0) = MIN_TRAVEL_SECS = 3 min (placeholder).


8. Synchronizacja COHABIT (force_cohabit_sex)

Gdy osoba A z rolą PLAN_COHABIT wchodzi w EVT_SEX_HOME, partner B może być jeszcze w innej aktywności. Zamiast czekać aż B sam dojdzie do meet_time, wymuszamy B natychmiast.

Mechanizm stale event:

  1. Inkrementujemy partner->sched_gen.
  2. Stare zdarzenie B w schedulerze (z poprzednim gen) zostanie pominięte.
  3. Wstawiamy nowe EVT_HOME_REST dla B z czas_konca identycznym jak A.

Dzięki temu oboje kończą seks jednocześnie → act_count[EVT_SEX_HOME] jest zawsze parzyste.

Wyjątek: jeśli B jest aktualnie w EVT_SEX_HOST, EVT_SEX_GUEST lub EVT_WAIT_FOR_PARTNER (romansuje) → nie przerywamy.


9. Stale event detection

Każda osoba ma pole sched_gen (licznik generacji). Każde zdarzenie w schedulerze niesie ze sobą gen wstawionego zdarzenia.

W sim_process_event(): jeśli item->gen != osoba->sched_gen → zdarzenie jest stale i jest pomijane.

Używane wyłącznie przez force_cohabit_sex() do unieważnienia starych zdarzeń partnera.


10. Zakończenie seksu jako gość

Po EVT_SEX_GUEST (seks u partnera w jego domu):

  • 80%: EVT_STAY_OVERNIGHT → nocuje → rano EVT_MORNING_RETURN → EVT_HOME_REST.
  • 20%: EVT_MORNING_RETURN od razu → EVT_HOME_REST.

Decyduje prand(id, dzien, salt=50) % 5 < 4.


11. Ochrona przed romansem partnera (sprawdzenie planu)

W next_activity(EVT_HOME_REST) i next_activity(EVT_WATCH_TV) dla PLAN_COHABIT, przed wejściem w EVT_SEX_HOME sprawdzamy:

  1. Czy partner jest aktualnie w aktywności seksualnej (EVT_SEX_HOST, EVT_SEX_GUEST, EVT_WAIT_FOR_PARTNER) → pomiń.
  2. Czy partner ma romans zaplanowany na dziś (plans[partner.id].role == PLAN_HOST lub PLAN_GUEST z meet_time > 0) → pomiń.

Cel: uniknięcie sytuacji gdy A wchodzi w SEX_HOME z B, a B zaraz wejdzie w SEX z kimś trzecim (romans).


12. Czyszczenie planu po spotkaniu

Plan (plans[osoba->id].meet_time) jest zerowany gdy:

  • EVT_SEX_HOST odpala się (gospodarz zakończył seks),
  • EVT_SEX_HOME odpala się (współmieszkańcy zakończyli seks),
  • EVT_MORNING_RETURN odpala się (gość wrócił do domu).

13. Lokalizacja osoby podczas aktywności (LOC_STREET vs LOC_UNIT)

Osoba jest LOC_STREET (w drodze) podczas:

  • EVT_COMMUTE_TO_WORK
  • EVT_COMMUTE_FROM_WORK
  • EVT_COMMUTE_TO_SCHOOL
  • EVT_COMMUTE_FROM_SCHOOL
  • EVT_TRAVEL_TO_PARTNER
  • EVT_MORNING_RETURN

We wszystkich pozostałych aktywnościach: LOC_UNIT (w konkretnym lokalu).


14. Inicjalizacja (sim_init_all)

Na starcie dla każdej osoby:

  • Stan: śpi (EVT_SLEEP), jest w domu (LOC_UNIT, home_unit_id).
  • Obliczana jest godzina wstania na bieżący dzień.
  • Jeśli godzina wstania już minęła → planowane na jutro (+86400s).
  • Do schedulera wstawiane jest EVT_WAKEUP.

15. Harmonogram weekendowy

15.1 Obiad (sobota i niedziela)

  • Dotyczy par współmieszkających (home_unit_id identyczne, partner_id > 0).
  • Czas: losowo 13:00–15:00, synchronizowany przez shared_id = min(A.id, B.id) → oboje mają identyczny czas.
  • Salt=45. Aktywność: EVT_LUNCH (≈60 min ± 15 min, salt=14).
  • Dzieci nie dostają własnego zdarzenia obiadu — są w domu podczas HOME_REST.

15.2 Zakupy sobotnie

  • Dotyczy: kobiet (GENDER_FEMALE) powyżej 18 lat.
  • Prawdopodobieństwo: 70% (prand(id, d, 46) % 10 < 7).
  • Czas: losowo 9:00–13:00 (salt=47). Aktywność: EVT_GROCERY_SHOPPING.

15.3 Nauka domowa — niedziela

  • Dotyczy: dzieci i uczniów (STATUS_CHILD, STATUS_STUDENT).
  • Prawdopodobieństwo: 70% (salt=55).
  • Czas: losowo 10:00–12:00 (salt=56). Aktywność: EVT_HOME_LEARNING.

15.4 Seks sobotni (pary COHABIT)

Romanse (affair_partner_id > 0) mają priorytet i działają wg reguł weekday (HOST/GUEST), nie weekendowych.

Typ paryPrawdopob.SlotCzas
Bez dzieci (children_count == 0)90% (salt=48)Rano lub wieczór (50/50, salt=57)Rano: wakeup + 60–120 min; Wieczór: 16–23 (po kolacji)
Z dziećmi70% (salt=48)Tylko wieczór16–23 (po kolacji)

Rano: czas = wakeup_tod + M(60) + prand(58) % M(60), cappowany do shopping_time - M(30) (jeśli kobieta ma zakupy) lub do 12:00.

Wieczór: surowy czas 16:00–23:00 (salt=49) podnoszony do pora_kolacji + M(60), żeby kolacja zawsze była przed seksem. Max 22:30.

Flaga sat_sex_morning = 1 oznacza poranny slot.

15.5 Seks niedzielny (pary COHABIT)

  • Dotyczy: osoby ≥ 19 lat, które nie miały seksu w sobotę (sat_had_sex[id] == 0).
  • Prawdopodobieństwo: 80% (salt=59).
  • Czas: 16:00–23:00 (po kolacji, ta sama logika przesunięcia co sobota).

Flaga sat_had_sex[id]:

  • Reset przy EVT_WAKEUP w sobotę.
  • Set = 1 przy EVT_SEX_HOME w sobotę.
  • Czytana przy planowaniu niedzielnym.

15.6 Przepływ stanów weekendowych

WAKEUP → BREAKFAST →
  [sob, kobieta >18, 70%] → HOME_REST → GROCERY_SHOPPING →
  [sob/ndz, para] → HOME_REST → LUNCH →
  HOME_REST →
  [sob/ndz, seks wieczorny] → SEX_HOME →
  HOME_REST → DINNER → FALLING_ASLEEP → SLEEP

  [sob, para bez dzieci, seks rano] → HOME_REST → SEX_HOME →
  HOME_REST → (powyżej od GROCERY_SHOPPING)

  [ndz, dzieci, 70%] → HOME_REST → HOME_LEARNING →
  HOME_REST → LUNCH → ...

  [sob/ndz, single 18–40, klub] → HOME_REST → CLUB_NIGHT →
    [15%] → SEX_AWAY → HOME_REST → FALLING_ASLEEP
    [85%] → HOME_REST → FALLING_ASLEEP

15.7 Klub nocny — szukanie przygodnego seksu (EVT_CLUB_NIGHT = 410)

Modeluje sobotnie i niedzielne wyjścia singli do klubów nocnych w poszukiwaniu jednorazowego kontaktu seksualnego.

Podstawa empiryczna (Gorzów Wlkp.): Miasto ma ~5 aktywnych klubów nocnych (Klub Studio, Pub Wesele, Viva Disco, Ósemka, MIXcoolTURA). Klub Studio opisywany jako odwiedzany przez „setki osób co tydzień"; pojemność większych lokali do ~500 os. Łączna frekwencja w sobotni wieczór: szacunkowo 1 500–2 500 os. Z tego ~20–30% aktywnie szuka przygody seksualnej. Źródło: [baza.mgbi.pl](https://baza.mgbi.pl/katalog/baza/baza-firm-gorzow-wielkopolski) + lokalne materiały prasowe (marzec 2026).

Kto uczestniczy:

  • Status: dowolny (poza dziećmi — wiek ≥ 18)
  • Wiek: 18–40 lat
  • Relacja: brak stałego partnera (partner_id == 0) i brak romansu (affair_partner_id == 0)
  • Dotyczy soboty i niedzieli

Prawdopodobieństwo wyjścia:

DzieńPrawdopob.Salt
Sobota8%64
Niedziela3%64

Godzina wyjścia:

  • Sobota: losowo 20:00–23:00 (salt=65)
  • Niedziela: losowo 20:00–22:00 (salt=65)

Zapisywane jako plan->meet_time, plan->role = PLAN_AWAY, plan->partner_id = 0, plan->meet_loc = 0. W next_home(): gdy plan->role == PLAN_AWAY && plan->partner_id == 0 → EVT_CLUB_NIGHT (zamiast EVT_TRAVEL_TO_PARTNER).

Czas trwania aktywności EVT_CLUB_NIGHT:

1h ± 30 min (salt=63). Osoba jest „w mieście" bez konkretnego lokalu (activity_unit = 0).

Wynik po wyjściu z klubu:

WynikPrawdopob.Następna aktywnośćSalt
Znaleziono partnera15%EVT_SEX_AWAY66
Nic się nie wydarzyło85%EVT_HOME_REST66

Seks przygodny (EVT_SEX_AWAY po EVT_CLUB_NIGHT):

  • Czas trwania: jak standardowy EVT_SEX_AWAY (tabela czas×wiek, salt=31, brak małżeństwa).
  • Lokalizacja: meet_loc = 0 (brak konkretnego lokalu).
  • Po seksie: bezpośrednio EVT_HOME_REST (bo plan->partner_id == 0; brak EVT_MORNING_RETURN).
  • Flaga sat_had_sex: nie ustawiana (osoba jest singlem, nie wpływa na plan niedzielny).

Skala dla Gorzowa przy ~12 000 eligible singli:

MiaraSobotaNiedziela
Planuje wyjście~960 os.~360 os.
W EVT_CLUB_NIGHT jednocześnie (21–01)~500–800 os.~180–300 os.
W EVT_SEX_AWAY (przygodny)~140 os.~54 os.

16. Poznanie na zakupach (try_shop_flirt)

Wywoływana przy EVT_GROCERY_SHOPPING. Modeluje przypadkowe poznanie się w sklepie spożywczym.

16.1 Warunki wstępne

  • Osoba jest singlem (partner_id == 0)
  • Wiek: 18–50 lat
  • 5% szans na „spotkanie" kogoś w sklepie (salt=83, prand % 100 < 5)

16.2 Wybór kandydata

Deterministyczny punkt startowy (salt=84), przeszukiwanie do 10 kolejnych osób po id. Kandydat musi spełniać:

  • aktualnie w EVT_GROCERY_SHOPPING
  • singiel (partner_id == 0)
  • płeć przeciwna
  • różnica wieku ≤ 12 lat

16.3 Nowy związek

  • Kanoniczny inicjator: niższe id
  • 10% szans na nowy związek (salt=85, prand % 100 < 10)

Efekt: analogicznie do try_work_encounter — REL_PARTNER, rel_since_year, EVT_FIRST_MEETING.


17. Podryw w pracy (try_work_encounter)

Wywoływana przy EVT_WORK_BREAK. Modeluje rozmowę i ewentualne poznanie się dwóch współpracowników na przerwie.

17.1 Warunki wstępne

  • Osoba jest singlem (partner_id == 0)
  • Wiek: 18–55 lat
  • Organizacja (work_org_id) istnieje i ma ≥ 2 pracowników
  • 30% szans na zainicjowanie rozmowy (salt=79, prand % 100 < 30)

17.2 Wybór kandydata

Deterministycznie wybierany z listy pracowników tej samej organizacji (salt=82). Przeszukiwanie do 5 kolejnych pozycji licząc od punktu startowego; kandydat musi aktualnie być w EVT_WORK_BREAK.

17.3 Kanoniczny inicjator i EVT_WORK_CHAT

Tylko osoba z niższym id loguje zdarzenie. Obie strony widzą to samo zdarzenie EVT_WORK_CHAT (od t_start do t_end przerwy).

17.4 Podryw i nowy związek

Warunki podrywu (wszystkie muszą być spełnione):

  • różna płeć
  • kandydat jest singlem (partner_id == 0)
  • różnica wieku ≤ 10 lat

Dwa niezależne rzuty:

  1. 15% szans na podryw (salt=80, prand % 100 < 15)
  2. 8% szans że podryw kończy się związkiem (salt=81, prand % 100 < 8)

Efekt: nowy REL_PARTNER — oboje otrzymują wzajemne partner_id, rel_type = REL_PARTNER, rel_since_year = rok bieżący. Logowany EVT_FIRST_MEETING.

Oczekiwana częstość: łącznie ~0.36% sesji EVT_WORK_BREAK zaowocuje związkiem.


18. Romanse w pracy (try_affair_start)

Wywoływana przy EVT_WORK_BREAK, po try_work_encounter(). Modeluje powstawanie nowych romansów pozamałżeńskich w miejscu pracy.

18.1 Warunki wstępne — mężczyzna

  • REL_SPOUSE (żonaty), wiek ≤ 32 lat
  • affair_partner_id == 0 (brak aktywnego romansu)
  • Pracuje w organizacji z ≥ 2 pracownikami
  • 5% szans na próbę (salt=93, prand % 100 < 5)

18.2 Wybór kandydatki

Deterministyczny punkt startowy (salt=94), przeszukiwanie do 10 kolejnych pozycji z listy pracowników org. Kandydatka musi spełniać:

  • Kobieta, wiek ≤ 29 lat
  • partner_id == 0 (singielka)
  • affair_partner_id == 0 (wolna)
  • Aktualnie w EVT_WORK_BREAK (ta sama org, ta sama przerwa)
  • Różnica wieku: mężczyzna starszy o 1–3 lata (dokładnie)
  • kandydatka.education <= mężczyzna.education — mężczyźni romansują z kobietami o równym lub niższym wykształceniu; kobiety nie idą z mężczyznami o niższym

18.3 Start romansu

  • 10% szans że romans faktycznie się zaczyna (salt=95, prand % 100 < 10)
  • Skutek: affair_partner_id ustawiany obustronnie (mężczyzna ↔ kandydatka)
  • Logowany EVT_AFFAIR_START = 508 (P1=mężczyzna, P2=kochanka)

EVT_AFFAIR_END = 509 jest logowany w try_breakup w momencie konwersji kochanki na stały związek (P6).


19. Rozstania i rozwody (try_breakup)

Wywoływana przy EVT_WAKEUP gdy osoba ma partnera. Kanoniczny inicjator: niższe id (dzięki temu każda para sprawdzana raz).

18.1 Kwalifikacja do rozstania

Trzy ścieżki kwalifikacyjne (pierwsza pasująca wygrywa):

ScenariuszWarunekPrawdopobieństwo/dzieńSalt
Romansmężczyzna ma kochankę bez innego partnera0.3% (% 1000 < 3)86
Kohabitacjarazem ≥ 7 lat I (brak dzieci LUB najmłodsze ≥ 17 lat)0.05% (% 2000 < 1)87
Osobne domy5–8 lat stażu I oboje bezdzietni0.1% (% 1000 < 1)87

18.2 Fallback — szukanie lokalu (P4)

Tylko dla kohabitacji bez romansu: przed rozstaniem szukamy wolnego lokalu mieszkalnego dla mężczyzny (30 losowych prób, salt=88). Brak wolnego lokalu → rozstanie nie zachodzi.

18.3 Skutki rozstania

  1. Zerowanie pól związku: partner_id = 0, rel_type = REL_NONE, rel_since_year = 0 u obojga.
  2. Logowany EVT_DIVORCE (byli małżonkowie, REL_SPOUSE) lub EVT_BREAKUP (partnerzy, REL_PARTNER).
  3. Mężczyzna przy kohabitacji bez romansu przenosi się do znalezionego lokalu; sched_gen++.

18.4 Konwersja romansu w związek (P6)

Gdy rozstanie spowodowane romansem:

  • romans → nowy REL_PARTNER (wzajemne partner_id, rel_since_year = rok bieżący)
  • mężczyzna przenosi się do domu kochanki (jeśli wcześniej kohabitował)
  • stare zdarzenie mężczyzny unieważnione: sched_gen++
  • logowany EVT_PARTNER_MOVES_IN

18.5 Opieka nad dziećmi po rozstaniu (P5)

Każde dziecko pary (z obu tablic children[]) jest rozpatrywane niezależnie:

  • 5% szans z ojcem (prand(child_id, dzien, 88) % 100 < 5)
  • 95%: dziecko zostaje z matką (home_unit_id bez zmian)

19. Ślub (try_marry)

Wywoływana przy EVT_WAKEUP. Sprawdza czy para REL_PARTNER powinna wziąć ślub. Kanoniczny inicjator: niższe id.

19.1 Prawdopodobieństwo ślubu

Zależy od stażu (rel_since_year → rok bieżący):

StażPrógPrawdopobieństwo/dzieńSkumulowane
< 2 lata% 14000 < 1~0.007%~5% w 2 latach
2–5 lat% 578 < 1~0.17%~85% w tym przedziale
5–7 lat% 664 < 1~0.15%~66% z pozostałych
≥ 7 lat% 50 < 12%domknięcie 100%

Salt: 89.

19.2 Skutki ślubu

  • rel_type = REL_SPOUSE u obojga
  • marriage_day = day_since_1960(t) u obojga (dni od 1960-01-01)
  • Logowany EVT_WEDDING

20. Przeprowadzka po ślubie (try_move_in_after_wedding)

Wywoływana przy EVT_WAKEUP. Mężczyzna wprowadza się do domu kobiety. Kanoniczny inicjator: niższe id.

Warunki: REL_SPOUSE, marriage_day > 0, oboje żyją osobno (home_unit_id != partner->home_unit_id).

20.1 Harmonogram przeprowadzki

Dzień od ślubuPrawdopobieństwoWzór
130%prand % 10 < 3
2~14%prand % 7 < 1
3~17%prand % 6 < 1
420%prand % 5 < 1
525%prand % 4 < 1
6~33%prand % 3 < 1
750%prand % 2 < 1
≥ 8100%zawsze

Salt: 90.

20.2 Skutki przeprowadzki

  • Mężczyzna: home_unit_id = kobiety->home_unit_id
  • Zaktualizowane occupant_count obu lokali (stary -1, nowy +1)
  • Jeśli mężczyzna był aktualnie w starym domu: current_unit_id zaktualizowane
  • Jeśli mężczyzna ma wyższe id niż inicjator: sched_gen++ + EVT_HOME_REST od razu
  • Logowany EVT_PARTNER_MOVES_IN

21. Narodziny dziecka (try_birth)

Wywoływana przy EVT_WAKEUP (dla kobiet zamężnych kohabitujących). Zwraca czas końca porodu lub 0.

21.1 Warunki

  • GENDER_FEMALE
  • REL_SPOUSE + partner_id != 0
  • marriage_day > 0
  • Para kohabituje (home_unit_id == partner->home_unit_id)
  • children_count < 6

21.2 Okno porodu

Numer dzieckaOknoPrzybliżenie
Pierwsze (last_birth_day == 0)marriage_day + 300 … marriage_day + 91210 mies.–2,5 roku po ślubie
Kolejnelast_birth_day + 450 … last_birth_day + 164215–54 mies. po poprzednim

Salt: 91. Poza oknem → brak rzutu.

21.3 Prawdopodobieństwo

prand(osoba->id, dzien, 91) % 1250 == 0 → ~0.08%/dzień w oknie.

21.4 Czas trwania porodu

Godzina rozpoczęciaCzas końca (birth_end)Efekt
Przed 10:30Następny dzień 09:00Kobieta pomija EVT_WAKEUP dnia+1 → pełny dzień odpoczynku
Po/o 10:30Następny dzień losowo 14:00–17:00 (salt=92)Wstaje późno, do końca dnia HOME_REST

Mechanizm: try_birth zwraca birth_end != 0 → wywołujący (sim_process_event, blok EVT_WAKEUP) nadpisuje nastepna_aktywnosc = EVT_HOME_REST i czas_konca = birth_end.

21.5 Skutki narodzin

  • children_count++ u obojga (matka i ojciec)
  • last_birth_day = day_since_1960(t) u obojga
  • Logowany EVT_BIRTH (czas od t do birth_end)

22. Kalendarz szkolny (sim_calendar)

Moduł src/sim_calendar.c (nagłówek include/sim_calendar.h) dostarcza funkcje klasyfikujące dzień jako szkolny lub wolny. Wywoływane z EVT_BREAKFAST w sim_schedule.c.

22.1 Polskie święta stałe

DataŚwięto
1 styczniaNowy Rok
6 styczniaTrzech Króli
1 majaŚwięto Pracy
3 majaŚwięto Konstytucji
15 sierpniaWniebowzięcie NMP
1 listopadaWszystkich Świętych
11 listopadaNiepodległość
24 grudniaWigilia (od 2025 roku)
25 grudniaBoże Narodzenie
26 grudniaDrugi dzień BN

Wielkanoc pominięte (ruchome, uproszczenie modelu).

22.2 Przerwa świąteczna (Boże Narodzenie)

  • Zaczyna się w sobotę poprzedzającą 24 grudnia (poprzez wyznaczenie dnia tygodnia 23 grudnia).
  • Kończy się 31 grudnia (włącznie).

22.3 Przerwa zimowa (ferie)

Algorytm: spośród kandydatów (poniedziałki od 7 stycznia do 1 marca) szukamy 14-dniowego okna z największą liczbą dni roboczych (Pn–Pt, bez świąt) przypadających w lutym. Przy remisie preferowany jest późniejszy start. Wynik jest cachowany per rok.

22.4 Rok szkolny — start

1 września, chyba że wypada w weekend lub jest świętem — wtedy następny dzień roboczy.

22.5 Wakacje letnie — koniec roku szkolnego

Typ szkołyKlasaKoniec zajęć
Liceum (BTYPE_SCHOOL_SECONDARY=4)Klasa 4 (matura)Ostatni piątek roboczy kwietnia
Technikum (BTYPE_SCHOOL_TECHNIKUM=14)Klasa 5 (matura)Ostatni piątek roboczy kwietnia
Wszystkie pozostałe—Pierwszy piątek ≥ 21 czerwca

Klasa 8 szkoły podstawowej nie ma odrębnej daty końca roku — kończy zajęcia razem z pozostałymi klasami podstawówki. Historyczna zasada kończenia w środę (sprzed 2001 r.) nie jest modelowana.

Wakacje trwają od pierwszego dnia po ostatnich zajęciach do dnia przed startem nowego roku szkolnego.

22.6 Studenci uczelni wyższych

TrybDni zajęćRok akademicki
Dzienne (cal_uni_fulltime_day)Pn–Pt (bez świąt)1 październik – koniec czerwca
Zaoczne (cal_uni_parttime_day)Sb–Nd (bez świąt)od soboty przed pierwszym roboczym poniedziałkiem października

Ustalanie trybu (bez nowego pola w strukturze):

  • EDU_HIGHER_MED → zawsze dzienne
  • age > 28 → zawsze zaoczne
  • Pozostali → dzienne

Tryb dzienny/zaoczny oblicza stu_is_parttime(age, education) z sim_student.c. Rok akademicki przechowywany w tablicy cal_table[] inicjalizowanej przy starcie demona.

22.7 Przedszkola i zerówka

cal_preschool_day(t, age):

  • Przedszkola czynne w dni robocze (Pn–Pt), bez świąt, cały rok (brak ferii zimowych).
  • Wyjątek: dzieci w wieku 6 lat (zerówka) mają wakacje letnie identyczne z klasą 1 szkoły podstawowej (pierwszy piątek ≥ 21 czerwca → wrzesień).

22.8 Typy szkół

StałaWartośćOpis
BTYPE_SCHOOL_PRIMARY3Szkoła podstawowa, klasy 1–8
BTYPE_SCHOOL_SECONDARY4Liceum ogólnokształcące, klasy 1–4
BTYPE_SCHOOL_TECHNIKUM14Technikum, klasy 1–5
BTYPE_SCHOOL_ZSZ18Zasadnicza szkoła zawodowa / branżowa I st., klasy 1–3 (wiek 15–17)
BTYPE_SCHOOL_POSTSECONDARY19Szkoła policealna, grupy 1–2 (wiek 20–21, po maturze)
BTYPE_UNIVERSITY5Uczelnia wyższa
BTYPE_PRESCHOOL12Przedszkole (STATUS_PRESCHOOL, wiek 3–5)
BTYPE_NURSERY13Żłobek (STATUS_CHILD z class_id > 0, wiek 0–2)

W generatorze: wiek 15–18 → 50% liceum / 50% technikum; wiek 19 → wyłącznie technikum (klasa 5).

Żłobki uczęszczają tylko niemowlęta spełniające trzy kryteria: (1) wiek 0–2, (2) oboje rodzice STATUS_EMPLOYED, (3) oboje rodzice EDU_SECONDARY lub EDU_HIGHER (nie EDU_HIGHER_MED). Harmonogram żłobkowy identyczny jak przedszkolny (EVT_PRESCHOOL, cal_preschool_day()). Rodzice obsługiwani przez city_has_young_child() — analogicznie jak rodzice przedszkolaków.