Ukraine's Higher Education Model

Ukraine's Higher Education Model preview image

1 collaborator

Default-person Artem Serdyuk (Author)

Tags

(This model has yet to be categorized with any tags)
Visible to everyone | Changeable by the author
Model was written in NetLogo 6.4.0 • Viewed 30 times • Downloaded 0 times • Run 0 times
Download the 'Ukraine's Higher Education Model' modelDownload this modelEmbed this model

Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)


Comments and Questions

Please start the discussion about this model! (You'll first need to log in.)

Click to Run Model

;extensions [csv]

globals [
  frontline-xcor         ; X coordinate of the frontline
  city-centers        ; List of city center patches

  war-intensity          ; Overall war intensity affecting infrastructure
  air-raid-probability    ; Probability of air raid per tick
  missile-attack-recovery-counter

  teacher-batch-size    ; Size of teacjer batches (currently 20)
  student-batch-size    ; Size of student batches (currently 100)
  student-total-attempts      ; Total attempts a student can make across all tiers
  student-attempts-per-tier   ; Maximum attempts per university tier

  air-raid?
  last-air-raid-tick         ; When the last air raid occurred
  air-raid-recovery-counter  ; Counter for recovery period
  air-raid-recovery-time      ; how many ticks recovery takes

   ; Teacher tracking metrics
  teachers-initially-assigned  ; Count of successful initial assignments
  teachers-quit               ; Count of teachers who quit due to stress
  teachers-fired              ; Count of teachers laid off due to capacity/performance
  teachers-rehired            ; Count of unemployed teachers who found new positions
]

breed [students student]
breed [teachers teacher]
breed [universities university]
breed [cities city]

patches-own [
  local-war-intensity    ; Local war intensity for this area
]

students-own [
  male?                 ; Gender (relevant for conscription)
  age                   ; Student's age

  propensity-to-study   ; Natural desire to study regardless of circumstances (0-100)
  desire-to-study       ; Motivation to study (0-100)
  studying?             ; Whether actively studying
  abroad?               ; Whether studying abroad

  program-type          ; "bachelor", "master" or "phd"
  my-university         ; The university this student attends
  previous-university
  last-application-attempt  ; Tick when last attempted to enter
  remaining-attempts       ; How many attempts they still have

  academic-skill                ; Student's academic ability (0-100)
  baseline-academic-skill       ; Natural academic ability before stress effects
  current-academic-performance  ; Actual current performance (0-100) affected by stress

  conscription-fear   ; How much they fear conscription (0-100)
  stress-level           ; Individual stress level (0-100)
  stress-resilience      ; How well they handle stress (0-100)

  max-stress-threshold
  min-stress-for-return
]

teachers-own [
  my-university     ; Current university
  unemployed?       ; Whether currently looking for work
  teaching-skill    ; Individual teaching ability (0-100)
  baseline-teaching-skill
  stress-level      ; Individual stress level (0-100)
  adaptation-rate   ; How quickly they adapt to new stress caused by warfare of regulations
]

universities-own [
;; Capacity
  location-type         ; "home-city" or "big-city"
  capacity           ; How many students can enroll
  enrolled-students-count  ; Current number of enrolled students
  current-teachers   ; Current number of teachers
  teachers-needed    ; How many teachers needed based on capacity

;; Quality
  quality               ; Education quality rating (0-100)
  entry-barrier         ; How difficult it is to enter (0-100)

  distance-from-front   ; Distance from the front line
  local-risk            ; Local war risk based on location
  infrastructure-damage ; Damage level from attacks (0-100)
  faculty-stress-level  ; Stress level of faculty at this university (0-100)
  bureaucratic-load    ; Bureaucratic load at this university (0-100)
  online-mode?          ; Whether currently teaching online
  is-merged?            ; Whether university has been merged
  relocated?
]

cities-own [
  city-type             ; "big-city" or "home-city"
]

to setup
  clear-all
  setup-globals
  setup-cities
  setup-universities
  setup-patches
  setup-teachers
  ask teachers [assign-teacher-to-university]
  set teachers-initially-assigned teachers-rehired
  set teachers-rehired 0
  initialize-university-quality  ; Initializes quality based on teachers
  setup-students
  reset-ticks
end 

to setup-globals
  set air-raid-probability 0.2 ; once per 5 days
  set war-intensity 0
  set frontline-xcor max-pxcor         ; Start frontline in right side of map
  set student-batch-size 100
  set teacher-batch-size 20  ; Each teacher agent represents 20 actual teachers
  set student-total-attempts 15
  set student-attempts-per-tier 3
  set air-raid? false
  set last-air-raid-tick 0
  set air-raid-recovery-counter 0
  set air-raid-recovery-time 15; how many ticks recovery takes

  set teachers-initially-assigned 0
  set teachers-quit 0
  set teachers-fired 0
  set teachers-rehired 0
end 

to setup-cities
  ; Create 20-24 cities
  let num-cities 20 + random 4
  let num-big-cities round (num-cities * 0.3)  ; 30% are big cities

  ; Create big cities first (they need more space)
  create-cities num-big-cities [
    setxy random-xcor random-ycor
    while [any? other cities in-radius 10] [
      setxy random-xcor random-ycor
    ]
    set city-type "big-city"
    set color red
    set shape "circle"
    set size 2
  ]

  ; Create remaining home cities
  create-cities (num-cities - num-big-cities) [
    setxy random-xcor random-ycor
    while [any? other cities in-radius 7] [
      setxy random-xcor random-ycor
    ]
    set city-type "home-city"
    set color cyan
    set shape "circle"
    set size 1.5
  ]
end 

to color-patch
  ; Base color from war intensity
  let base-color scale-color red local-war-intensity 100 0
  set pcolor base-color
end 

to setup-patches
  ask patches [
    ; Initialize local war intensity based on distance from frontline
    set local-war-intensity 0
    color-patch
  ]
end 

to go
  update-war-intensity
  check-critical-events
  batch-update-universities
  batch-update-students
  batch-update-teachers
  tick
end 

to setup-universities
  create-universities number-of-universities [
    ; First determine if this will be a big-city or home-city university
    set location-type one-of ["big-city" "home-city"]
    set relocated? false

    ; Find appropriate city type to move to
    let target-cities cities with [city-type = [location-type] of myself]

    ifelse any? target-cities [
      move-to one-of target-cities
      right random 360
      forward random 3
    ][
      ; Fallback if no matching cities available
      move-to one-of cities
      set location-type [city-type] of one-of cities-here  ; Adapt to the city type we landed in
    ]

    ; Set initial properties based on location type
    ifelse location-type = "big-city" [
      set capacity round (5000 + random 15000)
      set quality 50 + random 30  ; Initial baseline quality for big cities
    ][
      set capacity round (1000 + random 4000)
      set quality 30 + random 30  ; Initial baseline quality for smaller cities
    ]

    set entry-barrier max list 20 min list 95 (quality * 0.8 + random 20)

    set enrolled-students-count 0
    set infrastructure-damage 0
    set is-merged? false
    set online-mode? false
    set faculty-stress-level 0
    set bureaucratic-load 30 + random 10
    set current-teachers 0
    set teachers-needed ceiling (capacity / 10)

    set shape "pentagon"
    set size 1.5 + log (capacity / 10) 10
    update-university-appearance
  ]
end 

to initialize-university-quality
  ask universities [
    let my-teachers teachers with [my-university = myself]

    ; Keep the existing baseline but adjust based on teachers
    ifelse any? my-teachers [
      let avg-teaching-skill mean [teaching-skill] of my-teachers
      ; Teaching skill influences up to ±20 points of quality
      let teacher-quality-impact (avg-teaching-skill - 50) * 0.4
      set quality max list 0 min list 100 (quality + teacher-quality-impact)
    ][set quality max list 0 (quality - 10)]

    ; Update entry barrier based on new quality
    set entry-barrier max list 20 min list 95 (quality * 0.8 + random 20)

    update-university-appearance
  ]
end 

to update-university-appearance
  ; University appearance
  set size 1.5 + log ifelse-value (enrolled-students-count > 0) [enrolled-students-count][1] 10

   ifelse relocated? [
    set color turquoise + 2
  ][
    set color ifelse-value (infrastructure-damage > 20)
      [ red ]
      [ ifelse-value is-merged? [ violet ] [ blue ] ]
  ]

  set label-color black
  set label ""
  set label enrolled-students-count
end 

to update-war-intensity
  ; Update global war intensity using sine wave
  let time-factor ticks * 2  ; Adjust frequency
  set war-intensity 40 * sin time-factor + 50  ; Oscillate between 10% and 90%

  ; Update local war intensities and university risks
  ask patches [
    let distance-effect abs (pxcor - frontline-xcor)
    set local-war-intensity max (list 0 (war-intensity * (1 - (distance-effect / (max-pxcor + 1)))))

    ; Update local-risk for any universities on this patch
    ask universities-here [set local-risk local-war-intensity]

    color-patch
  ]
end 

to check-critical-events
  set air-raid? false

  ; Base probability calculation
  let raid-chance (war-intensity * air-raid-intensity) / 2000

  ; Increase chance if no raids for a while
  let time-since-last-raid ticks - last-air-raid-tick
  if time-since-last-raid > 20 [
    set raid-chance raid-chance * 2
  ]

  ; Check for air raid
  if random-float 1 < raid-chance [
    run-air-raid
    set last-air-raid-tick ticks
    set air-raid-recovery-counter air-raid-recovery-time
  ]

    if air-raid-recovery-counter > 0 [
    set air-raid-recovery-counter air-raid-recovery-counter - 1
    ; Change raid-marked patches to recovery color
    ask patches with [pcolor = red] [set pcolor orange]
  ]

    ; Clear recovery patches when done
    if air-raid-recovery-counter = 0 [
      ask patches with [pcolor = orange] [set pcolor black]
    ]
end 

to run-air-raid
  set air-raid? true
  set last-air-raid-tick ticks
  set air-raid-recovery-counter 15  ; Set recovery period

  ; Force all universities to go online during air raid
  ask universities [
    set online-mode? true

    if random 100 < (10 * (air-raid-intensity / 5)) [  ; Scale hit chance by intensity
      set color red
      let impact 10 + random 20
      set infrastructure-damage min list 100 (infrastructure-damage + impact)
      ask patches in-radius 3 [
        if not any? universities-here [set pcolor red]
      ]
    ]
  ]

  ask students with [not abroad?] [
    let stress-increase (25 + random 25) * (air-raid-intensity / 5)  ; Up to 50 points at max intensity
    set stress-level min list 100 (stress-level + stress-increase)
  ]

  ask teachers [
    let stress-increase (30 + random 30) * (air-raid-intensity / 5)  ; Up to 60 points at max intensity
    set stress-level min list 100 (stress-level + stress-increase)
  ]
end 

to handle-air-raid-recovery
  set air-raid-recovery-counter air-raid-recovery-counter - 1

  ask universities [
    if infrastructure-damage > 0 [
      ; Scale recovery rate based on damage level
      let recovery-rate 0.5 + (infrastructure-damage / 25)  ; Faster recovery for more damage

      ; Slower recovery under high war intensity
      if war-intensity > 50 [
        set recovery-rate recovery-rate * 0.7
      ]

      ; Apply recovery
      set infrastructure-damage max list 0 (infrastructure-damage - recovery-rate)
    ]
  ]
    ; Return from online mode if safe enough and not during active air raid
    if not air-raid? and infrastructure-damage < 40 and local-risk < 40 [
      set online-mode? false
    ]

    ; Reset visual effects when recovery complete
    if air-raid-recovery-counter <= 0 and color = red [
      update-university-appearance
    ]
end 

to batch-update-universities
  ask universities [
    if (enrolled-students-count <= 0) and (ticks > 10) [
     ; Make sure to properly handle any teachers
      handle-university-closure self
      die
    ]

    if ((infrastructure-damage >= 70 or local-risk >= 80) and enrolled-students-count > 0) [relocate]
    if expel-worst-students = true [expel-poor-performers]

    damage-infrastructure
    update-bureaucratic-load
    update-online-mode
    update-faculty-stress
    update-university-quality
    update-university-capacity
    update-teacher-count
    if merge-universities? [merge-universities]
    update-university-appearance
  ]
end 

to batch-update-students
  ask students [
    if not studying? and not abroad? [
      if age < 18 [check-abroad-opportunity]
      if not abroad? [  ; Continue only if didn't go abroad
        ifelse previous-university != nobody [check-return-to-studies]
        [check-retry-university-entry]
      ]
    ]

    if studying? = true [
      update-student-stress
      update-desire-to-study
      update-student-performance  ; This is where performance is affected by stress
      check-dropout-risk
    ]
  ]
end 

to batch-update-teachers
  ask teachers [
    update-teacher-stress
    update-teacher-skill
    if not unemployed? and stress-level > 80 [consider-quitting ]
    if unemployed? [assign-teacher-to-university]
    ]
end 

to update-teacher-stress
  ifelse (not unemployed? and my-university != nobody) [
    ; === EMPLOYED TEACHERS ===
    let current-stress stress-level

    ; === SECURITY FACTOR ===
    let security-stress (
      ([local-risk] of my-university * (war-intensity / 100)) +
      [infrastructure-damage] of my-university
    ) * 0.05  ; Scale factor to keep impact reasonable
    set current-stress max list 0 min list 100 (current-stress + security-stress)

    ; === STUDENT FACTOR ===
    let student-impact 0
    if any? students with [my-university = [my-university] of myself] [
      let avg-desire mean [desire-to-study] of students with [my-university = [my-university] of myself]
      let avg-performance mean [current-academic-performance] of students with [my-university = [my-university] of myself]
      set student-impact (
        ifelse-value (avg-desire < 40 or avg-performance < 40)
          [5]  ; High stress if either metric is poor
          [ifelse-value (avg-desire > 70 and avg-performance > 70)
            [-3]  ; Stress reduction if both metrics are good
            [0]   ; Neutral impact otherwise
          ]
      )
    ]
    set current-stress max list 0 min list 100 (current-stress + student-impact)

    ; === TEACHING FACTOR ===
    let teaching-impact (
      ifelse-value (teaching-skill > 70 and [quality] of my-university > 70)
        [-5]  ; Significant stress reduction for skilled teachers at good universities
        [ifelse-value (teaching-skill < 30 or [quality] of my-university < 30)
          [5]  ; Increased stress for poor skill match
          [0]  ; Neutral otherwise
        ]
    )
    set current-stress max list 0 min list 100 (current-stress + teaching-impact)

    ; === BUREAUCRATIC FACTOR ===
    let bureaucracy-impact ([bureaucratic-load] of my-university - 50) * 0.1
    set current-stress max list 0 min list 100 (current-stress + bureaucracy-impact)

    ; === RECOVERY ===
    let recovery-amount current-stress * adaptation-rate
    set current-stress max list 0 min list 100 (current-stress - recovery-amount)

    ; Set final stress level
    set stress-level current-stress

  ][
    ; === UNEMPLOYED TEACHERS ===
    ; Only affected by local security situation
    let security-stress [local-war-intensity] of patch-here * (war-intensity / 100)
    let recovery-amount stress-level * adaptation-rate

    set stress-level max list 0 min list 100 (
      stress-level + (security-stress * 0.1) - recovery-amount
    )
  ]
end 

to update-teacher-skill
  if not unemployed? and my-university != nobody [
    ifelse stress-level > 60 [
      ; High stress causes skill deterioration
      let stress-impact (stress-level - 60) * 0.02
      set teaching-skill max list 0 (teaching-skill * (1 - stress-impact))
    ][
      ; Low stress allows recovery based on teacher's adaptation rate
      if teaching-skill < baseline-teaching-skill [
        let skill-gap (baseline-teaching-skill - teaching-skill)
        let recovery-amount skill-gap * adaptation-rate
        set teaching-skill min list baseline-teaching-skill (teaching-skill + recovery-amount)
      ]
    ]
  ]
end 

; This helper procedure should be called whenever a university is about to die

to handle-university-closure [closing-university]
  ask teachers with [my-university = closing-university] [
    set unemployed? true
    set my-university nobody
    set color orange
    show-turtle
  ]

  set current-teachers 0  ; Reset teacher count
end 

to update-student-stress
  if not abroad? [
    ; Initialize local variables
    let is-online? false
    let war-exposure 0
    let teacher-support 0
    let stress-change 0
    let recovery-rate 0

    ; Get environmental conditions if student is at university
    if my-university != nobody [
      set is-online? [online-mode?] of my-university
      set war-exposure [local-risk] of my-university * (war-intensity / 100)

      let my-teachers teachers with [my-university = [my-university] of myself]
      if any? my-teachers [
        set teacher-support ((mean [teaching-skill] of my-teachers) - 50) / 50
      ]
    ]

    ; === CALCULATE STRESSORS ===
    set stress-change (war-exposure * 0.7)
    if is-online? [ set stress-change stress-change + 30 ]

    ; === CALCULATE RECOVERY ===
    ; Base recovery increases with higher current stress
    set recovery-rate 5 + (stress-resilience * 0.1) + (stress-level * 0.1)
    if not is-online? [ set recovery-rate recovery-rate + 5 ]
    set recovery-rate recovery-rate + (10 * teacher-support)

    ; === UPDATE FINAL STRESS LEVEL ===
    set stress-level max list 0 (min list 100 (stress-level + stress-change - recovery-rate))
  ]
end 

to update-student-performance
  if studying? [
    let stress-impact 0

    ; Calculate stress impact on performance
    ; High stress (>50) starts to negatively affect performance
    if stress-level > 50 [
      set stress-impact (stress-level - 50) * 0.02  ; Each point of stress above 50 reduces performance by 2%
    ]

    ; Teacher quality can help mitigate stress effects
    let teacher-support 0
    if my-university != nobody [
      let my-teachers teachers with [my-university = [my-university] of myself]
      if any? my-teachers [
        set teacher-support mean [teaching-skill] of my-teachers / 200  ; Max 50% stress reduction
      ]
    ]

    ; Calculate final performance
    ; Base it on natural ability but reduce by stress
    let stress-modifier (1 - (stress-impact * (1 - teacher-support)))

    ; Online mode has additional negative impact
    let online-penalty 0
    if my-university != nobody and [online-mode?] of my-university [
      set online-penalty 0.1  ; 10% performance reduction in online mode
    ]

    ; Update current performance
    set current-academic-performance max list 0 (
      baseline-academic-skill *
      (stress-modifier * (1 - online-penalty))
    )
  ]
end 

to update-desire-to-study
  ; Cache the calculation
  let base-desire max list 0 (propensity-to-study * (1 - (stress-level / 150)))

  if male? and age >= 18 and age <= 45 [
    let conscription-motivation conscription-fear * (war-intensity / 100)
    set desire-to-study min list 100 (base-desire + conscription-motivation)
  ]
end 

to check-dropout-risk
  let quit-threshold ifelse-value (male? and age >= 18 and age <= 45) [20] [30]

  if (desire-to-study < quit-threshold and studying? = true) [
    if random 100 < (quit-threshold - desire-to-study) * 2 [
      handle-dropout
    ]
  ]
end 

to handle-dropout
  if my-university != nobody [
    ask my-university [
      set enrolled-students-count enrolled-students-count - student-batch-size
    ]
    set previous-university my-university  ; Store the university before dropping out
    set my-university nobody
  ]
  set studying? false
  show-turtle
  set color black
  right random 360
  forward random 3
end 

; procedure for retrying university entry

to check-retry-university-entry
  ; Only try if they have attempts left and enough time has passed
  if remaining-attempts > 0 and (ticks - last-application-attempt) > 30 [  ; Wait 30 ticks between attempts
    ; Recalculate study motivation
    let study-motivation 0

    ; Base motivation from propensity to study (decreases with age)
    let age-factor max list 0 (1 - (age - 17) / 43)
    set study-motivation propensity-to-study * age-factor

    ; Add conscription avoidance motivation
    if male? [
      let conscription-motivation conscription-fear * (war-intensity / 100)
      ifelse age >= 18 and age <= 45 [
        set study-motivation study-motivation + conscription-motivation
      ][
        set study-motivation study-motivation + (conscription-motivation * 0.5)
      ]
    ]

    ; Additional motivation if stress is low
    if stress-level < 50 [
      set study-motivation study-motivation + (50 - stress-level) / 2
    ]

    ; Normalize motivation and update desire-to-study
    set study-motivation min list 100 study-motivation
    set desire-to-study study-motivation

    ; If motivated enough, try to enter university again
    if desire-to-study > 60 [  ; Only retry if highly motivated
      set last-application-attempt ticks
      set remaining-attempts remaining-attempts - 1
      choose-university  ; Try to enter university again
    ]
  ]
end 

to check-abroad-opportunity
  if not studying? and not abroad? and age < 18 [
    let my-skill academic-skill
    let abroad-chance calculate-entry-chance my-skill 70

    if abroad-chance > (100 - random abroad-entry-chance) [
      set abroad? true
      set studying? true
      set my-university nobody
      setxy (min-pxcor + 3 + random 5) (max-pycor - 3 - random 5)
      set color yellow
    ]
  ]
end 

;; Modified check-return-to-studies to use previous-university

to check-return-to-studies
  ; Only consider returning if stress is below threshold and has a previous university
  if stress-level < min-stress-for-return and previous-university != nobody [
    ; Calculate return probability based on multiple factors
    let return-chance 0

    ; Base chance increases as stress decreases
    set return-chance (min-stress-for-return - stress-level) / 2

    ; Additional motivation from conscription fear
    if male? and age >= 18 and age <= 45 [
      let conscription-motivation conscription-fear * (war-intensity / 100)
      set return-chance return-chance + conscription-motivation / 2
    ]

    ; Check university conditions
    if [infrastructure-damage] of previous-university < 50 and
       [local-risk] of previous-university < 50 and
       [enrolled-students-count] of previous-university < [capacity] of previous-university [

      ; Make the decision
      if random 100 < return-chance [
        set studying? true
        set my-university previous-university  ; Return to previous university
        set previous-university nobody  ; Clear previous university as they're now enrolled
        ask my-university [
          set enrolled-students-count enrolled-students-count + student-batch-size
        ]
        hide-turtle
      ]
    ]
  ]
end 

to update-university-quality
  let quality-change 0
  let my-students students with [my-university = myself]
  let my-teachers teachers with [my-university = myself]

  ; Base rate of change - slower changes
  let change-rate 0.1  ; 10% change per tick

  ; === 1. TEACHER FACTORS ===
  ifelse any? my-teachers [
    let avg-teaching-skill mean [teaching-skill] of my-teachers
    let avg-teacher-stress mean [stress-level] of my-teachers

    ; Teacher impact: skill reduced by stress
    let effective-skill avg-teaching-skill * (1 - (avg-teacher-stress / 200))
    let teaching-impact (effective-skill - quality) * 0.3

    ; Reduced effectiveness during disruptions
    if online-mode? or relocated? [ set teaching-impact teaching-impact * 0.7 ]

    set quality-change quality-change + teaching-impact
  ][
    set quality-change quality-change - 1  ; Simple penalty for no teachers
  ]

  ; === 2. STUDENT FACTORS ===
  if any? my-students [
    let avg-performance mean [current-academic-performance] of my-students
    let avg-student-stress mean [stress-level] of my-students
    let avg-desire mean [desire-to-study] of my-students

    ; Performance impact adjusted by desire to study
    let performance-impact (avg-performance - quality) * (avg-desire / 100) * 0.2

    ; Stress penalty when high
    let stress-impact 0
    if avg-student-stress > 50 [
      set stress-impact (50 - avg-student-stress) * 0.1
    ]

    set quality-change quality-change + performance-impact + stress-impact
  ]

  ; === 3. INFRASTRUCTURE IMPACT ===
  let infrastructure-impact (50 - infrastructure-damage) * 0.1
  set quality-change quality-change + infrastructure-impact

  ; === 4. EVENT IMPACTS ===
  ; Major events amplify changes
  if is-merged? or relocated? [ set quality-change quality-change * 1.3 ]

  ; Apply gradual change
  set quality-change quality-change * change-rate

  ; === APPLY FINAL CHANGES ===
  set quality max (list 0 (min (list 100 (quality + quality-change))))
  update-university-appearance
end 
;;===========================================================================

to setup-students
  create-students initial-students / student-batch-size [
    ; Try to place more students (50%) near big cities
    ifelse random-float 1 < 0.5 [
      let big-cities cities with [city-type = "big-city"]
      ifelse any? big-cities [
        move-to one-of big-cities
      ]
      [move-to one-of cities]
      ]
      [move-to one-of cities]

    right random 360
    forward random 5

    ; Rest of student setup
    set male? random 2 = 0
    set age fat-tailed-age
    set shape "person"
    set color green

    set studying? false
    set abroad? false
    set previous-university nobody
    set last-application-attempt 0
    set remaining-attempts student-total-attempts

    set stress-level random 50
    set desire-to-study 20 + random 80
    set max-stress-threshold 80
    set min-stress-for-return 40

    set academic-skill random-normal 50 30
    set academic-skill max list 0 min list 100 academic-skill

    set propensity-to-study random-normal (100 - (age - 17) * 2) 15
    set propensity-to-study max list 0 min list 100 propensity-to-study

    set baseline-academic-skill academic-skill
    set current-academic-performance academic-skill

    set stress-resilience random-normal 50 40
    set stress-resilience max list 0 min list 100 stress-resilience

    ifelse male? [
      ifelse age >= 18 and age <= 45
      [set conscription-fear random-normal 70 15]
      [set conscription-fear random-normal 30 15]
    ] [set conscription-fear 0]
    set conscription-fear max list 0 min list 100 conscription-fear

    calculate-desire-to-study
    if not studying? [choose-university]
  ]
end 

to calculate-desire-to-study
  let study-motivation 0

  if not studying? [
  ; Base motivation from propensity to study (decreases with age)
  let age-factor max list 0 (1 - (age - 17) / 43)  ; Scales from 1 at 17 to 0 at 60
  set study-motivation propensity-to-study * age-factor

  ; Add conscription avoidance motivation for males
  if male? [
    let conscription-motivation conscription-fear * (war-intensity / 100)
    ifelse age >= 18 and age <= 45 [
      ; Peak conscription motivation for military age
      set study-motivation study-motivation + conscription-motivation
    ][
      ; Reduced effect outside prime military age
      set study-motivation study-motivation + (conscription-motivation * 0.5)
    ]
  ]
  ; Normalize motivation to 0-100 scale
  set study-motivation min list 100 study-motivation
  set desire-to-study study-motivation  ; Update desire-to-study for other procedures

  ; Always try to enter, but success depends on skills and barriers
  ]
end 

to choose-university
  let my-skill academic-skill

  ; Check for studying abroad
  let abroad-chance calculate-entry-chance my-skill 70
  if (abroad-chance > random (100 - random abroad-entry-chance)) and age < 18 [
    set abroad? true
    set studying? true
    set my-university nobody
    setxy (min-pxcor + 3 + random 5) (max-pycor - 3 - random 5)
    set color yellow
    stop
  ]

  ; === Try Elite Universities ===
  let elite-universities universities with [
    infrastructure-damage < 70 and
    local-risk < 70 and
    quality > 50 and
    enrolled-students-count < capacity
  ]

  if any? elite-universities and remaining-attempts > 0 [
    let tries min list student-attempts-per-tier remaining-attempts
    repeat tries [
      let target max-one-of elite-universities [quality - (distance myself * 2)]
      if target != nobody [
        let entry-chance calculate-entry-chance my-skill [quality] of target
        if entry-chance > random 90 [
          enroll-in-university target
          set remaining-attempts remaining-attempts - 1
          stop
        ]
      ]
      set remaining-attempts remaining-attempts - 1
    ]
  ]

  ; === Try Mid-tier Universities ===
  let mid-universities universities with [
    infrastructure-damage < 70 and
    local-risk < 70 and
    quality <= 50 and quality > 30 and
    enrolled-students-count < capacity
  ]

  if any? mid-universities and remaining-attempts > 0 [
    let tries min list student-attempts-per-tier remaining-attempts
    repeat tries [
      let target max-one-of mid-universities [quality - (distance myself * 2)]
      if target != nobody [
        let entry-chance calculate-entry-chance my-skill [quality] of target
        if entry-chance > random 80 [
          enroll-in-university target
          set remaining-attempts remaining-attempts - 1
          stop
        ]
      ]
      set remaining-attempts remaining-attempts - 1
    ]
  ]

  ; === Try Easy Universities ===
  let easy-universities universities with [
    infrastructure-damage < 60 and
    local-risk < 70 and
    enrolled-students-count < capacity
  ]

  if any? easy-universities and remaining-attempts > 0 [
    repeat remaining-attempts [
      let target max-one-of easy-universities [quality - (distance myself * 2)]
      if target != nobody [
        let entry-chance calculate-entry-chance my-skill [quality] of target
        if entry-chance > random 40 [
          enroll-in-university target
          set remaining-attempts remaining-attempts - 1
          stop
        ]
      ]
      set remaining-attempts remaining-attempts - 1
    ]
  ]

  ; Mark as unsuccessful if all attempts failed
  if not studying? [
    set my-university nobody
    set color red
  ]
end 

to-report calculate-entry-chance [skill barrier]
  let base-chance 100 * (skill / 100) * (1 - (barrier / 200)) ; Reduced barrier impact
  let bonus random 20 ; Only positive random bonus
  report max list 0 min list 100 (base-chance + bonus)
end 

to enroll-in-university [uni]
  set abroad? false
  set my-university uni
  set studying? true
  ifelse age < 22 [
      set program-type "bachelor"
    ][ifelse age < 25 [
        set program-type one-of ["bachelor" "master" "master"]
      ][set program-type one-of ["master" "master" "phd"]
      ]
    ]
  ask uni [set enrolled-students-count enrolled-students-count + student-batch-size]
  hide-turtle
end 
;; ====================================================================

to setup-teachers
  create-teachers (sum [ceiling (capacity / 10)] of universities / teacher-batch-size) [
    ; Try to place more teachers (80%) near big cities
    ifelse random-float 1 < 0.8
    [
      let big-cities cities with [city-type = "big-city"]
      ifelse any? big-cities
      [move-to one-of big-cities]
      [move-to one-of cities]
    ][move-to one-of cities]

    right random 360
    forward random 5

    ; Rest of teacher setup
    set shape "person"
    set color orange
    set teaching-skill min list 100 (max list 0 (random-normal 70 20))
    set baseline-teaching-skill teaching-skill
    set stress-level random 30
    set adaptation-rate random-float 0.1
    set unemployed? true
    set my-university nobody

    assign-teacher-to-university
  ]
end 

to assign-teacher-to-university
  if not unemployed? [ stop ]  ; Don't try to assign if already employed
  ; Only look at universities that need teachers
  let potential-universities universities with [current-teachers < teachers-needed]

  if any? potential-universities [
    ; Group universities by quality
    let high-quality-unis potential-universities with [quality >= 70]
    let other-unis potential-universities with [quality < 70]

    ; Good teachers (skill >= 70) try high quality universities first
    ifelse teaching-skill >= 70 and any? high-quality-unis [
      let best-university min-one-of high-quality-unis [distance myself]
      try-join-university best-university
    ][
      ; Everyone else just picks closest university
      let best-university min-one-of potential-universities [distance myself]
      try-join-university best-university
    ]
  ]
end 

; Helper procedure for joining university

to try-join-university [university1]
  if university1 != nobody [
    if random 100 < 90 [  ; Keep the high hiring chance
      set my-university university1
      set unemployed? false
      ask university1 [
        set current-teachers current-teachers + teacher-batch-size
      ]
      hide-turtle
    ]
  ]
end 

to update-teacher-count
  set teachers-needed ceiling (capacity / 10)  ; Actual number of teachers needed
  set current-teachers (count teachers with [my-university = myself] * teacher-batch-size)
  ; If too many teachers, lay off some - but only if there are teachers to lay off

  while [current-teachers > teachers-needed and any? teachers with [my-university = myself]] [
    let teacher-to-layoff nobody
    ifelse (fire-worst-teachers = true)
      [set teacher-to-layoff min-one-of teachers with [my-university = myself] [teaching-skill / (stress-level + 1)]]
      [set teacher-to-layoff one-of teachers with [my-university = myself]]

    if teacher-to-layoff != nobody [
      ask teacher-to-layoff [
        set unemployed? true
        set my-university nobody
        set color orange
        show-turtle
      ]
      set current-teachers current-teachers - teacher-batch-size
      set teachers-fired teachers-fired + 1
    ]
  ]
end 

to consider-quitting
  if not unemployed? [
    ; High stress gives 30% chance of quitting
    if stress-level > 80 [
      if random 100 < (20 + 100 - stress-level) [
        ; Leave current position
        set teachers-quit teachers-quit + teacher-batch-size
        ask my-university [
          set current-teachers current-teachers - teacher-batch-size
        ]
        ; Update teacher status
        set unemployed? true
        set my-university nobody
        set color orange
        show-turtle
      ]
    ]
  ]
end 

;; =======================================================

to damage-infrastructure
  ; Use patch's local-war-intensity directly
  let current-intensity [local-war-intensity] of patch-here

  ; Damage chance based directly on local war intensity
  if random-float 100 < current-intensity [
    if random-float 100 < 15 [  ; Base 15% chance of attack
      let damage-amount random 50 * (current-intensity / 50)
      set infrastructure-damage min list 100 (infrastructure-damage + damage-amount)
    ]
  ]

  ; Repair functionality when conditions are favorable
  if current-intensity < 50 [ ; Only repair when relatively safe
    let repair-chance (50 - current-intensity) / 50  ; Higher chance of repair when safer
    if random-float 1 < repair-chance [
      let repair-amount 2 + random 3
      set infrastructure-damage max (list 0 (infrastructure-damage - repair-amount))
    ]
  ]
end 

to update-online-mode
  ifelse local-risk > 40 [set online-mode? true]
  [set online-mode? false]
end 

to merge-universities
  if (infrastructure-damage > 80 or quality < 10) or (enrolled-students-count < 200) [
    let potential-partners other universities in-radius 20

    if any? potential-partners [
      let merger-candidate max-one-of potential-partners [
        (1 / (distance myself + 1)) *
        ((100 - infrastructure-damage) / 100) *
        (quality / 100) *
        (enrolled-students-count / 10)
      ]

      if merger-candidate != nobody [
        let my-strength (
          ((100 - infrastructure-damage) / 100) *
          (quality / 100) *
          (enrolled-students-count / 10)
        )
        let their-strength (
          ([100 - infrastructure-damage] of merger-candidate / 100) *
          ([quality] of merger-candidate / 100) *
          ([enrolled-students-count] of merger-candidate / 10)
        )

        ifelse my-strength > their-strength [
          ; We absorb them
          set capacity (capacity + [capacity] of merger-candidate) * 0.8
          set is-merged? true
          ask students with [my-university = merger-candidate] [
            set my-university myself
            move-to myself
            set stress-level min list 100 (stress-level + 25) ; adding merger stress
            hide-turtle
          ]
          set enrolled-students-count enrolled-students-count + [enrolled-students-count] of merger-candidate

          ask teachers with [my-university = merger-candidate] [
            set my-university myself
            move-to myself
            set stress-level min list 100 (stress-level + 30) ; adding merger stress
            hide-turtle
          ]
          set current-teachers current-teachers + [current-teachers] of merger-candidate

          handle-university-closure merger-candidate
          ask merger-candidate [ die ]
          update-university-appearance
        ] [
          ; They absorb us
          ask merger-candidate [
            set capacity (capacity + [capacity] of myself) * 0.8
            set is-merged? true
            set enrolled-students-count enrolled-students-count + [enrolled-students-count] of myself
            set current-teachers current-teachers + [current-teachers] of myself
            update-university-appearance
          ]
          ask students with [my-university = myself] [
            set my-university merger-candidate
            move-to merger-candidate
            set stress-level min list 100 (stress-level + 25) ; adding merger stress
            hide-turtle
          ]
          ask teachers with [my-university = myself] [
            set my-university merger-candidate
            move-to merger-candidate
            set stress-level min list 100 (stress-level + 30) ; adding merger stress
            hide-turtle
          ]

          handle-university-closure self
          die
        ]
      ]
    ]
  ]
end 

to update-university-capacity
  let target-capacity enrolled-students-count

  ; Don't let capacity drop below a minimum based on university type
  let min-capacity ifelse-value (location-type = "big-city")
    [1000]  ; Minimum for big city universities
    [500]   ; Minimum for other universities

  set target-capacity max list target-capacity min-capacity

  ; Gradual adjustment toward target (5% per tick)
  let capacity-difference target-capacity - capacity
  let adjustment-rate 0.05

  ; Apply the change
  set capacity round(capacity + (capacity-difference * adjustment-rate))
end 

to update-faculty-stress
  let my-teachers teachers with [my-university = myself]
  ifelse any? my-teachers [
    ; Set faculty stress as average of teacher stress
    set faculty-stress-level min list 100 (mean [stress-level] of my-teachers)
  ][
    ; If no teachers, base stress on environmental factors
    set faculty-stress-level min list 100 (
      (infrastructure-damage + bureaucratic-load + local-risk) / 3)
  ]
end 

to update-bureaucratic-load
  let regulation-chance 30 * (new-regulation-intensity / 5)

    if random 100 < regulation-chance [
      ifelse random 100 < 20 [  ; 20% chance of positive reform
        set bureaucratic-load max (list 0 (bureaucratic-load - 5 - random 10))
      ] [set bureaucratic-load bureaucratic-load + random 10]
    ]

    ; Gradual improvement as university adapts
    if bureaucratic-load > 50 and random 100 < 30 [set bureaucratic-load bureaucratic-load - 2]
    set bureaucratic-load max list 0 min list bureaucratic-load 100
end 

;; =================================================================

to add-new-regulation
  ; Sudden increase in bureaucratic load
  ask universities [
    ; Significant increase in bureaucratic load (20-40%)
    let regulation-impact 30 + random 40
    set bureaucratic-load min list 100 (bureaucratic-load + regulation-impact)
  ]
end 

to run-missile-attack  ; Air raid

  set missile-attack-recovery-counter 10

  ; Affect universities based on their location and chance
  ask universities [
    ; Calculate chance of being hit based on distance from front
    let hit-chance 20 + random 20  ; Base 20-40% chance
    if distance-from-front < 20 [
      set hit-chance hit-chance * 1.2
    ]

    ; Only apply damage if university is actually hit
    if random 100 < hit-chance [
      ; Much milder impact - infrastructure damage capped at 50
      let impact 5 + random 10
      set infrastructure-damage min list 50 (infrastructure-damage + impact)

      ; Force online mode only if significant damage
      if infrastructure-damage > 30 [
        set online-mode? true
      ]

      ; Visual effect without size change
      set color red
    ]
  ]

  ; Affect students - using more efficient checks
  ask students with [not abroad?] [set stress-level min list 100 (stress-level + 20)]

  ; Schedule cleanup of visual effects
  set missile-attack-recovery-counter 5
end 

to handle-missile-recovery
  ; Gradually recover from missile attack effects
  set missile-attack-recovery-counter missile-attack-recovery-counter - 1

  if missile-attack-recovery-counter <= 0 [
    ; Reset war intensity to normal levels
    set war-intensity war-intensity * 0.9

    ; Help universities recover
    ask universities [
      ; Gradual infrastructure recovery
      if infrastructure-damage > 0 [
        let recovery-rate 2 + random 3
        set infrastructure-damage max list 0 (infrastructure-damage - recovery-rate)
      ]

      ; Return from online mode if safe
      if local-risk < 40 [
        set online-mode? false
      ]

      ; Faculty stress recovery
      set faculty-stress-level max list 0 (faculty-stress-level - 1)
    ]
  ]
end 

to-report fat-tailed-age
 ifelse random-float 1 < 0.8 [
    ; First peak (power law for younger students)
    let alpha 1.5
    let u random-float 1
    let x (1 - u) ^ (-1 / alpha)
    report min (list 55 (max (list 17 (17 + (x - 1) * 38 / 8))))
  ][
    ; Second peak (normal distribution for mature students)
    let mu 37
    let sigma 4
    let age1 round (mu + (sqrt (-2 * ln random-float 1) * cos (360 * random-float 1)) * sigma)
    report min (list 55 (max (list 17 age1)))
  ]
end 

to relocate
  ; Attempt emergency relocation
  let safe-locations patches with [
    local-war-intensity < 30 and
    not any? universities-here and
    any? cities in-radius 5 and
    ; Add boundary checks to keep universities visible
    pxcor > min-pxcor + 5 and
    pxcor < max-pxcor - 5 and
    pycor > min-pycor + 5 and
    pycor < max-pycor - 5
  ]

  if any? safe-locations [
    ; Find best new location near a city
    let new-location min-one-of safe-locations [distance myself + (local-war-intensity / 10)]

    ; Relocate university
    move-to new-location
    set infrastructure-damage 30 ; Some damage from relocation
    set faculty-stress-level min list 100 (faculty-stress-level + 30)
    set bureaucratic-load min list 100 (bureaucratic-load + 20)
    set online-mode? true ; Temporary online mode during transition
    set relocated? true   ; Mark as relocated

    ; Update stress for students and teachers without moving them
    ask students with [my-university = myself] [
      move-to new-location
      set stress-level min list 100 (stress-level + 25)
    ]

    ask teachers with [my-university = myself] [
      move-to new-location
      set stress-level min list 100 (stress-level + 30)
    ]

    update-university-appearance
  ]
end 

to expel-poor-performers
    let poor-performers students with [
      my-university = myself and
      current-academic-performance < 20
    ]

    if any? poor-performers [
      ask poor-performers [
        ; Store university before expulsion for potential return
        set previous-university my-university
        set my-university nobody
        set studying? false
        show-turtle
        set color black
      ]
      ; Update university enrollment count
      set enrolled-students-count enrolled-students-count - (count poor-performers * student-batch-size)
    ]
end 

to add-student-stress
  ask students [
    set stress-level min list 100 (stress-level + additional-stress)
  ]
end 

to add-teacher-stress
  ask teachers [
    set stress-level min list 100 (stress-level + additional-stress)
  ]
end 

There is only one version of this model, created 12 days ago by Artem Serdyuk.

Attached files

File Type Description Last updated
Ukraine's Higher Education Model.png preview Preview for 'Ukraine's Higher Education Model' 12 days ago, by Artem Serdyuk Download

This model does not have any ancestors.

This model does not have any descendants.