<?xml version="1.0" encoding="utf-8"?>
<model version="NetLogo 3D 7.0.3" snapToGrid="false">
  <code><![CDATA[extensions [sound nw]

globals [
  ;; core
  min-prevalence
  max-prevalence
  memes-per-change
  meta-influencers-droit
  meta-influencers-gauche
  inject-tick
  iter change total inversion try major fractale
  ordonnee abcisse profondeur
  list_data file-in in_data repet_data
  links-dead links-create meta-agents meta-links meta-create Interactions %Major

  ;; LOCALE
 ;; locale-format          ;; "EN" | "FR"

  ;; CSV (simplifié, sans BOTH)
  ;;csv-export             ;; switch
  ;;csv-basename           ;; string
  ;;csv-mode               ;; "Statistics" | "Values"
  csv-file-stats
  csv-file-values
  csv-buffer             ;; liste de lignes (strings) à écrire en fin de run/try
  csv-open?              ;; buffer initialisé ?
  ;;csv-values-step        ;; pas d’export Values (ticks mod step = 0)
  ;;csv-values-start       ;; tick de départ pour exporter Values

  ;; NEW: import Values CSV
  list_values_data
  values_file_in
  values_sep

  ;; compat: si vous n’avez pas le switch, le code compile quand même
  ;;inject-metas-only
]

turtles-own [
  opinion
  prevalence
  agent-type
  influence
  opinion-previous
  influence-previous
  x3d y3d z3d

  meme-plus
  meme-minus
  meme-plus-w
  meme-minus-w

  old-opinion
  proposed-opinion

  tx-bonus
]

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; LOCALE / FORMAT HELPERS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to-report col-sep
  ifelse locale-format = "FR" [ report ";" ] [ report "," ]
end

to-report replace-all [s old new]
  let out s
  while [ position old out != false ] [
    let i position old out
    set out (word (substring out 0 i) new (substring out (i + length old) (length out)))
  ]
  report out
end

to-report fmt [x]
  ;; formatte nombres selon locale-format (décimale "," en FR)
  if x = nobody [ report "" ]
  if not is-number? x [ report (word x) ]
  let s (word "" x)
  if locale-format = "FR" [
    set s replace-all s "." ","
  ]
  report s
end

to-report join-cols [lst]
  let sep col-sep
  let out ""
  foreach lst [ val ->
    let s (word "" val)
    set out ifelse-value (out = "")
      [ s ]
      [ (word out sep s) ]
  ]
  report out
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; VALUES CSV IMPORT HELPERS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to-report split-by [s sep]
  ;; retourne une liste de segments (strings)
  let parts []
  let rest s
  while [ position sep rest != false ] [
    let i position sep rest
    set parts lput (substring rest 0 i) parts
    set rest substring rest (i + length sep) (length rest)
  ]
  set parts lput rest parts
  report parts
end

to-report to-number-locale [s sep]
  ;; s: string ; sep: ";" (FR) ou "," (EN)
  if s = "" [ report 0 ]
  let x s
  ;; si colonnes séparées par ";" on suppose décimale ","
  if sep = ";" [
    set x replace-all x "," "."
  ]
  set x replace-all x " " ""
  report read-from-string x
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; SETUP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to setup
  clear-all
  set repet_data false
  set iter 0
  set min-prevalence 0
  set max-prevalence 99
  set-default-shape turtles "person"
  set try 1
  set inject-tick inject-base
  set major 0

  ;; Locale defaults
  if not is-string? locale-format [ set locale-format "FR" ]
  if (locale-format != "FR" and locale-format != "EN") [ set locale-format "FR" ]

  ;; tick-event initialisé par event-init
  if not is-number? event-init [ set event-init 50 ]
  set tick-event event-init

  set links-dead 0
  set links-create 0
  set meta-create 0
  set meta-agents 0
  set change 0
  set total 0
  set inversion 0
  set fractale 0

  if (vary-influence = true) or (meta-ok = true) [ set meta-links meta-min ]

  ;; CSV defaults
  if not is-boolean? csv-export [ set csv-export false ]
  if (not is-string? csv-basename) or (csv-basename = "") [ set csv-basename "run" ]
  if not is-string? csv-mode [ set csv-mode "Statistics" ]
  if (csv-mode != "Statistics" and csv-mode != "Values") [
    set csv-mode "Statistics"
  ]

  if not is-number? csv-values-step  [ set csv-values-step 10 ]
  if csv-values-step < 1 [ set csv-values-step 1 ]

  if not is-number? csv-values-start [ set csv-values-start 0 ]
  if csv-values-start < 0 [ set csv-values-start 0 ]

  set csv-file-stats ""
  set csv-file-values ""
  set csv-buffer []
  set csv-open? false

  ;; import values defaults
  set list_values_data []
  set values_file_in false
  set values_sep ";"

  ;; compat
  if not is-boolean? inject-metas-only [ set inject-metas-only false ]

  ;; defaults group-impact
  if (not is-string? group-impact-mode) [ set group-impact-mode "all" ]
  if (not is-number? group-k) [ set group-k 10 ]
  if (not is-number? group-impact-weight) [ set group-impact-weight 0.5 ]
  if (not is-number? group-impact-alpha) [ set group-impact-alpha 1.0 ]

  ;; default switches
  if not is-boolean? show-links [ set show-links false ]
  if not is-boolean? metablock  [ set metablock false ]

  ;; defaults inversion/ponts
  if (not is-number? prevalence-weight) [ set prevalence-weight 1.5 ]
  if (not is-number? adoption-floor)    [ set adoption-floor 0.02 ]
  if (not is-number? bridge-prob)       [ set bridge-prob 0.10 ]

  ;; defaults reward
  if not is-number? reward-step       [ set reward-step 0.05 ]
  if not is-number? reward-cap        [ set reward-cap  0.50 ]
  if not is-string? reward-scope      [ set reward-scope "both" ]
  if not is-number? reward-prev-delta [ set reward-prev-delta 0 ]
  if not is-number? reward-decay      [ set reward-decay 0 ]

  ;; defaults memes
  if not is-boolean? use-memes?    [ set use-memes? false ]
  if not is-number? meme-max       [ set meme-max 100 ]
  if not is-number? meme-gain      [ set meme-gain 1.0 ]
  if not is-number? meme-anti-leak [ set meme-anti-leak 0.0 ]
  if not is-number? meme-decay     [ set meme-decay 0.0 ]

  ;; defaults memes pondérés
  if not is-number? meme-weight-mean [ set meme-weight-mean 1.0 ]
  if not is-number? meme-weight-sd   [ set meme-weight-sd 0.0 ]
  if not is-number? meme-weight-min  [ set meme-weight-min 0.05 ]
  if not is-number? meme-weight-max  [ set meme-weight-max 5.0 ]

  ;; defaults injection
  if not is-boolean? auto_inject?   [ set auto_inject? false ]
  if not is-boolean? repeat-inject? [ set repeat-inject? false ]
  if not is-number? inject-tick     [ set inject-tick 50 ]
  if not is-number? inject-pace     [ set inject-pace 50 ]

  if not is-string? inject-sign     [ set inject-sign "plus" ]
  if not is-number? inject-amount   [ set inject-amount 1 ]
  if not is-number? inject-weight   [ set inject-weight 1.0 ]
  if not is-number? inject-prob-max [ set inject-prob-max 1.0 ]

  if not is-number? inject-low_meme  [ set inject-low_meme -1.0 ]
  if not is-number? inject-high_meme [ set inject-high_meme  1.0 ]
  if not is-number? inject-low-prev  [ set inject-low-prev  0.0 ]
  if not is-number? inject-high-prev [ set inject-high-prev 99.0 ]

  set-background-black

  create
  rapport
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; CREATE
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to create
  create-turtles pop / 2 [
    set agent-type "Right side"
    set opinion random-float 1
    set color blue
    set prevalence random-float (opinion * 100)
    set influence random-float 1
    set opinion-previous opinion
    set influence-previous influence
    set tx-bonus 0
    init-memes-from-state
    update-3d self
  ]

  create-turtles pop / 2 [
    set agent-type "Left side"
    set opinion (random-float 1 - 1)
    set color red
    set prevalence random-float (abs opinion * 100)
    set influence random-float 1
    set opinion-previous opinion
    set influence-previous influence
    set tx-bonus 0
    init-memes-from-state
    update-3d self
  ]

  influenceurs
  reset-ticks

  set total 0
  set change 0
  set Interactions 0
  set %Major 0

  update-networks
  recolor-links
  apply-link-visibility
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; OUTPUT HEADERS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to rapport
  if output = "Statistics" [
    output-print join-cols (list
      "Try" "Iter"
      "Opinion global"
      "Opinion right side" "Opinion left side"
      "Prevalence right side" "Prevalence left side"
      "Influence right side" "Influence left side"
      "Left %" "Right %"
      "Links-Remove" "Links-Create"
      "Inversion %" "change" "total" "fractale"
    )
  ]
  if output = "Values" [
    ;; memed RETIRÉ des Values
    output-print join-cols (list
      "Try" "Ticks" "Agents"
      "Prevalence" "Opinion" "Influence"
      "meme plus" "meme minus"
      "meme plus w" "meme minus w"
    )
  ]
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; META-INFLUENCEURS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to influenceurs
  if meta-mode = "Pourcent" [
  if meta-influencers-selection = "All" [
    let k round (count turtles * meta-influencers / 100)
    if k > 0 [
      ask n-of k turtles [
        if (prevalence >= prev-low and prevalence <= prev-high) [
          set influence 1
          set color yellow
          set meta-agents meta-agents + 1
        ]
      ]
    ]
  ]

  if meta-influencers-selection = "Right side" [
    set meta-influencers-droit round (count turtles * meta-influencers / 100)
    let candidates turtles with [opinion > 0]
    let k min list meta-influencers-droit count candidates
    if k > 0 [
      ask n-of k candidates [
        if (prevalence > prev-low and prevalence <= prev-high) [
          set influence 1
          set color yellow
          set meta-agents meta-agents + 1
        ]
      ]
    ]
  ]

  if meta-influencers-selection = "Left side" [
    set meta-influencers-gauche round (count turtles * meta-influencers / 100)
    let candidates turtles with [opinion < 0]
    let k min list meta-influencers-gauche count candidates
    if k > 0 [
      ask n-of k candidates [
        if (prevalence > prev-low and prevalence <= prev-high) [
          set influence 1
          set color yellow
          set meta-agents meta-agents + 1
        ]
      ]
    ]
  ]
]
  
  if meta-mode = "Nombre" [
  if meta-influencers-selection = "All" [
    let k meta-influencers
    let candidates turtles with [(prevalence > prev-low and prevalence <= prev-high)]
    if k > 0 [
      ask up-to-n-of k turtles [
          set influence 1
          set color yellow
          set meta-agents meta-agents + 1
        ]
      ]     
    ]
  
       

  if meta-influencers-selection = "Right side" [
    set meta-influencers-droit meta-influencers 
    let candidates turtles with [opinion > 0 and (prevalence > prev-low and prevalence <= prev-high)]
    let k min list meta-influencers-droit count candidates
    if k > 0 [
      ask up-to-n-of k candidates [
      
          set influence 1
          set color yellow
          set meta-agents meta-agents + 1
        ]
      ]
    ]

  if meta-influencers-selection = "Left side" [
    set meta-influencers-gauche meta-influencers 
    let candidates turtles with [opinion < 0 and (prevalence > prev-low and prevalence <= prev-high) ]
    let k min list meta-influencers-gauche count candidates
    if k > 0 [
      ask up-to-n-of k candidates [
        
          set influence 1
          set color yellow
          set meta-agents meta-agents + 1
        ]
      ]
    ]
  ]
 
  
end

to-report meta?
  report (color = yellow) or (influence = 1)
end

to maybe-set-opinion [ new-op ]
  let old-op opinion
  let bounded-op max list -1 min list 1 new-op

  if metablock and meta? and (sign old-op != sign bounded-op) [
    let mag max list (abs old-op) (abs bounded-op)
    set opinion (sign old-op) * mag
    stop
  ]
  set opinion bounded-op
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; CSV (bufferisé) — sans BOTH
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to-report csv-filename [mode-tag]
  report (word csv-basename "-" try "-" mode-tag "-" locale-format ".csv")
end

to csv-begin
  if not csv-export [ stop ]

  set csv-buffer []
  set csv-open? true

  if csv-mode = "Statistics" [
    set csv-file-stats csv-filename "stats"
    set csv-buffer lput (join-cols (list
    "try" "iter" "tick"
    "left_pct" "right_pct"
    "avg_opinion"
    "med_op_right" "med_op_left"
    "med_prev_right" "med_prev_left"
    "med_infl_right" "med_infl_left"
    "links_remove" "links_create" 
    "bridge_links"
    "inversion_pct" "change" "total" "fractale" "major"
    "interactions_per_iter" "majority_pct" "interactions_per_inversion"
    "meta_links" "meta_agents"
    "mean_prevalence" "median_prevalence" "median_opinion"
    "mean_abs_opinion"
    "mean_meme_stock" "mean_meme_derived_opinion"
    "mean_polarity_index" "meme_saturation_pct"
    "right_meme_polarization" "left_meme_polarization"
        "opinion_meme_gap"
    "ideologization_index"
    "ideologization_opinion_based")) csv-buffer
  ]

  if csv-mode = "Values" [
    set csv-file-values csv-filename "values"
    ;; memed RETIRÉ des Values CSV
    set csv-buffer lput (join-cols (list
      "try" "tick" "agent"
      "prevalence" "opinion" "influence"
      "meme_plus" "meme_minus"
      "meme_plus_w" "meme_minus_w"
    )) csv-buffer
  ]
end

to ensure-csv-ready
  if not csv-export [ stop ]
  if not csv-open? [ csv-begin ]
end

to csv-row-statistics
  ;; appelé seulement si csv-mode = "Statistics"
  let avg-opinion mean [opinion] of turtles
  let opR safe-median (turtles with [opinion >= 0]) "opinion"
  let opL safe-median (turtles with [opinion < 0])  "opinion"
  let prevR (safe-median (turtles with [opinion >= 0]) "prevalence") / 100
  let prevL (safe-median (turtles with [opinion < 0])  "prevalence") / 100
  let inflR safe-median (turtles with [opinion >= 0]) "influence"
  let inflL safe-median (turtles with [opinion < 0])  "influence"
  let leftpct  (count turtles with [opinion < 0])  / (pop / 100)
  let rightpct (count turtles with [opinion >= 0]) / (pop / 100)
  ;; bridge links = ties connecting opposite opinion signs
let bridge_links count links with [ (sign [opinion] of end1) != (sign [opinion] of end2) ]


  ;; --- UI monitor-aligned extras ---
  let interactions-per-iter ifelse-value (iter > 0) [ total / iter ] [ 0 ]
  let majority-pct %Major
  let interactions-per-inversion ifelse-value (change > 0) [ total / change ] [ 0 ]

  let mean-prevalence ifelse-value (any? turtles) [ mean [prevalence] of turtles ] [ 0 ]
  let median-prevalence safe-median turtles "prevalence"
  let median-opinion safe-median turtles "opinion"
  let mean-abs-opinion ifelse-value (any? turtles) [ mean [abs opinion] of turtles ] [ 0 ]

  ;; meme aggregates (only meaningful when use-memes? = true, but exported regardless)
  let mean-meme-stock ifelse-value (any? turtles) [ mean [meme-plus + meme-minus] of turtles ] [ 0 ]

  let mean-meme-derived-opinion ifelse-value (any? turtles) [
    mean [
      ifelse-value ((meme-plus-w + meme-minus-w) > 0)
        [ (meme-plus-w - meme-minus-w) / (meme-plus-w + meme-minus-w) ]
        [ 0 ]
    ] of turtles
  ] [ 0 ]

  let mean-pol-index mean-polarity-index
  let meme-sat meme-saturation-pct

  ;; Right/Left meme polarization within camps (quantity-based, for comparability with earlier monitors)
  let right-den sum [meme-plus + meme-minus] of turtles with [opinion >= 0]
  let right-num (sum [meme-plus] of turtles with [opinion >= 0]) - (sum [meme-minus] of turtles with [opinion >= 0])
  let right-meme-pol ifelse-value (right-den > 0) [ right-num / right-den ] [ 0 ]

  let left-den sum [meme-plus + meme-minus] of turtles with [opinion < 0]
  let left-num (sum [meme-plus] of turtles with [opinion < 0]) - (sum [meme-minus] of turtles with [opinion < 0])
  let left-meme-pol ifelse-value (left-den > 0) [ left-num / left-den ] [ 0 ]

  ;; Opinion–Meme Gap: absolute mismatch between expressed opinion and meme-derived opinion (weighted)
  let opinion-meme-gap ifelse-value (any? turtles) [
    mean [
      abs (opinion - (ifelse-value ((meme-plus-w + meme-minus-w) > 0)
        [ (meme-plus-w - meme-minus-w) / (meme-plus-w + meme-minus-w) ]
        [ 0 ]))
    ] of turtles
  ] [ 0 ]

    ;; Ideologization indices (two constructs, exported separately)
  ;; A) Meme-based: representational imbalance (quantity level)
  let ideologization-index ifelse-value (any? turtles) [
    ideologization-meme-based
  ] [ 0 ]

  ;; B) Opinion-based: expressed extremity anchored by prevalence
  let ideologization-opinion-based-val ifelse-value (any? turtles) [
    ideologization-opinion-based
  ] [ 0 ]


  set csv-buffer lput (join-cols (list
    fmt try
    fmt iter
    fmt ticks
    fmt leftpct
    fmt rightpct
    fmt avg-opinion
    fmt opR
    fmt opL
    fmt prevR
    fmt prevL
    fmt inflR
    fmt inflL
    fmt links-dead
    fmt links-create
    fmt bridge_links
    fmt inversion
    fmt change
    fmt total
    fmt fractale
    fmt major

    fmt interactions-per-iter
    fmt majority-pct
    fmt interactions-per-inversion

    fmt meta-links
    fmt meta-agents

    fmt mean-prevalence
    fmt median-prevalence
    fmt median-opinion
    fmt mean-abs-opinion

    fmt mean-meme-stock
    fmt mean-meme-derived-opinion
    fmt mean-pol-index
    fmt meme-sat
        fmt right-meme-pol
    fmt left-meme-pol
    fmt opinion-meme-gap
    fmt ideologization-index
    fmt ideologization-opinion-based-val
  )) csv-buffer

end


to csv-row-values
  ;; appelé seulement si csv-mode = "Values"
  if ticks < csv-values-start [ stop ]
  if (ticks mod csv-values-step) != 0 [ stop ]

  foreach sort turtles [ t ->
    set csv-buffer lput (join-cols (list
      fmt try
      fmt ticks
      fmt [who] of t
      fmt [prevalence] of t
      fmt [opinion] of t
      fmt [influence] of t
      fmt [meme-plus] of t
      fmt [meme-minus] of t
      fmt [meme-plus-w] of t
      fmt [meme-minus-w] of t
    )) csv-buffer
  ]
end

to csv-flush
  if empty? csv-buffer [ stop ]
  file-close-all

  if csv-mode = "Statistics" [
    if file-exists? csv-file-stats [ file-delete csv-file-stats ]
    file-open csv-file-stats
  ]
  if csv-mode = "Values" [
    if file-exists? csv-file-values [ file-delete csv-file-values ]
    file-open csv-file-values
  ]

  foreach csv-buffer [ line -> file-print line ]
  file-close
end

to csv-end
  ;; écriture finale du buffer
  if csv-open? [ csv-flush ]
  file-close-all
  set csv-buffer []
  set csv-open? false
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; GO
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to go
  ifelse (iter < max_iter) [

    if csv-export [ ensure-csv-ready ]

    if iter > 0 [ set Interactions (total / iter) ]
    if iter > 0 [ set %Major (major / iter * 100) ]
    set iter iter + 1
    set meta-create 0

    ;; EVENEMENTS (corrigé)
if auto_event [
  if (iter = tick-event) [
    event
    if repeat_event [
      set tick-event (tick-event + event-pace)
    ]
  ]
]


    ;; INJECTION AUTO
    if auto_inject? [ 
      if ticks = inject-tick [
        inject-memes
        if repeat-inject? [ set inject-tick (inject-tick + inject-pace) ]
      ]
    ]

    if meta-ok = true [ meta ]

    update-opinions
    if network = true [ update-networks ]
    recolor-links
    apply-link-visibility

    ;; OUTPUT Statistics
    if output = "Statistics" [
      let avg-opinion mean [opinion] of turtles
      let positive-opinion safe-median (turtles with [opinion >= 0]) "opinion"
      let negative-opinion safe-median (turtles with [opinion < 0])  "opinion"
      let positive-prevalence (safe-median (turtles with [opinion >= 0]) "prevalence") / 100
      let negative-prevalence (safe-median (turtles with [opinion < 0])  "prevalence") / 100
      let positive-influence safe-median (turtles with [opinion >= 0]) "influence"
      let negative-influence safe-median (turtles with [opinion < 0])  "influence"
      let Left%  (count turtles with [opinion < 0])  / (pop / 100)
      let Right% (count turtles with [opinion >= 0]) / (pop / 100)
      let ti iter

      output-print join-cols (list
        fmt try
        fmt ti
        fmt avg-opinion
        fmt positive-opinion
        fmt negative-opinion
        fmt positive-prevalence
        fmt negative-prevalence
        fmt positive-influence
        fmt negative-influence
        fmt Left%
        fmt Right%
        fmt links-dead
        fmt links-create
        fmt inversion
        fmt change
        fmt total
        fmt fractale
      )
    ]

    tick

    ifelse use-memes? [
      if (change > 1 and iter > 1) [ set fractale (ln total / ln change) ]
    ] [
      if (change > 1 and total > 1) [ set fractale (ln total) / (ln change) ]
    ]

    if (cumulative = false) [
      set change 0
      set total 0
    ]

    colorer

    if (refresh = true) [
      if ticks > 200 [ reset-ticks clear-plot ]
    ]

    if threshold <= (count turtles with [opinion > 0]) / (pop / 100) [
      set major major + 1
    ]

    ;; CSV buffer write selon mode
    if csv-export [
      if csv-mode = "Statistics" [ csv-row-statistics ]
      if csv-mode = "Values"     [ csv-row-values ]
    ]

  ] [

    ;; fin d'un try
    ifelse (try < nb_try) [ 
      if csv-export [ csv-end ]
      set try try + 1
      set major 0
      clear-turtles
      clear-plot
      set change 0
      set total 0
      set fractale 0
      set meta-links meta-min
      set iter 0
      set tick-event event-init
      set links-create 0
      set links-dead 0
      set meta-create 0
      set meta-agents 0
      set min-prevalence 0
      set max-prevalence 99

      ifelse (repet_data = true) [
        data
      ] [
        create
        set meta-links meta-min
        set inject-tick inject-base
      ]
    ] [
      if csv-export [ csv-end ]
      sound:play-note "Tubular Bells" 60 64 1
      stop
    ]
  ]
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; UPDATE OPINIONS (mèmes pondérés)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to update-opinions
  ask turtles [
    set opinion-previous opinion
    let target one-of link-neighbors

    if target != nobody [
      let raw-dprev ([prevalence] of target) - prevalence
      if raw-dprev < 1 [ set raw-dprev 0 ]
      let dprev raw-dprev / max-prevalence

      if dprev > 0 [
        let dmem abs(abs(opinion) - abs([opinion] of target))

        let base-prob dprev * prevalence-weight
        let pol-penalty max list adoption-floor (1 - polarization-factor * dmem)
        let p-adopt base-prob * pol-penalty * [influence] of target * (1 + [tx-bonus] of target)

        let sgn-emetteur sign ([opinion] of target)
        let gprob group-alignment-effective self sgn-emetteur
        let w group-impact-weight
        let alpha group-impact-alpha
        set p-adopt p-adopt * ((1 - w) + (w * (gprob ^ alpha)))

        if p-adopt < 0 [ set p-adopt 0 ]
        if p-adopt > 1 [ set p-adopt 1 ]

        if random-float 1 < p-adopt [
          set old-opinion opinion
          set proposed-opinion [opinion] of target

          ifelse use-memes? [
            transmit-memes target
            recompute-from-memes
          ] [
            maybe-set-opinion proposed-opinion
          ]

          if opinion = old-opinion [ stop ]
          set total total + 1

          let emitter-sign sign ([opinion] of target)
          let eligible? (reward-scope = "both") or
                        (reward-scope = "left-only"  and emitter-sign < 0) or
                        (reward-scope = "right-only" and emitter-sign >= 0)
          if eligible? [
            ask target [
              set tx-bonus min (list reward-cap (tx-bonus + reward-step))
            ]
          ]

          if reward-prev-delta > 0 [
            set prevalence min (list max-prevalence (prevalence + reward-prev-delta))
          ]

          set influence-previous influence
          if vary-influence = true [
            if abs(old-opinion) > abs(opinion) [
              set influence min (list 1 (influence + rate-infl))
              if (influence-previous < 1 and influence = 1) [
                if meta-ok = true [
                  if meta-links < meta-max [ set meta-links meta-links + 1 ]
                  set meta-agents meta-agents + 1
                ]
                set color yellow
              ]
            ]
            if abs(old-opinion) < abs(opinion) [
              set influence max (list 0 (influence - rate-infl))
              if (influence < influence-previous and influence-previous = 1) [
                if meta-ok = true [
                  set meta-agents meta-agents - 1
                  ifelse opinion >= 0 [ set color blue ] [ set color red ]
                ]
              ]
            ]
          ]

          if (sign old-opinion) != (sign opinion) [
            set change change + 1
          ]

          if change > 0 [
            set memes-per-change (((sum [meme-plus + meme-minus] of turtles) / change) / pop)
          ]
        ]
      ]
    ]

    ;; modulation prevalence (widget: mode_prev)
    if mode_prev = true [
      if prevalence > abs opinion * 100 [
        set prevalence prevalence - abs(opinion - opinion-previous) * influence * rate-mod
      ]
      if prevalence < abs opinion * 100 [
        set prevalence prevalence + abs(opinion - opinion-previous) * influence * rate-mod
      ]
      if prevalence < min-prevalence [ set prevalence min-prevalence ]
      if prevalence > max-prevalence [ set prevalence max-prevalence ]
    ]

    if random-float 1 < noise [
      let delta (random-float 0.4 - 0.2)
      maybe-set-opinion (opinion + delta)
    ]

    if use-memes? [ decay-memes ]
    update-3d self

    if (output = "Values") [ compute-statistics ]
  ]

  if reward-decay > 0 [
    ask turtles [ set tx-bonus max (list 0 (tx-bonus - reward-decay)) ]
  ]

  ifelse (total > 0)
    [ set inversion (100 * change / total) ]
    [ set inversion 0 ]
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; VALUES OUTPUT (memed RETIRÉ)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to compute-statistics
  if output = "Values" [
    output-print join-cols (list
      fmt try
      fmt ticks
      fmt who
      fmt prevalence
      fmt opinion
      fmt influence
      fmt meme-plus
      fmt meme-minus
      fmt meme-plus-w
      fmt meme-minus-w
    )
  ]
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; IMPORT SIMPLE (format existant) + WRAPPER
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to in_file
  in_file_simple
end

to in_file_simple
  carefully [
    set file-in user-file
    if (file-in != false) [
      set list_data []
      file-open file-in
      while [not file-at-end?] [
        ;; format attendu : tick prevalence opinion influence
        set list_data sentence list_data (list (list file-read file-read file-read file-read))
      ]
      file-close
      user-message "File uploaded (simple format)!"
      set in_data true
    ]
  ] [
    user-message "File read error"
  ]
  set choice_iter 0
  data
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; IMPORT VALUES CSV (nouveau) — charge un CSV Values multi-ticks
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to in_file_values
  carefully [
    set values_file_in user-file
    if values_file_in = false [ stop ]

    set list_values_data []
    file-open values_file_in

    if file-at-end? [ user-message "Empty file" stop ]
    let header file-read-line

    ;; détecter séparateur colonnes
    ifelse (position ";" header != false)
      [ set values_sep ";" ]
      [ set values_sep "," ]

    while [not file-at-end?] [
      let line file-read-line
      if line != "" [
        let cols split-by line values_sep
        set list_values_data lput cols list_values_data
      ]
    ]
    file-close

    user-message "File uploaded (values CSV)!"
  ] [
    user-message "Values file read error"
    stop
  ]

  data-values
end

to data-values
  clear-turtles
  clear-links

  let tick_to_load choice_iter

  ;; colonnes attendues (Values sans memed):
  ;; 0 try, 1 tick, 2 agent, 3 prevalence, 4 opinion, 5 influence,
  ;; 6 meme_plus, 7 meme_minus, 8 meme_plus_w, 9 meme_minus_w
  let rows filter [cols ->
      (length cols >= 10) and
      (to-number-locale (item 1 cols) values_sep = tick_to_load)
    ] list_values_data

  if empty? rows [
    user-message (word "No rows found for tick " tick_to_load)
    stop
  ]

  let n min list pop length rows
  let selected sublist rows 0 n

  set meta-agents 0

  create-turtles n [
    let cols item who selected

    set prevalence to-number-locale (item 3 cols) values_sep
    set opinion    to-number-locale (item 4 cols) values_sep
    set influence  to-number-locale (item 5 cols) values_sep

    set meme-plus    to-number-locale (item 6 cols) values_sep
    set meme-minus   to-number-locale (item 7 cols) values_sep
    set meme-plus-w  to-number-locale (item 8 cols) values_sep
    set meme-minus-w to-number-locale (item 9 cols) values_sep

    set opinion-previous opinion
    set influence-previous influence
    set tx-bonus 0

    ;; bornes prudentes
    if prevalence < 0 [ set prevalence 0 ]
    if prevalence > 99 [ set prevalence 99 ]
    if opinion < -1 [ set opinion -1 ]
    if opinion > 1 [ set opinion 1 ]
    if influence < 0 [ set influence 0 ]
    if influence > 1 [ set influence 1 ]

    ;; type & couleur
    ifelse opinion < 0 [
      set agent-type "Left side"
      set color red
    ] [
      set agent-type "Right side"
      set color blue
    ]

    if influence = 1 [
      set color yellow
      set meta-agents meta-agents + 1
    ]

    update-3d self
  ]

  update-networks
  apply-link-visibility
  recolor-links

  set repet_data true
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; I/O : DATA (simple) — utilisé par in_file_simple
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to data
  clear-turtles
  clear-links
  set meta-agents 0
  let tick_to_load choice_iter

  ifelse (is-list? list_data) [
    let filtered_data filter [ row -> first row = tick_to_load ] list_data
    
    if empty? filtered_data [
  let available remove-duplicates map [row -> first row] list_data
 
]

    create-turtles length filtered_data [
      let my_index who
      let agent_data item my_index filtered_data

      set prevalence item 1 agent_data
      set opinion    item 2 agent_data
      set influence  item 3 agent_data

      if influence = 1 [ set meta-agents meta-agents + influence ]

      set opinion-previous opinion
      set influence-previous influence
      set tx-bonus 0

      if opinion < 0 [ set color red  set agent-type "Left side"  ]
      if opinion > 0 [ set color blue set agent-type "Right side" ]
      if influence = 1 [ set color yellow ]

      init-memes-from-state
      update-3d self
    ]
  ] [
    set in_data false
    user-message "Read error"
  ]

  update-networks
  apply-link-visibility
  recolor-links

  influenceurs
  update-opinions
  set repet_data true
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; COLORATION
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to colorer
  ask turtles [
    ifelse meta? [ set color yellow ] [
      ifelse opinion >= 0 [ set color blue ] [ set color red ]
    ]
  ]
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; NETWORK
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to update-networks
  let doomed links with [
    abs([opinion] of end1 - [opinion] of end2) > (link-removal-threshold / 100)
  ]
  let doomedProb doomed with [ random-float 1 < prob ]
  let n-remove min (list linksdown count doomedProb)
  if n-remove > 0 [
    ask n-of n-remove doomedProb [ die ]
    set links-dead links-dead + n-remove
  ]

  let j linksup
  while [j > 0] [
    let t one-of turtles
    if t = nobody [ stop ]
    ask t [
      let myop opinion
      let candidates other turtles with [ not link-neighbor? myself ]
      let pool-homo candidates with [ abs(opinion - myop) < (link-formation-threshold / 100) ]
      let pool-bridge candidates with [ (sign opinion) != (sign myop) ]

      let friend nobody
      if any? pool-bridge and (random-float 1 < bridge-prob) [
        set friend max-one-of pool-bridge [ abs(opinion - myop) ]
      ]
      if (friend = nobody) and any? pool-homo [
        set friend min-one-of pool-homo [ abs(opinion - myop) ]
      ]

      if friend != nobody and (random-float 1 < prob) [
        create-link-with friend
        set links-create links-create + 1
        let same-sign? (sign opinion) = (sign [opinion] of friend)
        ask link-with friend [
          set color (ifelse-value same-sign? [ green ] [ gray ])
          set thickness linktick
          if show-links [ show-link ]
        ]
      ]
    ]
    set j j - 1
  ]
end

to meta
  if not network [ stop ]
  ask turtles [
    let pool other turtles with [
      color = yellow and
      not link-neighbor? myself and
      (count link-neighbors) < meta-links
    ]
    if any? pool [
      let friend one-of pool
      create-link-with friend
      let same-sign? (sign opinion) = (sign [opinion] of friend)
      ask link-with friend [
        set color (ifelse-value same-sign? [ green ] [ gray ])
        set thickness linktick
        if show-links [ show-link ]
      ]
    ]
  ]
end

to apply-link-visibility
  ifelse show-links [ ask links [ show-link ] ] [ ask links [ hide-link ] ]
end

to recolor-links
  ask links [
    let s1 sign [opinion] of end1
    let s2 sign [opinion] of end2
    ifelse s1 = s2 [ set color green ] [ set color gray ]
    set thickness linktick
  ]
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; EVENT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to event
  ask turtles [
    let event-prob random-float 1
    if event-prob <= event-prob-max [
      ifelse meme_set = true [
        if (to_left = false) [
          if agent-type = "Right side" [
            if opinion < 0 [ maybe-set-opinion (opinion + event_size) ]
          ]
        ]
        if (to_left = true) [
          if agent-type = "Left side" [
            if opinion > 0 [ maybe-set-opinion (opinion - event_size) ]
          ]
        ]
      ] [
        if (to_left = false) [
          if (opinion < high_meme and opinion > low_meme and prevalence < high-prev and prevalence > low-prev) [
            maybe-set-opinion (opinion + event_size)
            if (prev_change != 0) [ set prevalence min (list max-prevalence (prevalence + prev_change)) ]
          ]
        ]
        if (to_left = true) [
          if (opinion > low_meme and opinion < high_meme and prevalence > low-prev and prevalence < high-prev) [
            maybe-set-opinion (opinion - event_size)
            if (prev_change != 0) [ set prevalence min (list max-prevalence (prevalence + prev_change)) ]
          ]
        ]
      ]
      if use-memes? [ init-memes-from-state ]
    ]
  ]
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; UTILITAIRES DIVERS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to set-background-black
  ask patches [ set pcolor black ]
end

to update-3d [agt]
  ask agt [
    set x3d opinion * 16
    set y3d prevalence / 6
    set z3d influence * 16
    setxyz x3d y3d z3d
  ]
end

to-report safe-median [agentset varname]
  if not any? agentset [ report 0 ]
  report median [ runresult varname ] of agentset
end

to-report sign [x]
  ifelse x > 0 [ report 1 ] [ ifelse x < 0 [ report -1 ] [ report 0 ] ]
end

;; Meme Saturation (%)
to-report meme-saturation-pct
  if not use-memes? [ report 0 ]
  if not any? turtles [ report 0 ]
  let total-memes sum [meme-plus + meme-minus] of turtles
  let capacity meme-max * count turtles
  if capacity <= 0 [ report 0 ]
  report 100 * total-memes / capacity
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; IMPACT DE GROUPE
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to-report group-alignment-all [agt sign-ref]
  let nbrs [link-neighbors] of agt
  if not any? nbrs [ report 0.5 ]
  let same count nbrs with [ (sign opinion) = sign-ref ]
  report same / count nbrs
end

to-report group-alignment-k [agt sign-ref k]
  let nbrs [link-neighbors] of agt
  let deg count nbrs
  if deg = 0 [ report 0.5 ]
  let kk max list 1 min list deg floor k
  let agop [opinion] of agt
  let pool min-n-of kk nbrs [ abs(opinion - agop) ]
  if not any? pool [ report 0.5 ]
  let same count pool with [ (sign opinion) = sign-ref ]
  report same / count pool
end

to-report group-alignment-effective [agt sign-ref]
  ifelse (group-impact-mode = "k-nearest")
    [ report group-alignment-k agt sign-ref group-k ]
    [ report group-alignment-all agt sign-ref ]
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; MEMES : quantité + poids
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to-report initial-prevalence-to-memes [prev]
  report (prev / 99) * meme-max
end

to init-memes-from-state
  let totq initial-prevalence-to-memes prevalence

  ifelse opinion >= 0 [
    set meme-plus  totq * (0.5 + 0.5 * abs opinion)
    set meme-minus totq - meme-plus
  ] [
    set meme-minus totq * (0.5 + 0.5 * abs opinion)
    set meme-plus  totq - meme-minus
  ]

  set meme-plus-w  meme-plus  * meme-weight-mean
  set meme-minus-w meme-minus * meme-weight-mean

  if meme-plus < 0 [ set meme-plus 0 ]
  if meme-minus < 0 [ set meme-minus 0 ]
  if meme-plus-w < 0 [ set meme-plus-w 0 ]
  if meme-minus-w < 0 [ set meme-minus-w 0 ]
end

to-report draw-meme-weight
  let w meme-weight-mean
  if meme-weight-sd > 0 [
    set w (meme-weight-mean + (random-float (2 * meme-weight-sd) - meme-weight-sd))
  ]
  if w < meme-weight-min [ set w meme-weight-min ]
  if w > meme-weight-max [ set w meme-weight-max ]
  report w
end

to recompute-from-memes
  let totw meme-plus-w + meme-minus-w
  if totw < 1e-6 [ set totw 1e-6 ]
  set proposed-opinion ((meme-plus-w - meme-minus-w) / totw)
  maybe-set-opinion proposed-opinion

  let totq meme-plus + meme-minus
  let scaled (totq / meme-max) * 99
  if scaled < 0 [ set scaled 0 ]
  if scaled > 99 [ set scaled 99 ]
  set prevalence scaled
end

to decay-memes
  if meme-decay <= 0 [ stop ]
  let f (1 - meme-decay)
  set meme-plus    max list 0 (meme-plus    * f)
  set meme-minus   max list 0 (meme-minus   * f)
  set meme-plus-w  max list 0 (meme-plus-w  * f)
  set meme-minus-w max list 0 (meme-minus-w * f)
end

to transmit-memes [emitter]
  let sgn sign [opinion] of emitter
  let w draw-meme-weight
  let leak (meme-anti-leak * meme-gain)

  ifelse sgn >= 0 [
    set meme-plus   meme-plus + meme-gain
    set meme-plus-w meme-plus-w + (w * meme-gain)

    set meme-minus   max list 0 (meme-minus - leak)
    set meme-minus-w max list 0 (meme-minus-w - (w * leak))
  ] [
    set meme-minus   meme-minus + meme-gain
    set meme-minus-w meme-minus-w + (w * meme-gain)

    set meme-plus   max list 0 (meme-plus - leak)
    set meme-plus-w max list 0 (meme-plus-w - (w * leak))
  ]

  let totq meme-plus + meme-minus
  if totq > meme-max [
    let factor meme-max / totq
    set meme-plus    meme-plus    * factor
    set meme-minus   meme-minus   * factor
    set meme-plus-w  meme-plus-w  * factor
    set meme-minus-w meme-minus-w * factor
  ]
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; INJECTION
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to inject-memes
  let base-pool turtles with [
    opinion >= inject-low_meme and opinion <= inject-high_meme and
    prevalence >= inject-low-prev and prevalence <= inject-high-prev
  ]

  let pool base-pool
  if inject-metas-only [
    set pool base-pool with [ color = yellow ]
  ]

  ask pool [
    if random-float 1 <= inject-prob-max [
      let w inject-weight
      if w < meme-weight-min [ set w meme-weight-min ]
      if w > meme-weight-max [ set w meme-weight-max ]

      if inject-amount < 0 [ stop ]

      if inject-sign = "plus" [
        set meme-plus   meme-plus + inject-amount
        set meme-plus-w meme-plus-w + (w * inject-amount)
      ]
      if inject-sign = "minus" [
        set meme-minus   meme-minus + inject-amount
        set meme-minus-w meme-minus-w + (w * inject-amount)
      ]

      let totq meme-plus + meme-minus
      if totq > meme-max [
        let factor meme-max / totq
        set meme-plus    meme-plus    * factor
        set meme-minus   meme-minus   * factor
        set meme-plus-w  meme-plus-w  * factor
        set meme-minus-w meme-minus-w * factor
      ]

      if use-memes? [ recompute-from-memes ]
    ]
  ]
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Additional reporter
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to-report mean-polarity-index
  let total-plus  sum [meme-plus] of turtles
  let total-minus sum [meme-minus] of turtles
  ifelse (total-plus + total-minus > 0)
    [ report (total-plus - total-minus) / (total-plus + total-minus) ]
    [ report 0 ]
end

;; ---------------------------------------------------------------------------
;; IDEOLOGIZATION INDICES (two distinct constructs)
;; ---------------------------------------------------------------------------

;; 1) Meme-based ideologization: representational imbalance (quantity level)
to-report ideologization-meme-based
  if not any? turtles [ report 0 ]
  report mean [ (abs (meme-plus - meme-minus) / 100) ] of turtles
end

;; 2) Opinion-based ideologization: expressed extremity anchored by prevalence
to-report ideologization-opinion-based
  if not any? turtles [ report 0 ]
  report mean [ (abs opinion) * (prevalence / 99) ] of turtles
end

]]></code>
  <widgets>
    <view3d wrappingAllowedZ="true" x="0" wrappingAllowedX="true" y="0" minPycor="0" height="423" showTickCounter="true" patchSize="12.0" fontSize="10" wrappingAllowedY="true" width="903" tickCounterLabel="ticks" maxPycor="18" updateMode="0" frameRate="30.0" maxPzcor="18" maxPxcor="20" minPxcor="-20" minPzcor="0"></view3d>
    <button x="12" y="60" height="33" disableUntilTicks="false" forever="false" kind="Observer" width="64" sizeVersion="0">event</button>
    <switch x="79" y="61" height="33" on="true" variable="to_left" display="to_left" width="90" sizeVersion="0"></switch>
    <switch x="173" y="62" height="33" on="true" variable="meme_set" display="meme_set" width="97" sizeVersion="0"></switch>
    <slider x="14" step="0.01" y="152" max="2" display="event_size" height="33" min="0" direction="Horizontal" default="0.25" variable="event_size" width="276" sizeVersion="0"></slider>
    <input x="83" multiline="false" y="228" height="60" variable="high_meme" type="number" width="66" sizeVersion="0">0.5</input>
    <input x="12" multiline="false" y="228" height="60" variable="low_meme" type="number" width="66" sizeVersion="0">0.0</input>
    <input x="153" multiline="false" y="228" height="60" variable="high-prev" type="number" width="67" sizeVersion="0">100.0</input>
    <slider x="13" step="1" y="190" max="100" display="prev_change" height="33" min="-50" direction="Horizontal" default="8.0" variable="prev_change" width="277" sizeVersion="0"></slider>
    <slider x="15" step="0.01" y="99" max="1" width="274" display="event-prob-max" height="50" min="0" direction="Horizontal" default="0.5" variable="event-prob-max"></slider>
    <input x="224" multiline="false" y="228" height="60" variable="low-prev" type="number" width="67" sizeVersion="0">0.0</input>
    <button x="1350" y="22" height="40" disableUntilTicks="false" forever="false" kind="Observer" width="94" display="inject-memes">inject-memes</button>
    <slider x="1344" step="1" y="126" max="100" width="286" display="inject-base" height="50" min="0" direction="Horizontal" default="20.0" variable="inject-base"></slider>
    <switch x="1344" y="72" height="40" on="true" variable="auto_inject?" width="97" display="auto_inject?"></switch>
    <switch x="1455" y="72" height="40" on="true" variable="repeat-inject?" width="105" display="repeat-inject?"></switch>
    <slider x="1344" step="1" y="187" max="200" width="286" display="inject-pace" height="50" min="0" direction="Horizontal" default="20.0" variable="inject-pace"></slider>
    <slider x="1344" step=".01" y="246" max="1" width="285" display="inject-prob-max" height="50" min="0" direction="Horizontal" default="0.3" variable="inject-prob-max"></slider>
    <slider x="1344" step="1" y="304" max="500" width="285" display="inject-amount" height="50" min="0" direction="Horizontal" default="40.0" variable="inject-amount"></slider>
    <slider x="1344" step="0.1" y="362" max="5" width="284" display="inject-weight" height="50" min="0" direction="Horizontal" default="2.0" variable="inject-weight"></slider>
    <slider x="1344" step=".01" y="420" max="1" width="283" display="inject-low_meme" height="50" min="-1" direction="Horizontal" default="-0.3" variable="inject-low_meme"></slider>
    <slider x="1344" step=".01" y="477" max="1" width="282" display="inject-high_meme" height="50" min="-1" direction="Horizontal" default="0.3" variable="inject-high_meme"></slider>
    <slider x="1344" step="1" y="533" max="99" width="282" display="inject-low-prev" height="50" min="0" direction="Horizontal" default="10.0" variable="inject-low-prev"></slider>
    <slider x="1344" step="1" y="589" max="99" width="282" display="inject-high-prev" height="50" min="0" direction="Horizontal" default="60.0" variable="inject-high-prev"></slider>
    <chooser x="1345" y="647" height="60" variable="inject-sign" current="0" width="282" display="inject-sign">
      <choice type="string" value="plus"></choice>
      <choice type="string" value="minus"></choice>
    </chooser>
    <switch x="1457" y="23" height="40" on="true" variable="inject-metas-only" width="128" display="inject-metas-only"></switch>
    <switch x="1640" y="68" height="40" on="true" variable="csv-export" width="90" display="csv-export"></switch>
    <chooser x="1641" y="111" height="60" variable="locale-format" current="0" width="100" display="locale-format">
      <choice type="string" value="FR"></choice>
      <choice type="string" value="EN"></choice>
    </chooser>
    <chooser x="1744" y="110" height="60" variable="csv-mode" current="0" width="114" display="csv-mode">
      <choice type="string" value="Statistics"></choice>
      <choice type="string" value="Values"></choice>
    </chooser>
    <input x="1639" multiline="false" y="177" height="60" variable="csv-basename" type="string" width="188">Sim1</input>
    <monitor x="1639" precision="2" y="407" height="60" fontSize="11" width="100" display="csv-file-stats">csv-file-stats</monitor>
    <slider x="1644" step="1" y="240" max="100" width="181" display="csv-values-start" height="50" min="0" direction="Horizontal" default="0.0" variable="csv-values-start"></slider>
    <slider x="1648" step="1" y="297" max="50" width="181" display="csv-values-step" height="50" min="0" direction="Horizontal" default="1.0" variable="csv-values-step"></slider>
    <monitor x="1744" precision="2" y="408" height="60" fontSize="11" width="100" display="csv-file-values">csv-file-values</monitor>
    <button x="1753" y="478" height="40" disableUntilTicks="false" forever="false" kind="Observer" width="90">in_file_values</button>
    <button x="1647" y="478" height="39" disableUntilTicks="false" forever="false" kind="Observer" width="94">in_file</button>
    <input x="1709" multiline="false" y="528" height="60" variable="choice_iter" type="number" width="73" sizeVersion="0">0.0</input>
    <button x="1667" y="355" height="40" disableUntilTicks="false" forever="false" kind="Observer" width="70" display="csv open">csv-begin</button>
    <button x="1746" y="356" height="40" disableUntilTicks="false" forever="false" kind="Observer" width="68" display="csv close">csv-end</button>
    <input x="13" multiline="false" y="291" height="60" variable="tick-event" type="number" width="66" sizeVersion="0">2150.0</input>
    <input x="84" multiline="false" y="292" height="60" variable="event-pace" type="number" width="62" sizeVersion="0">300.0</input>
    <slider x="153" step="1" y="290" max="200" display="event-init" height="40" min="0" direction="Horizontal" default="50.0" variable="event-init" width="102" sizeVersion="0"></slider>
    <button x="87" y="7" height="46" disableUntilTicks="false" forever="false" kind="Observer" display="Setup" width="76" sizeVersion="0">setup</button>
    <button x="13" y="5" height="48" disableUntilTicks="false" forever="true" kind="Observer" display="Go" width="66" sizeVersion="0">go</button>
    <input x="171" multiline="false" y="0" height="60" variable="pop" type="number" width="65" sizeVersion="0">500.0</input>
    <input x="240" multiline="false" y="0" height="60" variable="max_iter" type="number" width="61" sizeVersion="0">2000.0</input>
    <monitor x="111" precision="2" y="456" height="45" fontSize="11" display="Influence right" width="94" sizeVersion="0"><![CDATA[median [influence] of turtles with [opinion > 0] * 100]]></monitor>
    <monitor x="10" precision="2" y="456" height="45" fontSize="11" display="Influence left" width="98" sizeVersion="0"><![CDATA[median [influence] of turtles with [opinion < 0] * 100]]></monitor>
    <monitor x="211" precision="17" y="457" height="45" fontSize="11" display="Try" width="77" sizeVersion="0">try</monitor>
    <monitor x="110" precision="2" y="410" height="45" fontSize="11" display="Agents % right" width="97" sizeVersion="0"><![CDATA[(count turtles with [opinion >= 0]) / (pop / 100)]]></monitor>
    <monitor x="11" precision="2" y="409" height="45" fontSize="11" display="Agents % left" width="97" sizeVersion="0"><![CDATA[(count turtles with [opinion < 0]) / (pop / 100)]]></monitor>
    <monitor x="211" precision="17" y="409" height="45" fontSize="11" display="iter" width="77" sizeVersion="0">iter</monitor>
    <switch x="16" y="355" height="33" on="true" variable="auto_event" display="auto_event" width="90" sizeVersion="0"></switch>
    <switch x="111" y="356" height="33" on="true" variable="repeat_event" display="repeat_event" width="101" sizeVersion="0"></switch>
    <chooser x="1700" y="595" height="45" variable="Output" current="0" display="Output" width="95" sizeVersion="0">
      <choice type="string" value="None"></choice>
      <choice type="string" value="Values"></choice>
      <choice type="string" value="Statistics"></choice>
    </chooser>
    <input x="217" multiline="false" y="344" height="60" variable="threshold" type="number" width="66" sizeVersion="0">50.01</input>
    <input x="306" multiline="false" y="1" height="60" variable="nb_try" type="number" width="64" sizeVersion="0">1.0</input>
    <input x="377" multiline="false" y="0" height="60" variable="noise" type="number" width="73" sizeVersion="0">0.02</input>
    <chooser x="299" y="73" height="45" variable="meta-influencers-selection" current="1" display="meta-influencers-selection" width="219" sizeVersion="0">
      <choice type="string" value="None"></choice>
      <choice type="string" value="All"></choice>
      <choice type="string" value="Right side"></choice>
      <choice type="string" value="Left side"></choice>
    </chooser>
    <slider x="301" step="1" y="122" max="100" display="meta-influencers" height="33" min="1" direction="Horizontal" default="12.0" variable="meta-influencers" width="219" sizeVersion="0"></slider>
    <slider x="619" step="0.01" y="505" max="1" display="reward-step" height="33" min="0" direction="Horizontal" default="0.3" variable="reward-step" width="180" sizeVersion="0"></slider>
    <slider x="986" step="0.1" y="504" max="5" display="reward-prev-delta" height="34" min="0" direction="Horizontal" default="0.3" variable="reward-prev-delta" width="169" sizeVersion="0"></slider>
    <slider x="1166" step="0.001" y="503" max="0.05" display="reward-decay" height="33" min="0" direction="Horizontal" default="0.003" variable="reward-decay" width="173" sizeVersion="0"></slider>
    <slider x="802" step="0.01" y="504" max="1" display="reward-cap" height="33" min="0" direction="Horizontal" default="0.85" variable="reward-cap" width="176" sizeVersion="0"></slider>
    <switch x="453" y="38" height="33" on="true" variable="cumulative" display="cumulative" width="90" sizeVersion="0"></switch>
    <switch x="454" y="0" height="33" on="false" variable="refresh" display="refresh" width="90" sizeVersion="0"></switch>
    <slider x="1038" step="0.1" y="657" max="6" width="288" display="meme-weight-mean" height="50" min="0.2" direction="Horizontal" default="1.0" variable="meme-weight-mean"></slider>
    <slider x="1038" step="0.01" y="715" max="1" width="290" display="meme-weight-sd" height="50" min="0" direction="Horizontal" default="0.1" variable="meme-weight-sd"></slider>
    <chooser x="849" y="717" height="45" variable="group-impact-mode" current="0" display="group-impact-mode" width="120" sizeVersion="0">
      <choice type="string" value="all"></choice>
      <choice type="string" value="k-nearest"></choice>
    </chooser>
    <slider x="730" step="0.1" y="714" max="10" width="305" display="meme-weight-max" height="50" min="0.1" direction="Horizontal" default="5.0" variable="meme-weight-max"></slider>
    <slider x="731" step="0.1" y="657" max="5" width="301" display="meme-weight-min" height="50" min="0.1" direction="Horizontal" default="1.0" variable="meme-weight-min"></slider>
    <input x="389" multiline="false" y="276" height="60" variable="linksdown" type="number" width="73" sizeVersion="0">15.0</input>
    <switch x="294" y="275" height="40" on="true" variable="network" width="90" display="network"></switch>
    <input x="468" multiline="false" y="276" height="60" variable="linksup" type="number" width="70" sizeVersion="0">5.0</input>
    <input x="541" multiline="false" y="275" height="60" variable="prob" type="number" width="73" sizeVersion="0">0.4</input>
    <input x="371" multiline="false" y="199" height="60" variable="prev-low" type="number" width="69" sizeVersion="0">60.0</input>
    <input x="301" multiline="false" y="198" height="60" variable="prev-high" type="number" width="64" sizeVersion="0">100.0</input>
    <switch x="421" y="161" height="33" on="true" variable="meta-ok" display="meta-ok" width="90" sizeVersion="0"></switch>
    <switch x="300" y="160" height="33" on="true" variable="vary-influence" display="vary-influence" width="117" sizeVersion="0"></switch>
    <input x="444" multiline="false" y="196" height="60" variable="meta-min" type="number" width="66" sizeVersion="0">4.0</input>
    <switch x="292" y="320" height="40" on="false" variable="show-links" width="94" display="show-links"></switch>
    <switch x="622" y="588" height="61" on="true" variable="use-memes?" width="102" display="use-memes?"></switch>
    <input x="1128" multiline="false" y="595" height="60" variable="meme-decay" type="number" width="78" sizeVersion="0">5.0E-5</input>
    <input x="1029" multiline="false" y="594" height="60" variable="meme-anti-leak" type="number" width="97" sizeVersion="0">0.0</input>
    <input x="946" multiline="false" y="594" height="60" variable="meme-gain" type="number" width="79" sizeVersion="0">0.8</input>
    <input x="731" multiline="false" y="590" height="60" variable="meme-max" type="number" width="88" sizeVersion="0">120.0</input>
    <chooser x="823" y="590" height="60" variable="reward-scope" current="0" display="reward-scope" width="119" sizeVersion="0">
      <choice type="string" value="both"></choice>
      <choice type="string" value="left-only"></choice>
      <choice type="string" value="right-only"></choice>
    </chooser>
    <slider x="873" step="0.1" y="545" max="3" display="group-impact-alpha" height="33" min="0.2" direction="Horizontal" default="1.2" variable="group-impact-alpha" width="179" sizeVersion="0"></slider>
    <slider x="1055" step="1" y="545" max="20" display="group-k" height="33" min="1" direction="Horizontal" default="10.0" variable="group-k" width="178" sizeVersion="0"></slider>
    <slider x="692" step="0.01" y="545" max="1" display="group-impact-weight" height="33" min="0" direction="Horizontal" default="0.41" variable="group-impact-weight" width="179" sizeVersion="0"></slider>
    <slider x="288" step="0.1" y="593" max="2" display="prevalence-weight" height="33" min="0" direction="Horizontal" default="1.2" variable="prevalence-weight" width="326" sizeVersion="0"></slider>
    <slider x="291" step="0.01" y="631" max="0.1" display="adoption-floor" height="33" min="0" direction="Horizontal" default="0.04" variable="adoption-floor" width="321" sizeVersion="0"></slider>
    <slider x="289" step="0.01" y="555" max="1" display="polarization-factor" height="33" min="0.0" direction="Horizontal" default="0.06" variable="polarization-factor" width="322" sizeVersion="0"></slider>
    <monitor x="195" precision="2" y="678" height="59" fontSize="12" display="%Major right " width="91" sizeVersion="0">%Major</monitor>
    <monitor x="97" precision="2" y="676" height="57" fontSize="12" display="Inter/iter" width="95" sizeVersion="0">Interactions</monitor>
    <monitor x="8" precision="2" y="677" height="57" fontSize="11" display="Inter/ inv" width="86" sizeVersion="0">total / change</monitor>
    <monitor x="192" precision="0" y="741" height="49" fontSize="12" display="meta-links" width="94" sizeVersion="0">meta-links</monitor>
    <monitor x="92" precision="0" y="740" height="47" fontSize="11" display="Inversions" width="98" sizeVersion="0">change</monitor>
    <monitor x="3" precision="0" y="739" height="46" fontSize="11" display="Interactions" width="91" sizeVersion="0">total</monitor>
    <monitor x="394" precision="8" y="674" height="60" fontSize="11" width="100" display="Right Meme Polarization "><![CDATA[mean [meme-plus] of turtles with [opinion >= 0]]]></monitor>
    <monitor x="498" precision="8" y="675" height="60" fontSize="11" width="100" display="Left Meme Polarization"><![CDATA[mean [meme-minus] of turtles with [opinion < 0]]]></monitor>
    <monitor x="603" precision="2" y="740" height="60" units="%" fontSize="11" width="100" display=" Meme Saturation">meme-saturation-pct</monitor>
    <monitor x="603" precision="10" y="676" height="60" fontSize="11" width="100" display="MMDO (Mean Meme-derived Opinion)"><![CDATA[mean [
ifelse-value (meme-plus + meme-minus > 0)
[(meme-plus - meme-minus) / (meme-plus + meme-minus)]
[0]
] of turtles]]></monitor>
    <monitor x="292" precision="17" y="735" height="60" fontSize="11" width="100" display="MPI (Mean Polarity Index)">mean-polarity-index</monitor>
    <monitor x="290" precision="8" y="674" height="60" fontSize="11" width="100" display="Mean Meme Stock">mean [meme-plus + meme-minus] of turtles</monitor>
    <monitor x="496" precision="4" y="738" height="60" fontSize="11" width="100" display="Ideologization Index (meme based)">mean [abs (meme-plus - meme-minus)] of turtles</monitor>
    <monitor x="394" precision="10" y="738" height="60" fontSize="11" width="100" display="Opinion–Meme Gap">mean [abs(opinion - ((meme-plus - meme-minus) /
      max list 1e-6 (meme-plus + meme-minus)))] of turtles</monitor>
    <switch x="292" y="513" height="33" on="false" variable="mode_prev" display="mode_prev" width="90" sizeVersion="0"></switch>
    <slider x="387" step="0.01" y="514" max="1" display="rate-mod" height="33" min="0" direction="Horizontal" default="0.4" variable="rate-mod" width="127" sizeVersion="0"></slider>
    <slider x="389" step="0.01" y="338" max="0.3" display="linktick" height="33" min="0.1" direction="Horizontal" default="0.2" variable="linktick" width="175" sizeVersion="0"></slider>
    <slider x="296" step="0.01" y="451" max="1" display="bridge-prob" height="33" min="0" direction="Horizontal" default="0.1" variable="bridge-prob" width="320" sizeVersion="0"></slider>
    <slider x="295" step="0.01" y="375" max="1" display="link-removal-threshold" height="33" min="0" direction="Horizontal" default="0.2" variable="link-removal-threshold" width="318" sizeVersion="0"></slider>
    <slider x="294" step="0.01" y="413" max="1" display="link-formation-threshold" height="33" min="0" direction="Horizontal" default="0.4" variable="link-formation-threshold" width="320" sizeVersion="0"></slider>
    <input x="519" multiline="false" y="493" height="60" variable="rate-infl" type="number" width="68" sizeVersion="0">0.01</input>
    <monitor x="110" precision="2" y="565" height="45" fontSize="11" display="Preval. right" width="92" sizeVersion="0"><![CDATA[median [prevalence] of turtles with [opinion > 0]]]></monitor>
    <monitor x="199" precision="17" y="613" height="45" fontSize="11" display="Links-create" width="89" sizeVersion="0">links-create</monitor>
    <monitor x="9" precision="17" y="615" height="45" fontSize="11" display="Influencers" width="87" sizeVersion="0">meta-agents</monitor>
    <monitor x="12" precision="2" y="512" height="45" fontSize="11" display="Opinion left" width="99" sizeVersion="0"><![CDATA[abs (median [opinion * 100] of turtles with [opinion < 0])]]></monitor>
    <monitor x="12" precision="2" y="564" height="45" fontSize="11" display="Preval. left" width="97" sizeVersion="0"><![CDATA[abs(median [prevalence] of turtles with [opinion < 0])]]></monitor>
    <monitor x="207" precision="2" y="513" height="45" fontSize="11" display="Inversion %" width="81" sizeVersion="0">inversion</monitor>
    <monitor x="208" precision="4" y="563" height="45" fontSize="11" display="Dim. fractale" width="79" sizeVersion="0">fractale</monitor>
    <monitor x="114" precision="2" y="512" height="45" fontSize="11" display="Opinion right" width="88" sizeVersion="0"><![CDATA[median [opinion * 100] of turtles with [opinion > 0]]]></monitor>
    <monitor x="103" precision="4" y="613" height="45" fontSize="11" display="Links-remove" width="86" sizeVersion="0">links-dead</monitor>
    <input x="515" multiline="false" y="196" height="60" variable="meta-max" type="number" width="70" sizeVersion="0">8.0</input>
    <switch x="516" y="159" height="33" on="true" variable="metablock" display="metablock" width="90" sizeVersion="0"></switch>
    <button x="547" y="39" height="54" disableUntilTicks="false" forever="false" kind="Observer" display="Influent" width="75" sizeVersion="0">set meta-create 0
influenceurs
meta</button>
    <chooser x="523" y="96" height="60" variable="meta-mode" current="0" width="100" display="meta-mode">
      <choice type="string" value="Nombre"></choice>
      <choice type="string" value="Pourcent"></choice>
    </chooser>
    <plot x="623" autoPlotX="true" yMax="70.0" autoPlotY="true" yAxis="Proportions" y="18" xMin="0.0" height="473" legend="true" xMax="200.0" yMin="30.0" xAxis="Iterations" display="Curves of agents" width="709" sizeVersion="0">
      <setup></setup>
      <update></update>
      <pen interval="1.0" mode="0" display="Agents % right" color="-14985354" legend="true">
        <setup></setup>
        <update><![CDATA[if ticks > 0 [plot (count turtles with [opinion >= 0] * 100 / pop) ]]]></update>
      </pen>
      <pen interval="1.0" mode="0" display="Right Meme Polarization " color="-8990512" legend="true">
        <setup></setup>
        <update><![CDATA[if ticks > 0 and use-memes? [plot mean [meme-plus] of turtles with [opinion >= 0] ]]]></update>
      </pen>
      <pen interval="1.0" mode="0" display="Left Meme Polarization" color="-1069655" legend="true">
        <setup></setup>
        <update><![CDATA[if ticks > 0 and use-memes? [plot mean [meme-minus] of turtles with [opinion < 0]]]]></update>
      </pen>
      <pen interval="1.0" mode="0" display="Agents % left" color="-5298144" legend="true">
        <setup></setup>
        <update><![CDATA[if ticks > 0 [plot (count turtles with [opinion < 0] * 100 / pop) ]]]></update>
      </pen>
    </plot>
  </widgets>
  <info><![CDATA[
---

# WHAT IS IT?

This simulator models how opinions spread and evolve in a connected population (multi-agent system).
Each agent has an **opinion** (−1 to +1), a **prevalence** (0–99), an **influence** (0–1), and **social links**.
The model tracks the co-evolution of opinions, prevalence (depth of internal representations), influence, and the network structure.

### 3D Representation

* **X**: opinion (−1 left, +1 right)
* **Y**: prevalence (0–99)
* **Z**: influence (0–1)
  Colors: **blue** (right), **red** (left), **yellow** (meta-influencer).
  Links: **green** (same sign), **gray** (opposite signs).

---

# HOW TO USE

1. Choose the population size with **`pop`**.
2. Click **Setup** (creates agents, black background, initializes `tick-event` to `event-init`).
3. Click **Go** to run/pause.

---

# GENERAL CONTROLS

* **Setup**: initialize agents/network; sets `tick-event ← event-init`.
* **Go**: start/stop the simulation.
* **in_file**: load agent states from a file (for `data`).
* **refresh**: resets plots after ~200 ticks.
* **cumulative**: if OFF, resets `change`/`total` every tick.
* **output**: *None | Statistics | Values | File*.

---

# POPULATION & ITERATIONS

* **`pop`**: number of agents (e.g., 100–5000).
* **`nb_try`**, **`max_iter`**, **`threshold`**: repetitions, trial length, majority threshold.
* **`choice_iter`**: iteration to replay when loading from file.

---

# SOCIAL NETWORK (link dynamics)

* **`link-removal-threshold`**: opinion distance (in %) above which a link may be cut.
* **`link-formation-threshold`**: maximum distance to allow a new link.
* **`prob`**: probability applied to deletions/formations.
* **`linksdown` / `linksup`**: caps on links removed/created per tick.
* **`bridge-prob`**: chance to create **bridges** across opposing camps.
* **`show-links?`**: toggle link visibility; **`linktick`**: visual thickness.

---

# META-INFLUENCERS

Agents with fixed high influence (influence = 1).

* **`meta-influencers-selection`**: *All / Right side / Left side*.
* **`meta-mode` / `meta-influencers`**: share of agents promoted to “meta”.
* **`prev-low` / `prev-high`**: prevalence eligibility bounds.
* **`meta-min` / `meta-max` / `meta-links`**: min/max and current quota of meta links.
* **`meta-ok`**: **enables dynamic meta linking** even if `vary-influence` = OFF.
* **`vary-influence`**: if ON, influence increases after successes and decreases after setbacks.
* **`metablock`**: if ON, metas **cannot flip sign** (veto on polarity changes).

> At initialization (`setup`) **and** at the start of each new trial, the model sets
> `meta-links ← meta-min` if **`vary-influence` = true** **or** **`meta-ok` = true** (as in your code).

---

# OPINION & PREVALENCE DYNAMICS

* **`rate-infl`**: speed of influence updates after adoption.
* **`noise`**: probability of additive opinion noise.
* **`polarization-factor`**: penalizes adoption across large opinion gaps.
* **`prevalence-weight`**: weight of prevalence differences in adoption.
* **`adoption-floor`**: minimum adoption probability (avoids strict zero).

### Prevalence modulation (renamed in code)

* **`mod-prev`** (formerly `modulation-prevalence`): ON to adapt prevalence to current vs previous opinion.
* **`Rate-mod`** (formerly `rate-modulation`): adjustment intensity.

---

# GROUP EFFECT

* **`group-impact-mode`**: *all* (all linked neighbors) or *k-nearest*.
* **`group-k`**: number of neighbors in *k-nearest* mode.
* **`group-impact-weight`**: weight of neighborhood alignment in adoption.
* **`group-impact-alpha`**: non-linearity

  * `<1`: small aligned clusters matter more,
  * `=1`: linear,
  * `>1`: only large aligned majorities matter.

---

# REWARD MECHANISM

A successful emitter (who convinces a neighbor) receives a temporary **bonus** (**`tx-bonus`**) that boosts future persuasion.

* **`reward-step`**: bonus increment per success.
* **`reward-cap`**: cap on cumulative bonus.
* **`reward-scope`**: *both / left-only / right-only*.
* **`reward-prev-delta`**: increase in the **target’s** prevalence after adoption (optional).
* **`reward-decay`**: bonus decay over ticks.

---

# Meme-Based Representation (Weighted Memes + Targeted Injection)

When **`use-memes?`** is ON, opinions and prevalence are computed from internal “meme” stocks.  
This version distinguishes **meme quantity** (how many representations an agent holds) from **meme weight** (how strongly each representation shapes the opinion).

---

## 1) Two levels: Quantity vs Weight

### Meme quantity → **Prevalence**
- **`meme-plus`**, **`meme-minus`** store how many pro/anti memes the agent holds.  
- **Prevalence (0–99)** is derived from the total quantity:  
  `meme-plus + meme-minus` rescaled to 0–99.

**Interpretation:** prevalence approximates how “rich” an agent’s internal representation system is (how many arguments/frames are available).

### Meme weight → **Opinion**
- **`meme-plus-w`**, **`meme-minus-w`** store the **cumulative weighted strength** of pro/anti memes.  
- Opinion is computed from the **weighted balance**:

\[
opinion = \frac{meme\text{-}plus\text{-}w - meme\text{-}minus\text{-}w}{meme\text{-}plus\text{-}w + meme\text{-}minus\text{-}w}
\]

- If pro-weights dominate → opinion moves toward **+1**
- If anti-weights dominate → opinion moves toward **−1**
- If balanced → opinion stays near **0**

A tiny denominator safeguard is used to avoid division by zero.

---

## 2) Weighted transmission during interactions

When an agent is influenced, the receiver gets:
- a **quantity increment** (`meme-gain`) on the side of the emitter (plus or minus),
- and a **weight increment** proportional to that quantity.

### Weight distribution parameters
- **`meme-weight-mean`** *(typical 0.2–3.0)*: average strength of newly acquired memes.  
  - Low values → many memes are needed to polarize opinions.  
  - High values → opinions polarize faster, even with small meme quantities.

- **`meme-weight-sd`** *(typical 0.0–1.0)*: heterogeneity (memes differ in strength).  
  - 0.0 → all memes are equally strong.  
  - Higher values → mixed populations with “weak” and “strong” memes.

- **`meme-weight-min / meme-weight-max`**: hard bounds preventing unrealistic weights.

---

## 3) Meme anti-leak and decay (optional)

- **`meme-anti-leak`** *(0–1)*: when one side grows, a fraction of the opposite stock is reduced.  
  High values create “winner-takes-more” dynamics (polarization reinforcement).

- **`meme-decay`** *(0–0.05 typical)*: forgetting rate applied each tick to quantities and weights.

---

# Meme Injection (Targeted diffusion of new representations)

Beyond “events” that shift opinions directly, the simulator can **inject memes** into a selected subgroup to simulate the introduction and diffusion of a new narrative, argument, or frame.

## 1) Targeting bounds (preferred controls)
Agents are eligible for injection if they satisfy:

- **`inject-low_meme ≤ opinion ≤ inject-high_meme`**
- **`inject-low-prev ≤ prevalence ≤ inject-high-prev`**

This allows injection into:
- moderates only (e.g., −0.2 to +0.2),
- one camp only (e.g., +0.2 to +1),
- low-prevalence agents only (e.g., 0 to 30).

## 2) Injection strength and reach
- **`inject-prob-max`** *(0–1)*: maximum share of eligible agents that actually receive the injected memes.
- **`inject-sign`**: `"plus"` or `"minus"` (which direction the injected memes support).
- **`inject-amount`** *(typical 1–10)*: how many memes are injected (quantity → raises prevalence).
- **`inject-weight`** *(typical 0.2–5.0)*: how strong injected memes are (weight → shifts opinion more sharply).

**Rule of thumb:**  
- Increase `inject-amount` to raise **prevalence** (more representations).  
- Increase `inject-weight` to raise **polarization intensity** (stronger conviction shift).

## 3) Scheduling injection
- **`auto_inject?`**: if ON, injection occurs when `ticks = inject-tick`.
- **`inject-tick`**: the tick at which injection happens.
- **`repeat-inject?`**: if ON, injection repeats every `inject-pace` ticks.
- **`inject-pace`**: the interval between repeated injections.

### Example scenarios
- **One-shot targeted campaign**:  
  `auto_inject? = ON`, `repeat-inject? = OFF`, `inject-tick = 50`, `inject-prob-max = 0.2`,  
  `inject-low_meme = -0.2`, `inject-high_meme = 0.2`, `inject-sign = "plus"`,  
  `inject-amount = 3`, `inject-weight = 2.0`.

- **Slow diffusion of a weak but persistent narrative**:  
  `repeat-inject? = ON`, `inject-pace = 25`, `inject-prob-max = 0.05`,  
  `inject-amount = 1`, `inject-weight = 0.5`.

- **High-impact shock on a small subgroup**:  
  `inject-prob-max = 0.02`, `inject-amount = 2`, `inject-weight = 5.0`,  
  targeting a narrow opinion band.

---
## Parameter Ranges — Key Sliders (Overview)

The table below summarizes the **recommended value ranges** for the **nine main sliders** governing opinion transmission, meme dynamics, and external shocks.  
Ranges are indicative and meant to support **exploratory, comparative, and pedagogical simulations** rather than strict calibration.

| Slider name | Typical range | What it controls | Low values → expected effects | High values → expected effects |
|------------|---------------|------------------|-------------------------------|--------------------------------|
| **prevalence-weight** | 0.0 – 2.0 | Weight of prevalence differences in adoption probability | Opinion change weakly tied to representational depth; more random diffusion | Deeply rooted agents dominate transmission; strong inertia |
| **adoption-floor** | 0.0 – 0.10 | Minimum probability of adoption regardless of distance | Near-impossible cross-camp adoption | Persistent low-level noise and occasional inversions |
| **polarization-factor** | 0.0 – 1.0 | Penalty applied to large opinion gaps | Distance barely matters; smooth convergence | Strong ideological barriers; entrenched camps |
| **group-impact-weight** | 0.0 – 1.0 | Strength of group alignment effect | Individual interactions dominate | Local majorities strongly condition adoption |
| **group-impact-alpha** | 0.2 – 3.0 | Non-linearity of group effect | Small minorities exert strong influence | Only large aligned groups matter |
| **meme-max** | 50 – 200 | Maximum stock of memes per agent (prevalence scale) | Shallow belief systems; fast saturation | Deep ideological accumulation; slow dynamics |
| **meme-gain** | 0.5 – 2.0 | Meme increment per successful transmission | Slow learning; weak reinforcement | Rapid ideological buildup |
| **meme-anti-leak** | 0.0 – 0.5 | Cross-erosion of opposite meme stock | Memes accumulate independently | Strong competition; winner-takes-more dynamics |
| **meme-decay** | 0.0 – 0.05 | Forgetting rate of memes per tick | Stable long-term memory | Rapid erosion; volatile belief systems |
| **event-prob-max** | 0.0 – 1.0 | Proportion of agents affected by an event | Micro-perturbations, local shocks | System-wide shocks |

---

### Usage notes
- **Low–mid ranges** are recommended for exploratory runs and sensitivity analysis.  
- **Extreme values** are useful to study boundary cases (lock-in, collapse, polarization).  
- Parameters interact strongly: e.g., high `meme-gain` combined with high `meme-anti-leak` accelerates polarization.

This table is intended as a **cheat sheet**; empirical calibration should rely on systematic parameter sweeps.

## Meme Injection — Slider Ranges, Effects, and Interactions

This table documents the **nine sliders governing meme injection**.  
Together, they define *when*, *how often*, *to whom*, and *with what strength* new memes are introduced into the population, allowing controlled simulations of campaigns, rumors, or polarizing shocks.

---

### Core Injection Parameters

| Slider | Typical range | Role in the model | Low values → effects | High values → effects |
|------|---------------|-------------------|----------------------|----------------------|
| **inject-tick** | 1 – max_iter | First tick at which meme injection can occur | Early priming of agents; long-run structural impact | Late shock; short-term perturbation with limited propagation |
| **inject-pace** | 1 – 200 | Interval (ticks) between injections | Continuous or quasi-continuous pressure | Rare, punctuated shocks |
| **inject-prob-max** | 0.0 – 1.0 | Maximum probability that an eligible agent receives a meme at an injection tick | Injection remains marginal or localized | Broad exposure; near-systemic dissemination |
| **inject-amount** | 0 – meme-max | Quantity of meme stock added per injection | Subtle informational nudges | Strong narrative saturation or propaganda burst |
| **inject-weight** | 0.0 – 2.0 (or higher) | Relative impact of injected memes on opinion vs. prevalence | Injected memes mainly increase prevalence (attention/salience) | Injected memes strongly bias opinion formation |

---

### Targeting and Selectivity Parameters

| Slider | Typical range | Role in the model | Low values → effects | High values → effects |
|------|---------------|-------------------|----------------------|----------------------|
| **inject-low_meme** | −1.0 – 1.0 | Lower bound of opinion eligible for injection | Broad targeting across ideological spectrum | Injection limited to one side or a narrow ideological niche |
| **inject-high_meme** | −1.0 – 1.0 | Upper bound of opinion eligible for injection | Narrow ideological window | Broad or opposing-side reach (depending on bounds) |
| **inject-low-prev** | 0 – 99 | Minimum prevalence required to receive injected memes | Inclusion of low-salience or weakly engaged agents | Targeting already attentive or mobilized agents |
| **inject-high-prev** | 0 – 99 | Maximum prevalence eligible for injection | Focus on low-to-mid engagement agents | Restriction to highly engaged elites |

---

### Interaction Effects (Key Dynamics)

- **inject-tick × inject-pace**  
  - Early + short pace → *persistent campaign dynamics*.  
  - Late + long pace → *isolated shock events*.

- **inject-prob-max × inject-amount**  
  - Low prob + high amount → *elite seeding* (few agents, strong impact).  
  - High prob + low amount → *mass diffusion* (many agents, weak signal).

- **inject-weight × inject-amount**  
  - High weight + high amount → *rapid opinion polarization*.  
  - Low weight + high amount → *agenda-setting without strong persuasion*.

- **inject-low_meme / inject-high_meme × inject-low-prev / inject-high-prev**  
  - Narrow opinion + high prevalence → *echo-chamber reinforcement*.  
  - Broad opinion + low prevalence → *grassroots diffusion potential*.

---

### Conceptual Interpretation

- Low values generally model **background noise**, rumors, or weak informational exposure.  
- High values approximate **organized campaigns**, disinformation bursts, or polarizing media events.  
- Intermediate combinations allow exploration of **threshold effects**, diffusion delays, and nonlinear amplification.

These sliders are designed to be orthogonal but **non-independent**: meaningful experiments emerge from their **joint configuration**, not isolated tuning.


## Preset — *Campaign / Rumor / Polarizing shock* (recommended default profile)

This preset is a **ready-to-run parameter profile** designed to reproduce a common empirical pattern in opinion dynamics:

1) a **stable baseline** (moderate homophily, limited cross-camp contact),  
2) a **rumor/campaign phase** (repeated external shocks reaching only part of the population),  
3) a **polarizing outcome** (network segmentation, fewer inversions, stronger within-camp reinforcement).

It is intended as a **starting point** for university-level experimentation (reproducible and interpretable), not as a calibrated model for a specific case.

---

### A. Core idea
- Use **repeat-event + event-pace** to create a *campaign/rumeur* that reappears periodically.
- Use **event-prob-max < 1** so the shock reaches only a subset of eligible agents, generating diffusion rather than an immediate global collapse.
- Keep **bridge-prob low but non-zero** so rare cross-camp bridges exist (possible inversions), while still allowing polarization to emerge.
- Activate **group impact** and a **mild reward system** to reproduce realistic “social proof” and reinforcement mechanisms.

---

### B. Default values (Preset)
*(Values assume your current sliders/switches; ranges remain adjustable by the operator.)*

#### 1) Events: “campaign / rumor” mechanics
- **auto_event**: ON  
- **repeat-event**: ON  
- **event-init**: `50` (first shock after an initial stabilization period)  
- **event-pace**: `25` (shock repeats every 25 iterations)  
- **event-prob-max**: `0.10` (≈10% of eligible agents receive the shock each cycle)

**Bounds & targeting**
- **meme_set**: OFF *(use bounds rather than structural Left/Right set)*  
- **low_meme / high_meme**: `-0.30 / +0.30` *(targets the “convertible middle”)*  
- **low-prev / high-prev**: `10 / 60` *(targets moderate-prevalence agents—reachable but not rigid)*  

**Shock magnitude**
- **event_size**: `0.25` *(clear movement without saturating ±1 too fast)*  
- **prev_change**: `+8` *(moderate strengthening of prevalence in targeted agents; set 0 if you want “pure opinion shock”)*  

**Interpretation**
- This reproduces a campaign/rumeur that repeatedly perturbs the **middle** rather than only extremes, and spreads indirectly through the network.

---

#### 2) Network: controlled homophily + rare bridges
- **network**: ON  
- **link-formation-threshold**: `0.20`  
- **link-removal-threshold**: `0.40`  
- **prob**: `0.30`  
- **linksup / linksdown**: `10 / 10` *(balanced churn)*  
- **bridge-prob**: `0.05` *(rare but non-zero cross-camp bridges)*  
- **show-links?**: optional (OFF for performance; ON for demonstrations)

**Expected effect**
- The network remains mostly homophilous, but with occasional “bridges” allowing limited cross-camp exposure.

---

#### 3) Opinion adoption: prevalence-driven, polarization-aware
- **prevalence-weight**: `1.40`  
- **polarization-factor**: `0.60`  
- **adoption-floor**: `0.03`  
- **noise**: `0.01` *(small background drift)*

**Expected effect**
- Adoption is mostly driven by **prevalence differences**, while strong polarization reduces cross-camp adoption without making it impossible.

---

#### 4) Group impact: social proof (moderate strength)
- **group-impact-mode**: `k-nearest`  
- **group-k**: `8`  
- **group-impact-weight**: `0.60`  
- **group-impact-alpha**: `1.20`

**Expected effect**
- Local neighbourhood alignment matters; **majorities** have slightly more weight than minorities (alpha > 1).

---

#### 5) Reward: modest reinforcement (avoid runaway)
- **reward-step**: `0.03`  
- **reward-cap**: `0.30`  
- **reward-decay**: `0.005`  
- **reward-scope**: `both`  
- **reward-prev-delta**: `0` *(keep prevalence effects attributable to memes/events; set 1–3 if you want “success breeds conviction”)*

**Expected effect**
- Successful influencers become moderately more effective over time, but decay prevents permanent dominance.

---

#### 6) Memes: ON (recommended for this preset)
- **use-memes?**: ON  
- **meme-max**: `120`  
- **meme-gain**: `1.0`  
- **meme-anti-leak**: `0.20`  
- **meme-decay**: `0.01`

**Expected effect**
- Agents gradually accumulate representations; anti-leak creates a mild competitive relation between pro/anti stocks, supporting polarization over repeated shocks.

---

#### 7) Meta-influencers: optional, controlled
- **meta-ok**: ON *(optional; ON reproduces real-world asymmetric reach)*  
- **meta-influencers-selection**: `All`  
- **meta-influencers**: `5%`  
- **prev-low / prev-high**: `20 / 80`  
- **meta-min / meta-max**: `8 / 20`  
- **metablock**: ON *(prevents sign switching for metas)*  
- **vary-influence**: OFF *(recommended OFF to avoid meta inflation; turn ON only if studying endogenous influencer emergence)*

**Expected effect**
- A small set of highly connected agents accelerates diffusion while the metablock prevents metas from oscillating across camps.

---

### C. What you should observe (typical outcomes)
- Early phase (before **event-init**): moderate clustering, limited movement.
- During repeated events: a growing asymmetry in meme stocks and prevalence among the targeted “middle”.
- Over time: stronger within-camp reinforcement, more **gray links** disappearing, fewer inversions.
- If you increase **event-prob-max** toward 0.30–0.50: faster and more global shifts.
- If you increase **bridge-prob** toward 0.10–0.20: more cross-camp exposure and more inversions (polarization weakens).

---

### D. Minimal variant (if you want “shock-only”, no campaign)
- Set **repeat-event = OFF** and keep a single **event-init** (or press **event** once).
- Keep all other values unchanged to compare *one-shot shock* vs *campaign repetition*.


---

## Meme Dynamics — Integrated Monitoring Indicators

This simulator includes **six dedicated monitors** designed to track how *memes* (internal representations) shape opinion formation, prevalence, and polarization over time.  
Each monitor is updated **at every tick** and provides a complementary analytical perspective on the meme–opinion coupling.

---

### 1. Mean Meme Stock
**What it measures**  
The average total number of memes held by agents:

Mean Meme Stock = mean(meme-plus + meme-minus)

**Why it matters**  
This indicator captures the **global cognitive density** of the population.

- Low values indicate weakly structured opinions (few internal representations).  
- High values reflect ideologically “loaded” agents with many arguments.

**Interpretation**  
- Rising values → accumulation of representations (learning, persuasion, repeated events).  
- Falling values → forgetting or erosion (via `meme-decay`).

**Implementation (monitor expression)**  

---

### 2. Meme Polarity Index
**What it measures**  
The **net ideological balance of all memes** in the system.

It compares the total stock of positive memes to negative memes.

**Interpretation**  
- Values close to `+1` → dominance of pro (+) memes.  
- Values close to `-1` → dominance of contra (−) memes.  
- Values near `0` → balanced or plural meme ecology.

**Implementation (monitor expression)**  

---

### 3. Opinion–Meme Gap
**What it measures**  
The average absolute difference between:
- the agent’s expressed opinion, and  
- the opinion implied by its internal meme balance.

**Why it matters**  
This indicator captures **latent cognitive inconsistency**:
agents may *express* an opinion that is not fully supported by their internal representations.

**Interpretation**  
- Low gap → opinions are well grounded in memes.  
- High gap → cognitive tension, instability, or transitional states.

**Implementation (monitor expression)**  

---

---

## Ideologization Indices (NEW – Dual Measure)

The simulator now exports **two distinct ideologization indicators** in the CSV *Statistics* output.  
They capture **complementary dimensions of ideological structuring** and should not be interpreted as redundant.

---

### 4a. Ideologization Index (meme-based)

**CSV column:**  
`ideologization_index`

**What it measures**  
The **average representational imbalance** within agents, based on their internal meme stocks.

This indicator captures how strongly agents are cognitively oriented toward one side through the **asymmetry of supporting arguments**, independently of their expressed opinion.

**Formal definition**  
For each agent *i*:
- Meme imbalance = `| meme-plus − meme-minus |`

The index is the population mean:


**Interpretation**  
- Low values → weakly structured or ambivalent meme ecology  
- High values → strong internal representational bias (ideological load)

This measure reflects **ideological depth at the cognitive level**, even if opinions remain moderate.

**Use in the article**  
- **Methods:** introduced as a *representational ideologization* metric  
- **Results:** used to compare cognitive polarization across experimental conditions (Exp1–Exp5)  
- Helps explain cases where opinions remain stable despite intense internal meme accumulation

---

### 4b. Ideologization Index (opinion-based)

**CSV column:**  
`ideologization_opinion_based`

**What it measures**  
The degree to which **expressed opinion extremity is supported by prevalence** (i.e., conviction strength).

This index captures **ideological entrenchment at the behavioral level**, combining stance and commitment.

**Formal definition**  
For each agent *i*:


The index is the population mean:

**Interpretation**  
- Low values → weakly anchored opinions or pragmatic attitudes  
- High values → extreme opinions supported by high conviction

This measure reflects **expressed ideological rigidity**, not internal argument diversity.

**Use in the article**  
- **Methods:** introduced as an *expressed ideologization* indicator  
- **Results:** contrasted with the meme-based index to distinguish:
  - cognitive saturation without opinion radicalization  
  - versus explicit ideological alignment

---

### How to read both indices together

The two measures should be interpreted **jointly**:

- **High meme-based / low opinion-based**  
  → cognitively loaded but behaviorally moderate agents (latent ideology)

- **Low meme-based / high opinion-based**  
  → strong stance with limited internal justification (fragile extremism)

- **High on both**  
  → fully ideologized population (entrenched opinions with deep representational support)

This distinction is central to the article’s argument on **multi-layered ideologization dynamics** in agent-based models.

---


### 5. Right Meme Polarization

**What it measures**  
The **internal ideological polarization of meme stocks** among agents holding a **positive opinion** (`opinion >= 0`).

It compares reinforcing memes (`meme-plus`) to counter-memes (`meme-minus`) **within the right-leaning subgroup only**, independently of the left side.

**Interpretation**  
- Values close to `+1` → strong dominance of reinforcing (pro-right) memes.  
- Values near `0` → balanced or internally plural meme structure.  
- Values below `0` → erosion or counter-meme dominance inside the right camp.

This indicator reveals whether right-side opinions are:
- deeply ideologized,
- stable but weakly supported,
- or vulnerable to counter-narratives.

**Implementation (plot and monitor expression)**  


---

### 6. Left Meme Polarization

**What it measures**  
The **internal ideological polarization of meme stocks** among agents holding a **negative opinion** (`opinion < 0`).

It measures the balance between reinforcing and counter-memes **inside the left-leaning subgroup**, independently from right-side dynamics.

**Interpretation**  
- Values close to `-1` → strong dominance of reinforcing (pro-left) memes.  
- Values near `0` → plural or contested internal meme structure.  
- Values above `0` → counter-meme pressure within the left camp.

This indicator is essential to detect:
- asymmetric polarization,
- minority radicalization,
- or differential resistance to meme diffusion.

**Implementation (plot and monitor expression)**

--- 

### 7. Mean Meme-derived Opinion

**What it measures**  
The **average opinion value reconstructed from meme stocks**, independently of the agents’ current explicit opinions.

This measure computes, for each agent, the opinion implied by the balance of its internal memes  
(`meme-plus` vs `meme-minus`), then averages this value across the whole population.

**Interpretation**  
- Values close to `+1` → the meme ecology strongly supports the positive (right/pro) polarity.  
- Values close to `-1` → dominance of negative (left/contra) meme representations.  
- Values near `0` → balanced or internally conflicting meme structures.

Comparing this indicator with the mean explicit opinion reveals **latent ideological tensions**:
- If meme-derived opinion is stronger than explicit opinion → opinions may soon shift.  
- If explicit opinion is stronger than meme-derived opinion → opinions are weakly grounded and fragile.


**Why it matters**  
This indicator captures the **deep cognitive orientation** of the population, beyond surface-level expressed opinions.  
It helps distinguish:
- superficial opinion alignment,
- structurally grounded ideological states,
- and phases where internal representations lag behind observable behavior.

---

**Implementation (monitor expression)**  

---

### 8. Meme Saturation (%)

**What it measures**  
The **overall saturation level of meme stocks** in the population, expressed as a **percentage of the maximum possible meme capacity**.

It compares the total number of memes currently held by all agents to the theoretical maximum (`meme-max × population`).

**Interpretation**  
- Values close to `0%` → agents hold very few internal representations; opinions are shallow and weakly grounded.  
- Intermediate values (`30–60%`) → active circulation of arguments with moderate cognitive load.  
- Values close to `100%` → saturated cognitive environment; agents are highly entrenched and resistant to change.

This indicator captures the **cognitive density** of the system and helps distinguish:
- early diffusion phases,
- mature ideological ecosystems,
- and saturation-driven stabilization or lock-in effects.

**Implementation (monitor expression)**  

 

*(These indicators are computed only when `use-memes?` is ON.)*

---

# EXOGENOUS EVENTS (bounded & probabilistic)

**Targeting**

* **`meme_set`** + **`to_left`**: if ON, structural targeting by camp (*Left side* / *Right side*).
* Otherwise, use bounds: **`low_meme` / `high_meme`** (opinion window) and **`low-prev` / `high-prev`** (prevalence window).

**Effects on targeted agents**

* **`event_size`**: opinion shift (toward the intended camp).
* **`prev_change`**: prevalence change (clamped to [0,99]).
* **`event-prob-max`** *(0–1)*: **maximum share** of targeted agents that **actually receive** the shock (each agent draws `U(0,1)`).

**Triggering**

* **`event` button**: one-shot shock (manual).
* **`auto_event` + `tick-event`**: scheduled automatic shock at iteration `tick-event`.

### Repeated events (per your code)

* **`event-init`**: **initial offset** of the first event (on `setup` and at each new trial, `tick-event ← event-init`).
* **`repeat-event`** (switch): if ON, **re-schedules** the next event after each occurrence.
* **`event-pace`** (≥ 1 tick recommended): spacing between repeated events.
* **Scheduling logic**:

  * If **`auto_event` = ON** and **`iter = tick-event`** → run `event`.

    * If **`repeat-event` = ON** → `tick-event ← tick-event + event-pace`.
    * Else (OFF) → **no** automatic re-scheduling (you may adjust `tick-event` manually).
  * If **`auto_event` = OFF** → **each tick**, `tick-event ← iter + event-pace` (the next time you switch ON, the event fires ≈ `event-pace` ticks later).

**Quick examples**

* Single calibration shock: `auto_event=ON`, `repeat-event=OFF`, `event-init=2`, `event-prob-max=1.0`.
* Periodic pulses: `auto_event=ON`, `repeat-event=ON`, `event-init=50`, `event-pace=50`, `event-prob-max=0.30`.
* Diffuse perturbations: `repeat-event=ON`, `event-pace=100`, `event-prob-max=0.05`.

---

# CSV EXPORT (NEW FEATURE)

The simulator supports **buffered CSV export**, allowing results to be written efficiently to disk at the end of a run or trial.

Two export modes are available:

## Statistics mode

Exports **aggregate indicators per tick**, including:

* mean opinion
* median opinion (left / right)
* median prevalence (left / right)
* median influence (left / right)
* population shares (left / right)
* number of links created and removed
* inversion rate
* interaction counters
* fractal indicators

## Values mode

Exports **individual agent states** at selected iterations.
One row is written **per agent per exported iteration**, including:

* opinion
* prevalence
* influence
* meme-plus
* meme-minus
* meme-plus weight
* meme-minus weight

---

## CSV Controls

* **csv-export**  
  Enables or disables CSV export.

* **csv-mode**  
  Selects `"Statistics"` or `"Values"` export mode.

* **csv-basename**  
  Base name used for generated CSV files.

* **csv-values-start**  
  First tick at which agent values are exported (Values mode).

* **csv-values-step**  
  Interval (in ticks) between value exports.

## CSV Buttons

* **csv open**  
  Initializes the CSV buffer and writes the file header.

* **csv close**  
  Flushes the buffer and writes the CSV file to disk.

CSV filenames are automatically constructed from the base name, trial number, export mode, and locale.

---

# IMPORTING AGENT STATES (NEW FEATURE)

The simulator supports **two distinct formats** for importing agent states.

---

## in_file (Simple format)

The **in_file** button loads a file containing a **single snapshot of agents**, typically corresponding to iteration 0.

Each line in the file must contain exactly:

* tick
* prevalence
* opinion
* influence

This format is intended for:

* handcrafted initial populations
* externally generated datasets
* controlled experimental starting points

When loaded:

* agents are created once
* meme stocks are initialized from opinion and prevalence
* the social network is rebuilt normally

---

## in_file_values (CSV Values re-import)

The **in_file_values** button loads agents from a CSV file previously exported in **Values mode**.

Usage:

* select the iteration to load using **choice_iter**
* click **in_file_values**

Behavior:

* agents are reconstructed exactly as they were at the selected iteration
* opinion, prevalence, influence, meme stocks, and meme weights are restored
* agents with influence = 1 are automatically recolored as meta-agents

This enables:

* replaying simulations from an intermediate state
* branching alternative scenarios
* counterfactual experiments
* reproducible analysis from archived runs

---

# OUTPUTS AND MONITORS

The interface provides monitors for:

* population shares (left / right)
* opinion, prevalence, and influence statistics
* meme-based indicators
* polarization and saturation measures
* inversion rates
* network dynamics (links created / removed)

Plots display **time trajectories of key variables**, supporting both exploratory and analytical use of the simulator.


# OUTPUTS / MONITORS / CSV

* **Monitors**: % left/right, medians (opinion/prevalence/influence), inversions, interactions, fractal dimension, links created/removed.
* **Graph**: time trajectories of key variables.
* **CSV**: if **`csv-export`** = ON, per-trial export with a standard header (`basename-try.csv`).

---

---
STATISTICS EXPORT — VARIABLES GUIDE
(Automatically exported when csv-export + statistics is ON)

---

| Variable | Meaning | Analytical role |
|---------|---------|-----------------|
| try | Run index | Multi-run / Monte Carlo analysis |
| tick | Simulation time | Temporal dynamics |
| pop | Population size | Normalization |
| interactions_per_iter | Total interactions per tick | Social activity level |
| change | Opinion changes | Instantaneous volatility |
| inversions | Sign changes (+↔−) | Ideological switching |
| interactions_per_inversion | Interactions per inversion | Cognitive inertia |
| links_created | New links | Network plasticity |
| links_removed | Deleted links | Network fragmentation |
| bridge_links | Cross-camp links | Ideological permeability |
| mean_opinion | Average opinion | Global orientation |
| median_opinion | Median opinion | Robust central tendency |
| mean_abs_opinion | Mean |opinion| | Degree of radicalization |
| majority_pct | Majority share | Dominance vs pluralism |
| mean_prevalence | Average prevalence | Depth of conviction |
| median_prevalence | Median prevalence | Distribution of conviction |
| mean_meme_stock | Avg. meme quantity | Cognitive density |
| mean_meme_derived_opinion | Opinion from memes | Latent ideological orientation |
| mean_polarity_index | Meme balance index | System-level polarity |
| meme_saturation_pct | Meme capacity usage (%) | Cognitive saturation |
| right_meme_polarization | Meme asymmetry (Right) | Intra-camp radicalization |
| left_meme_polarization | Meme asymmetry (Left) | Intra-camp radicalization |
| opinion_meme_gap | Opinion–meme distance | Cognitive dissonance |
| ideologization_index | Mean |meme+ − meme−| | Ideological intensity |
| meta_agents | Number of meta-agents | Influence concentration |
| meta_links | Links of meta-agents | Structural reach |

---

Notes:
• Meme-based indicators are meaningful only when use-memes? = ON
• ideologization_index measures ideological asymmetry, not direction
• inversions capture true allegiance shifts (sign changes)
• opinion_meme_gap signals latent instability
---


# THINGS TO WATCH

* Polarization, convergence, fragmentation.
* Roles of **meta-influencers** (and `metablock`), **group effect**, and **reward**.
* Impact of **memes** (memory, cross-leak, decay).
* How **repeated events** and **`event-prob-max`** shape the global dynamics.

---

# QUICK CHEAT SHEET — TYPICAL VALUES

| Parameter               | Useful range | Tendency                                                    |
| ----------------------- | ------------ | ----------------------------------------------------------- |
| `prevalence-weight`     | 0–2          | ↑ makes prevalence gaps dominate adoption                   |
| `adoption-floor`        | 0–0.1        | ↑ allows more “noisy” cross-camp adoptions                  |
| `bridge-prob`           | 0–0.3        | ↑ creates more cross-camp bridges & inversions              |
| `group-impact-weight`   | 0–1          | ↑ strengthens neighborhood alignment effect                 |
| `group-impact-alpha`    | 0.2–3        | <1 favors small aligned clusters; >1 needs large majorities |
| `reward-step`           | 0.01–0.1     | ↑ faster reinforcement of persuasive agents                 |
| `reward-decay`          | 0–0.05       | ↑ bonus fades faster                                        |
| `meme-anti-leak`        | 0–0.5        | ↑ growth erodes the opposite stock more                     |
| `event-prob-max`        | 0–1          | ↑ more “massive” shocks per occurrence                      |
| `event-pace`            | ≥1           | ↓ means more frequent events (if repetition ON)             |
| `mod-prev` & `Rate-mod` | —            | adapt prevalence to opinion changes                         |

---

# CREDITS

* Original concept: *Public Opinion Research Group* (GROP.CA)
* NetLogo implementation & enhancements: **Pierre-Alain Cotnoir** (2015–2026)
* AI-assisted design: GPT-4 & GPT-5 (2024–2026)
* Contact: [pacotnoir@gmail.com](mailto:pacotnoir@gmail.com)
]]></info>
  <turtleShapes>
    <shape name="default" rotatable="true" editableColorIndex="0">
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="150" y="5"></point>
        <point x="40" y="250"></point>
        <point x="150" y="205"></point>
        <point x="260" y="250"></point>
      </polygon>
    </shape>
    <shape name="airplane" rotatable="true" editableColorIndex="0">
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="150" y="0"></point>
        <point x="135" y="15"></point>
        <point x="120" y="60"></point>
        <point x="120" y="105"></point>
        <point x="15" y="165"></point>
        <point x="15" y="195"></point>
        <point x="120" y="180"></point>
        <point x="135" y="240"></point>
        <point x="105" y="270"></point>
        <point x="120" y="285"></point>
        <point x="150" y="270"></point>
        <point x="180" y="285"></point>
        <point x="210" y="270"></point>
        <point x="165" y="240"></point>
        <point x="180" y="180"></point>
        <point x="285" y="195"></point>
        <point x="285" y="165"></point>
        <point x="180" y="105"></point>
        <point x="180" y="60"></point>
        <point x="165" y="15"></point>
      </polygon>
    </shape>
    <shape name="arrow" rotatable="true" editableColorIndex="0">
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="150" y="0"></point>
        <point x="0" y="150"></point>
        <point x="105" y="150"></point>
        <point x="105" y="293"></point>
        <point x="195" y="293"></point>
        <point x="195" y="150"></point>
        <point x="300" y="150"></point>
      </polygon>
    </shape>
    <shape name="box" rotatable="false" editableColorIndex="0">
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="150" y="285"></point>
        <point x="285" y="225"></point>
        <point x="285" y="75"></point>
        <point x="150" y="135"></point>
      </polygon>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="150" y="135"></point>
        <point x="15" y="75"></point>
        <point x="150" y="15"></point>
        <point x="285" y="75"></point>
      </polygon>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="15" y="75"></point>
        <point x="15" y="225"></point>
        <point x="150" y="285"></point>
        <point x="150" y="135"></point>
      </polygon>
      <line endX="150" startY="285" marked="false" color="255" endY="135" startX="150"></line>
      <line endX="15" startY="135" marked="false" color="255" endY="75" startX="150"></line>
      <line endX="285" startY="135" marked="false" color="255" endY="75" startX="150"></line>
    </shape>
    <shape name="bug" rotatable="true" editableColorIndex="0">
      <circle x="96" y="182" marked="true" color="-1920102913" diameter="108" filled="true"></circle>
      <circle x="110" y="127" marked="true" color="-1920102913" diameter="80" filled="true"></circle>
      <circle x="110" y="75" marked="true" color="-1920102913" diameter="80" filled="true"></circle>
      <line endX="80" startY="100" marked="true" color="-1920102913" endY="30" startX="150"></line>
      <line endX="220" startY="100" marked="true" color="-1920102913" endY="30" startX="150"></line>
    </shape>
    <shape name="butterfly" rotatable="true" editableColorIndex="0">
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="150" y="165"></point>
        <point x="209" y="199"></point>
        <point x="225" y="225"></point>
        <point x="225" y="255"></point>
        <point x="195" y="270"></point>
        <point x="165" y="255"></point>
        <point x="150" y="240"></point>
      </polygon>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="150" y="165"></point>
        <point x="89" y="198"></point>
        <point x="75" y="225"></point>
        <point x="75" y="255"></point>
        <point x="105" y="270"></point>
        <point x="135" y="255"></point>
        <point x="150" y="240"></point>
      </polygon>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="139" y="148"></point>
        <point x="100" y="105"></point>
        <point x="55" y="90"></point>
        <point x="25" y="90"></point>
        <point x="10" y="105"></point>
        <point x="10" y="135"></point>
        <point x="25" y="180"></point>
        <point x="40" y="195"></point>
        <point x="85" y="194"></point>
        <point x="139" y="163"></point>
      </polygon>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="162" y="150"></point>
        <point x="200" y="105"></point>
        <point x="245" y="90"></point>
        <point x="275" y="90"></point>
        <point x="290" y="105"></point>
        <point x="290" y="135"></point>
        <point x="275" y="180"></point>
        <point x="260" y="195"></point>
        <point x="215" y="195"></point>
        <point x="162" y="165"></point>
      </polygon>
      <polygon color="255" filled="true" marked="false">
        <point x="150" y="255"></point>
        <point x="135" y="225"></point>
        <point x="120" y="150"></point>
        <point x="135" y="120"></point>
        <point x="150" y="105"></point>
        <point x="165" y="120"></point>
        <point x="180" y="150"></point>
        <point x="165" y="225"></point>
      </polygon>
      <circle x="135" y="90" marked="false" color="255" diameter="30" filled="true"></circle>
      <line endX="195" startY="105" marked="false" color="255" endY="60" startX="150"></line>
      <line endX="105" startY="105" marked="false" color="255" endY="60" startX="150"></line>
    </shape>
    <shape name="car" rotatable="false" editableColorIndex="0">
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="300" y="180"></point>
        <point x="279" y="164"></point>
        <point x="261" y="144"></point>
        <point x="240" y="135"></point>
        <point x="226" y="132"></point>
        <point x="213" y="106"></point>
        <point x="203" y="84"></point>
        <point x="185" y="63"></point>
        <point x="159" y="50"></point>
        <point x="135" y="50"></point>
        <point x="75" y="60"></point>
        <point x="0" y="150"></point>
        <point x="0" y="165"></point>
        <point x="0" y="225"></point>
        <point x="300" y="225"></point>
        <point x="300" y="180"></point>
      </polygon>
      <circle x="180" y="180" marked="false" color="255" diameter="90" filled="true"></circle>
      <circle x="30" y="180" marked="false" color="255" diameter="90" filled="true"></circle>
      <polygon color="255" filled="true" marked="false">
        <point x="162" y="80"></point>
        <point x="132" y="78"></point>
        <point x="134" y="135"></point>
        <point x="209" y="135"></point>
        <point x="194" y="105"></point>
        <point x="189" y="96"></point>
        <point x="180" y="89"></point>
      </polygon>
      <circle x="47" y="195" marked="true" color="-1920102913" diameter="58" filled="true"></circle>
      <circle x="195" y="195" marked="true" color="-1920102913" diameter="58" filled="true"></circle>
    </shape>
    <shape name="circle" rotatable="false" editableColorIndex="0">
      <circle x="0" y="0" marked="true" color="-1920102913" diameter="300" filled="true"></circle>
    </shape>
    <shape name="circle 2" rotatable="false" editableColorIndex="0">
      <circle x="0" y="0" marked="true" color="-1920102913" diameter="300" filled="true"></circle>
      <circle x="30" y="30" marked="false" color="255" diameter="240" filled="true"></circle>
    </shape>
    <shape name="cow" rotatable="false" editableColorIndex="0">
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="200" y="193"></point>
        <point x="197" y="249"></point>
        <point x="179" y="249"></point>
        <point x="177" y="196"></point>
        <point x="166" y="187"></point>
        <point x="140" y="189"></point>
        <point x="93" y="191"></point>
        <point x="78" y="179"></point>
        <point x="72" y="211"></point>
        <point x="49" y="209"></point>
        <point x="48" y="181"></point>
        <point x="37" y="149"></point>
        <point x="25" y="120"></point>
        <point x="25" y="89"></point>
        <point x="45" y="72"></point>
        <point x="103" y="84"></point>
        <point x="179" y="75"></point>
        <point x="198" y="76"></point>
        <point x="252" y="64"></point>
        <point x="272" y="81"></point>
        <point x="293" y="103"></point>
        <point x="285" y="121"></point>
        <point x="255" y="121"></point>
        <point x="242" y="118"></point>
        <point x="224" y="167"></point>
      </polygon>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="73" y="210"></point>
        <point x="86" y="251"></point>
        <point x="62" y="249"></point>
        <point x="48" y="208"></point>
      </polygon>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="25" y="114"></point>
        <point x="16" y="195"></point>
        <point x="9" y="204"></point>
        <point x="23" y="213"></point>
        <point x="25" y="200"></point>
        <point x="39" y="123"></point>
      </polygon>
    </shape>
    <shape name="cylinder" rotatable="false" editableColorIndex="0">
      <circle x="0" y="0" marked="true" color="-1920102913" diameter="300" filled="true"></circle>
    </shape>
    <shape name="dot" rotatable="false" editableColorIndex="0">
      <circle x="90" y="90" marked="true" color="-1920102913" diameter="120" filled="true"></circle>
    </shape>
    <shape name="face happy" rotatable="false" editableColorIndex="0">
      <circle x="8" y="8" marked="true" color="-1920102913" diameter="285" filled="true"></circle>
      <circle x="60" y="75" marked="false" color="255" diameter="60" filled="true"></circle>
      <circle x="180" y="75" marked="false" color="255" diameter="60" filled="true"></circle>
      <polygon color="255" filled="true" marked="false">
        <point x="150" y="255"></point>
        <point x="90" y="239"></point>
        <point x="62" y="213"></point>
        <point x="47" y="191"></point>
        <point x="67" y="179"></point>
        <point x="90" y="203"></point>
        <point x="109" y="218"></point>
        <point x="150" y="225"></point>
        <point x="192" y="218"></point>
        <point x="210" y="203"></point>
        <point x="227" y="181"></point>
        <point x="251" y="194"></point>
        <point x="236" y="217"></point>
        <point x="212" y="240"></point>
      </polygon>
    </shape>
    <shape name="face neutral" rotatable="false" editableColorIndex="0">
      <circle x="8" y="7" marked="true" color="-1920102913" diameter="285" filled="true"></circle>
      <circle x="60" y="75" marked="false" color="255" diameter="60" filled="true"></circle>
      <circle x="180" y="75" marked="false" color="255" diameter="60" filled="true"></circle>
      <rectangle endX="240" startY="195" marked="false" color="255" endY="225" startX="60" filled="true"></rectangle>
    </shape>
    <shape name="face sad" rotatable="false" editableColorIndex="0">
      <circle x="8" y="8" marked="true" color="-1920102913" diameter="285" filled="true"></circle>
      <circle x="60" y="75" marked="false" color="255" diameter="60" filled="true"></circle>
      <circle x="180" y="75" marked="false" color="255" diameter="60" filled="true"></circle>
      <polygon color="255" filled="true" marked="false">
        <point x="150" y="168"></point>
        <point x="90" y="184"></point>
        <point x="62" y="210"></point>
        <point x="47" y="232"></point>
        <point x="67" y="244"></point>
        <point x="90" y="220"></point>
        <point x="109" y="205"></point>
        <point x="150" y="198"></point>
        <point x="192" y="205"></point>
        <point x="210" y="220"></point>
        <point x="227" y="242"></point>
        <point x="251" y="229"></point>
        <point x="236" y="206"></point>
        <point x="212" y="183"></point>
      </polygon>
    </shape>
    <shape name="fish" rotatable="false" editableColorIndex="0">
      <polygon color="-1" filled="true" marked="false">
        <point x="44" y="131"></point>
        <point x="21" y="87"></point>
        <point x="15" y="86"></point>
        <point x="0" y="120"></point>
        <point x="15" y="150"></point>
        <point x="0" y="180"></point>
        <point x="13" y="214"></point>
        <point x="20" y="212"></point>
        <point x="45" y="166"></point>
      </polygon>
      <polygon color="-1" filled="true" marked="false">
        <point x="135" y="195"></point>
        <point x="119" y="235"></point>
        <point x="95" y="218"></point>
        <point x="76" y="210"></point>
        <point x="46" y="204"></point>
        <point x="60" y="165"></point>
      </polygon>
      <polygon color="-1" filled="true" marked="false">
        <point x="75" y="45"></point>
        <point x="83" y="77"></point>
        <point x="71" y="103"></point>
        <point x="86" y="114"></point>
        <point x="166" y="78"></point>
        <point x="135" y="60"></point>
      </polygon>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="30" y="136"></point>
        <point x="151" y="77"></point>
        <point x="226" y="81"></point>
        <point x="280" y="119"></point>
        <point x="292" y="146"></point>
        <point x="292" y="160"></point>
        <point x="287" y="170"></point>
        <point x="270" y="195"></point>
        <point x="195" y="210"></point>
        <point x="151" y="212"></point>
        <point x="30" y="166"></point>
      </polygon>
      <circle x="215" y="106" marked="false" color="255" diameter="30" filled="true"></circle>
    </shape>
    <shape name="flag" rotatable="false" editableColorIndex="0">
      <rectangle endX="75" startY="15" marked="true" color="-1920102913" endY="300" startX="60" filled="true"></rectangle>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="90" y="150"></point>
        <point x="270" y="90"></point>
        <point x="90" y="30"></point>
      </polygon>
      <line endX="90" startY="135" marked="true" color="-1920102913" endY="135" startX="75"></line>
      <line endX="90" startY="45" marked="true" color="-1920102913" endY="45" startX="75"></line>
    </shape>
    <shape name="flower" rotatable="false" editableColorIndex="0">
      <polygon color="1504722175" filled="true" marked="false">
        <point x="135" y="120"></point>
        <point x="165" y="165"></point>
        <point x="180" y="210"></point>
        <point x="180" y="240"></point>
        <point x="150" y="300"></point>
        <point x="165" y="300"></point>
        <point x="195" y="240"></point>
        <point x="195" y="195"></point>
        <point x="165" y="135"></point>
      </polygon>
      <circle x="85" y="132" marked="true" color="-1920102913" diameter="38" filled="true"></circle>
      <circle x="130" y="147" marked="true" color="-1920102913" diameter="38" filled="true"></circle>
      <circle x="192" y="85" marked="true" color="-1920102913" diameter="38" filled="true"></circle>
      <circle x="85" y="40" marked="true" color="-1920102913" diameter="38" filled="true"></circle>
      <circle x="177" y="40" marked="true" color="-1920102913" diameter="38" filled="true"></circle>
      <circle x="177" y="132" marked="true" color="-1920102913" diameter="38" filled="true"></circle>
      <circle x="70" y="85" marked="true" color="-1920102913" diameter="38" filled="true"></circle>
      <circle x="130" y="25" marked="true" color="-1920102913" diameter="38" filled="true"></circle>
      <circle x="96" y="51" marked="true" color="-1920102913" diameter="108" filled="true"></circle>
      <circle x="113" y="68" marked="false" color="255" diameter="74" filled="true"></circle>
      <polygon color="1504722175" filled="true" marked="false">
        <point x="189" y="233"></point>
        <point x="219" y="188"></point>
        <point x="249" y="173"></point>
        <point x="279" y="188"></point>
        <point x="234" y="218"></point>
      </polygon>
      <polygon color="1504722175" filled="true" marked="false">
        <point x="180" y="255"></point>
        <point x="150" y="210"></point>
        <point x="105" y="210"></point>
        <point x="75" y="240"></point>
        <point x="135" y="240"></point>
      </polygon>
    </shape>
    <shape name="house" rotatable="false" editableColorIndex="0">
      <rectangle endX="255" startY="120" marked="true" color="-1920102913" endY="285" startX="45" filled="true"></rectangle>
      <rectangle endX="180" startY="210" marked="false" color="255" endY="285" startX="120" filled="true"></rectangle>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="15" y="120"></point>
        <point x="150" y="15"></point>
        <point x="285" y="120"></point>
      </polygon>
      <line endX="270" startY="120" marked="false" color="255" endY="120" startX="30"></line>
    </shape>
    <shape name="leaf" rotatable="false" editableColorIndex="0">
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="150" y="210"></point>
        <point x="135" y="195"></point>
        <point x="120" y="210"></point>
        <point x="60" y="210"></point>
        <point x="30" y="195"></point>
        <point x="60" y="180"></point>
        <point x="60" y="165"></point>
        <point x="15" y="135"></point>
        <point x="30" y="120"></point>
        <point x="15" y="105"></point>
        <point x="40" y="104"></point>
        <point x="45" y="90"></point>
        <point x="60" y="90"></point>
        <point x="90" y="105"></point>
        <point x="105" y="120"></point>
        <point x="120" y="120"></point>
        <point x="105" y="60"></point>
        <point x="120" y="60"></point>
        <point x="135" y="30"></point>
        <point x="150" y="15"></point>
        <point x="165" y="30"></point>
        <point x="180" y="60"></point>
        <point x="195" y="60"></point>
        <point x="180" y="120"></point>
        <point x="195" y="120"></point>
        <point x="210" y="105"></point>
        <point x="240" y="90"></point>
        <point x="255" y="90"></point>
        <point x="263" y="104"></point>
        <point x="285" y="105"></point>
        <point x="270" y="120"></point>
        <point x="285" y="135"></point>
        <point x="240" y="165"></point>
        <point x="240" y="180"></point>
        <point x="270" y="195"></point>
        <point x="240" y="210"></point>
        <point x="180" y="210"></point>
        <point x="165" y="195"></point>
      </polygon>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="135" y="195"></point>
        <point x="135" y="240"></point>
        <point x="120" y="255"></point>
        <point x="105" y="255"></point>
        <point x="105" y="285"></point>
        <point x="135" y="285"></point>
        <point x="165" y="240"></point>
        <point x="165" y="195"></point>
      </polygon>
    </shape>
    <shape name="line" rotatable="true" editableColorIndex="0">
      <line endX="150" startY="0" marked="true" color="-1920102913" endY="300" startX="150"></line>
    </shape>
    <shape name="line half" rotatable="true" editableColorIndex="0">
      <line endX="150" startY="0" marked="true" color="-1920102913" endY="150" startX="150"></line>
    </shape>
    <shape name="pentagon" rotatable="false" editableColorIndex="0">
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="150" y="15"></point>
        <point x="15" y="120"></point>
        <point x="60" y="285"></point>
        <point x="240" y="285"></point>
        <point x="285" y="120"></point>
      </polygon>
    </shape>
    <shape name="person" rotatable="false" editableColorIndex="0">
      <circle x="110" y="5" marked="true" color="-1920102913" diameter="80" filled="true"></circle>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="105" y="90"></point>
        <point x="120" y="195"></point>
        <point x="90" y="285"></point>
        <point x="105" y="300"></point>
        <point x="135" y="300"></point>
        <point x="150" y="225"></point>
        <point x="165" y="300"></point>
        <point x="195" y="300"></point>
        <point x="210" y="285"></point>
        <point x="180" y="195"></point>
        <point x="195" y="90"></point>
      </polygon>
      <rectangle endX="172" startY="79" marked="true" color="-1920102913" endY="94" startX="127" filled="true"></rectangle>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="195" y="90"></point>
        <point x="240" y="150"></point>
        <point x="225" y="180"></point>
        <point x="165" y="105"></point>
      </polygon>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="105" y="90"></point>
        <point x="60" y="150"></point>
        <point x="75" y="180"></point>
        <point x="135" y="105"></point>
      </polygon>
    </shape>
    <shape name="plant" rotatable="false" editableColorIndex="0">
      <rectangle endX="165" startY="90" marked="true" color="-1920102913" endY="300" startX="135" filled="true"></rectangle>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="135" y="255"></point>
        <point x="90" y="210"></point>
        <point x="45" y="195"></point>
        <point x="75" y="255"></point>
        <point x="135" y="285"></point>
      </polygon>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="165" y="255"></point>
        <point x="210" y="210"></point>
        <point x="255" y="195"></point>
        <point x="225" y="255"></point>
        <point x="165" y="285"></point>
      </polygon>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="135" y="180"></point>
        <point x="90" y="135"></point>
        <point x="45" y="120"></point>
        <point x="75" y="180"></point>
        <point x="135" y="210"></point>
      </polygon>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="165" y="180"></point>
        <point x="165" y="210"></point>
        <point x="225" y="180"></point>
        <point x="255" y="120"></point>
        <point x="210" y="135"></point>
      </polygon>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="135" y="105"></point>
        <point x="90" y="60"></point>
        <point x="45" y="45"></point>
        <point x="75" y="105"></point>
        <point x="135" y="135"></point>
      </polygon>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="165" y="105"></point>
        <point x="165" y="135"></point>
        <point x="225" y="105"></point>
        <point x="255" y="45"></point>
        <point x="210" y="60"></point>
      </polygon>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="135" y="90"></point>
        <point x="120" y="45"></point>
        <point x="150" y="15"></point>
        <point x="180" y="45"></point>
        <point x="165" y="90"></point>
      </polygon>
    </shape>
    <shape name="sheep" rotatable="false" editableColorIndex="15">
      <circle x="203" y="65" marked="true" color="-1" diameter="88" filled="true"></circle>
      <circle x="70" y="65" marked="true" color="-1" diameter="162" filled="true"></circle>
      <circle x="150" y="105" marked="true" color="-1" diameter="120" filled="true"></circle>
      <polygon color="-1920102913" filled="true" marked="false">
        <point x="218" y="120"></point>
        <point x="240" y="165"></point>
        <point x="255" y="165"></point>
        <point x="278" y="120"></point>
      </polygon>
      <circle x="214" y="72" marked="false" color="-1920102913" diameter="67" filled="true"></circle>
      <rectangle endX="179" startY="223" marked="true" color="-1" endY="298" startX="164" filled="true"></rectangle>
      <polygon color="-1" filled="true" marked="true">
        <point x="45" y="285"></point>
        <point x="30" y="285"></point>
        <point x="30" y="240"></point>
        <point x="15" y="195"></point>
        <point x="45" y="210"></point>
      </polygon>
      <circle x="3" y="83" marked="true" color="-1" diameter="150" filled="true"></circle>
      <rectangle endX="80" startY="221" marked="true" color="-1" endY="296" startX="65" filled="true"></rectangle>
      <polygon color="-1" filled="true" marked="true">
        <point x="195" y="285"></point>
        <point x="210" y="285"></point>
        <point x="210" y="240"></point>
        <point x="240" y="210"></point>
        <point x="195" y="210"></point>
      </polygon>
      <polygon color="-1920102913" filled="true" marked="false">
        <point x="276" y="85"></point>
        <point x="285" y="105"></point>
        <point x="302" y="99"></point>
        <point x="294" y="83"></point>
      </polygon>
      <polygon color="-1920102913" filled="true" marked="false">
        <point x="219" y="85"></point>
        <point x="210" y="105"></point>
        <point x="193" y="99"></point>
        <point x="201" y="83"></point>
      </polygon>
    </shape>
    <shape name="square" rotatable="false" editableColorIndex="0">
      <rectangle endX="270" startY="30" marked="true" color="-1920102913" endY="270" startX="30" filled="true"></rectangle>
    </shape>
    <shape name="square 2" rotatable="false" editableColorIndex="0">
      <rectangle endX="270" startY="30" marked="true" color="-1920102913" endY="270" startX="30" filled="true"></rectangle>
      <rectangle endX="240" startY="60" marked="false" color="255" endY="240" startX="60" filled="true"></rectangle>
    </shape>
    <shape name="star" rotatable="false" editableColorIndex="0">
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="151" y="1"></point>
        <point x="185" y="108"></point>
        <point x="298" y="108"></point>
        <point x="207" y="175"></point>
        <point x="242" y="282"></point>
        <point x="151" y="216"></point>
        <point x="59" y="282"></point>
        <point x="94" y="175"></point>
        <point x="3" y="108"></point>
        <point x="116" y="108"></point>
      </polygon>
    </shape>
    <shape name="target" rotatable="false" editableColorIndex="0">
      <circle x="0" y="0" marked="true" color="-1920102913" diameter="300" filled="true"></circle>
      <circle x="30" y="30" marked="false" color="255" diameter="240" filled="true"></circle>
      <circle x="60" y="60" marked="true" color="-1920102913" diameter="180" filled="true"></circle>
      <circle x="90" y="90" marked="false" color="255" diameter="120" filled="true"></circle>
      <circle x="120" y="120" marked="true" color="-1920102913" diameter="60" filled="true"></circle>
    </shape>
    <shape name="tree" rotatable="false" editableColorIndex="0">
      <circle x="118" y="3" marked="true" color="-1920102913" diameter="94" filled="true"></circle>
      <rectangle endX="180" startY="195" marked="false" color="-1653716737" endY="300" startX="120" filled="true"></rectangle>
      <circle x="65" y="21" marked="true" color="-1920102913" diameter="108" filled="true"></circle>
      <circle x="116" y="41" marked="true" color="-1920102913" diameter="127" filled="true"></circle>
      <circle x="45" y="90" marked="true" color="-1920102913" diameter="120" filled="true"></circle>
      <circle x="104" y="74" marked="true" color="-1920102913" diameter="152" filled="true"></circle>
    </shape>
    <shape name="triangle" rotatable="false" editableColorIndex="0">
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="150" y="30"></point>
        <point x="15" y="255"></point>
        <point x="285" y="255"></point>
      </polygon>
    </shape>
    <shape name="triangle 2" rotatable="false" editableColorIndex="0">
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="150" y="30"></point>
        <point x="15" y="255"></point>
        <point x="285" y="255"></point>
      </polygon>
      <polygon color="255" filled="true" marked="false">
        <point x="151" y="99"></point>
        <point x="225" y="223"></point>
        <point x="75" y="224"></point>
      </polygon>
    </shape>
    <shape name="truck" rotatable="false" editableColorIndex="0">
      <rectangle endX="195" startY="45" marked="true" color="-1920102913" endY="187" startX="4" filled="true"></rectangle>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="296" y="193"></point>
        <point x="296" y="150"></point>
        <point x="259" y="134"></point>
        <point x="244" y="104"></point>
        <point x="208" y="104"></point>
        <point x="207" y="194"></point>
      </polygon>
      <rectangle endX="195" startY="60" marked="false" color="-1" endY="105" startX="195" filled="true"></rectangle>
      <polygon color="255" filled="true" marked="false">
        <point x="238" y="112"></point>
        <point x="252" y="141"></point>
        <point x="219" y="141"></point>
        <point x="218" y="112"></point>
      </polygon>
      <circle x="234" y="174" marked="false" color="255" diameter="42" filled="true"></circle>
      <rectangle endX="214" startY="185" marked="true" color="-1920102913" endY="194" startX="181" filled="true"></rectangle>
      <circle x="144" y="174" marked="false" color="255" diameter="42" filled="true"></circle>
      <circle x="24" y="174" marked="false" color="255" diameter="42" filled="true"></circle>
      <circle x="24" y="174" marked="true" color="-1920102913" diameter="42" filled="false"></circle>
      <circle x="144" y="174" marked="true" color="-1920102913" diameter="42" filled="false"></circle>
      <circle x="234" y="174" marked="true" color="-1920102913" diameter="42" filled="false"></circle>
    </shape>
    <shape name="turtle" rotatable="true" editableColorIndex="0">
      <polygon color="1504722175" filled="true" marked="false">
        <point x="215" y="204"></point>
        <point x="240" y="233"></point>
        <point x="246" y="254"></point>
        <point x="228" y="266"></point>
        <point x="215" y="252"></point>
        <point x="193" y="210"></point>
      </polygon>
      <polygon color="1504722175" filled="true" marked="false">
        <point x="195" y="90"></point>
        <point x="225" y="75"></point>
        <point x="245" y="75"></point>
        <point x="260" y="89"></point>
        <point x="269" y="108"></point>
        <point x="261" y="124"></point>
        <point x="240" y="105"></point>
        <point x="225" y="105"></point>
        <point x="210" y="105"></point>
      </polygon>
      <polygon color="1504722175" filled="true" marked="false">
        <point x="105" y="90"></point>
        <point x="75" y="75"></point>
        <point x="55" y="75"></point>
        <point x="40" y="89"></point>
        <point x="31" y="108"></point>
        <point x="39" y="124"></point>
        <point x="60" y="105"></point>
        <point x="75" y="105"></point>
        <point x="90" y="105"></point>
      </polygon>
      <polygon color="1504722175" filled="true" marked="false">
        <point x="132" y="85"></point>
        <point x="134" y="64"></point>
        <point x="107" y="51"></point>
        <point x="108" y="17"></point>
        <point x="150" y="2"></point>
        <point x="192" y="18"></point>
        <point x="192" y="52"></point>
        <point x="169" y="65"></point>
        <point x="172" y="87"></point>
      </polygon>
      <polygon color="1504722175" filled="true" marked="false">
        <point x="85" y="204"></point>
        <point x="60" y="233"></point>
        <point x="54" y="254"></point>
        <point x="72" y="266"></point>
        <point x="85" y="252"></point>
        <point x="107" y="210"></point>
      </polygon>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="119" y="75"></point>
        <point x="179" y="75"></point>
        <point x="209" y="101"></point>
        <point x="224" y="135"></point>
        <point x="220" y="225"></point>
        <point x="175" y="261"></point>
        <point x="128" y="261"></point>
        <point x="81" y="224"></point>
        <point x="74" y="135"></point>
        <point x="88" y="99"></point>
      </polygon>
    </shape>
    <shape name="wheel" rotatable="false" editableColorIndex="0">
      <circle x="3" y="3" marked="true" color="-1920102913" diameter="294" filled="true"></circle>
      <circle x="30" y="30" marked="false" color="255" diameter="240" filled="true"></circle>
      <line endX="150" startY="285" marked="true" color="-1920102913" endY="15" startX="150"></line>
      <line endX="285" startY="150" marked="true" color="-1920102913" endY="150" startX="15"></line>
      <circle x="120" y="120" marked="true" color="-1920102913" diameter="60" filled="true"></circle>
      <line endX="79" startY="40" marked="true" color="-1920102913" endY="269" startX="216"></line>
      <line endX="269" startY="84" marked="true" color="-1920102913" endY="221" startX="40"></line>
      <line endX="269" startY="216" marked="true" color="-1920102913" endY="79" startX="40"></line>
      <line endX="221" startY="40" marked="true" color="-1920102913" endY="269" startX="84"></line>
    </shape>
    <shape name="wolf" rotatable="false" editableColorIndex="0">
      <polygon color="255" filled="true" marked="false">
        <point x="253" y="133"></point>
        <point x="245" y="131"></point>
        <point x="245" y="133"></point>
      </polygon>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="2" y="194"></point>
        <point x="13" y="197"></point>
        <point x="30" y="191"></point>
        <point x="38" y="193"></point>
        <point x="38" y="205"></point>
        <point x="20" y="226"></point>
        <point x="20" y="257"></point>
        <point x="27" y="265"></point>
        <point x="38" y="266"></point>
        <point x="40" y="260"></point>
        <point x="31" y="253"></point>
        <point x="31" y="230"></point>
        <point x="60" y="206"></point>
        <point x="68" y="198"></point>
        <point x="75" y="209"></point>
        <point x="66" y="228"></point>
        <point x="65" y="243"></point>
        <point x="82" y="261"></point>
        <point x="84" y="268"></point>
        <point x="100" y="267"></point>
        <point x="103" y="261"></point>
        <point x="77" y="239"></point>
        <point x="79" y="231"></point>
        <point x="100" y="207"></point>
        <point x="98" y="196"></point>
        <point x="119" y="201"></point>
        <point x="143" y="202"></point>
        <point x="160" y="195"></point>
        <point x="166" y="210"></point>
        <point x="172" y="213"></point>
        <point x="173" y="238"></point>
        <point x="167" y="251"></point>
        <point x="160" y="248"></point>
        <point x="154" y="265"></point>
        <point x="169" y="264"></point>
        <point x="178" y="247"></point>
        <point x="186" y="240"></point>
        <point x="198" y="260"></point>
        <point x="200" y="271"></point>
        <point x="217" y="271"></point>
        <point x="219" y="262"></point>
        <point x="207" y="258"></point>
        <point x="195" y="230"></point>
        <point x="192" y="198"></point>
        <point x="210" y="184"></point>
        <point x="227" y="164"></point>
        <point x="242" y="144"></point>
        <point x="259" y="145"></point>
        <point x="284" y="151"></point>
        <point x="277" y="141"></point>
        <point x="293" y="140"></point>
        <point x="299" y="134"></point>
        <point x="297" y="127"></point>
        <point x="273" y="119"></point>
        <point x="270" y="105"></point>
      </polygon>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="-1" y="195"></point>
        <point x="14" y="180"></point>
        <point x="36" y="166"></point>
        <point x="40" y="153"></point>
        <point x="53" y="140"></point>
        <point x="82" y="131"></point>
        <point x="134" y="133"></point>
        <point x="159" y="126"></point>
        <point x="188" y="115"></point>
        <point x="227" y="108"></point>
        <point x="236" y="102"></point>
        <point x="238" y="98"></point>
        <point x="268" y="86"></point>
        <point x="269" y="92"></point>
        <point x="281" y="87"></point>
        <point x="269" y="103"></point>
        <point x="269" y="113"></point>
      </polygon>
    </shape>
    <shape name="x" rotatable="false" editableColorIndex="0">
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="270" y="75"></point>
        <point x="225" y="30"></point>
        <point x="30" y="225"></point>
        <point x="75" y="270"></point>
      </polygon>
      <polygon color="-1920102913" filled="true" marked="true">
        <point x="30" y="75"></point>
        <point x="75" y="30"></point>
        <point x="270" y="225"></point>
        <point x="225" y="270"></point>
      </polygon>
    </shape>
  </turtleShapes>
  <linkShapes>
    <shape name="default" curviness="0.0">
      <lines>
        <line x="-0.2" visible="false">
          <dash value="0.0"></dash>
          <dash value="1.0"></dash>
        </line>
        <line x="0.0" visible="true">
          <dash value="1.0"></dash>
          <dash value="0.0"></dash>
        </line>
        <line x="0.2" visible="false">
          <dash value="0.0"></dash>
          <dash value="1.0"></dash>
        </line>
      </lines>
      <indicator>
        <shape name="link direction" rotatable="true" editableColorIndex="0">
          <line endX="90" startY="150" marked="true" color="-1920102913" endY="180" startX="150"></line>
          <line endX="210" startY="150" marked="true" color="-1920102913" endY="180" startX="150"></line>
        </shape>
      </indicator>
    </shape>
  </linkShapes>
  <previewCommands>setup repeat 75 [ go ]</previewCommands>
</model>
