%%%
% Urne et probabilités
%%%
\def\filedateUrneProba{2025/05/26}%
\def\fileversionUrneProba{0.1a}%
\message{-- \filedateUrneProba\space v\fileversionUrneProba}%
%
\newtoks\tokUrneListeCouleurs%
\newtoks\tokUrneListeColonnes%
\newtoks\tokUrneListeNombres%

\def\UpdatetoksUrneCouleurs#1\nil{\addtotok\tokUrneListeCouleurs{#1,}}%
\def\UpdatetoksUrneNombres#1\nil{\addtotok\tokUrneListeNombres{"#1",}}%
\def\UpdatetoksUrneColonnes#1\nil{\addtotok\tokUrneListeColonnes{"#1",}}%

\setKVdefault[PfCUrne]{Couleurs=false,Nombres=false,Echelle=1,Repartition={1,2,3},Double=false,RepartitionC={1,2,3},RepartitionN={1,2,3},Roue=false,Rayon=3,Tableau=false,SansRemise=false,Solution=false,CouleurLigne=0.85white,CouleurColonne=0.85white,Different=false,RepartitionLigne={1,2,3},RepartitionColonne={1,2,3},Impression,Casino=false,Traces={},ListeCouleurs={},ListeNombres={},ListeColonne={},ListeLigne={},Orientation=false,CoefEcart=17,Association=false,Ameliore=false,Graine=1,LargeurMur=5,HauteurMur=10}%

\makeatletter
\NewDocumentCommand\PfC@BuildRoulette{}{%
  \begin{Geometrie}[Cadre="aucun"]
    u:=\useKV[PfCUrne]{Echelle}*1cm;

    color colzero,colrouge,coltoura,coltourb,colbarre;

    boolean Impression;
    Impression=\useKV[PfCUrne]{Impression};

    if Impression=false:
      colzero=green;
      colrouge=red;
      coltoura=(179,103,0)/256;
      coltourb=(179,111,48)/256;
      colbarre=0.7529white;
    else:
      colzero=white;
      colrouge=white;
      coltoura=black;
      coltourb=black;
      colbarre=black;
    fi;
    pair O,A[],B[],C[],D[];
    path cc[];
    O=(0,0);
    cc1=cercles(O,2u);
    cc2=cercles(O,2.75u);
    cc3=cercles(O,3.5u);
    cc4=cercles(O,3.7u);
    cc5=cercles(O,4u);
    cc6=cercles(O,3.125u);
    cc7=cercles(O,2.375u);
    if Impression=false:
      fill cc5 withcolor coltoura;
      fill cc4 withcolor coltourb;
      fill cc1 withcolor coltoura;
      trace cc1 withpen pencircle scaled 1.05;
      trace cc5 withpen pencircle scaled 1.05;
      trace cc4 withpen pencircle scaled 1.05;
      trace cc3 withpen pencircle scaled 1.05;
    else:
      fill cc5;
      fill cc4 withcolor white;
      trace cc1;
      trace cc3;
    fi;
    for k=0 upto 38:
      A[k]=pointarc(cc3,90-k*(360/37));
      B[k]=pointarc(cc1,90-k*(360/37));
    endfor;
    na:=1;
    for p_=32,15,19,4,21,2,25,17,34,6,27,13,36,11,30,8,23,10,5,24,16,33,1,20,14,31,9,22,18,29,7,28,12,35,3,26,0:
      if (na mod 2)=0:
        fill arccercle(A[na],A[na-1],O)--B[na-1]--reverse(arccercle(B[na],B[na-1],O))--cycle;
        drawoptions(withcolor white);
        label(TEX("\textbf{"&decimal(p_)&"}") rotated (-na*(360/37)),pointarc(cc6,90+0.5*(360/37)-na*(360/37)));
        drawoptions();
      else:
        if p_=0:
          fill arccercle(A[na],A[na-1],O)--B[na-1]--reverse(arccercle(B[na],B[na-1],O))--cycle withcolor colzero;
        else:
          fill arccercle(A[na],A[na-1],O)--B[na-1]--reverse(arccercle(B[na],B[na-1],O))--cycle withcolor colrouge;
        fi;
        if Impression=false:
          drawoptions(withcolor white);
        fi;
        label(TEX("\textbf{"&decimal(p_)&"}") rotated (-na*(360/37)),pointarc(cc6,90+0.5*(360/37)-na*(360/37)));
        if Impression=false:
          drawoptions();
        fi;
      fi;
      trace arccercle(A[na],A[na-1],O)--B[na-1]--reverse(arccercle(B[na],B[na-1],O))--cycle;
      na:=na+1;
    endfor;
    trace cc2;
    fill cercles(pointarc(cc7,90+0.5*(360/37)),0.125u);
    % barre
    cc8=cercles(O,1.5u);
    cc9=cercles(O,0.25u);
    fill cc9 withcolor colbarre;
    pair E[];
    anglebase=floor(uniformdeviate(360));
    E1=pointarc(cc8,anglebase);
    E4=pointarc(cc8,anglebase+6);
    E3=symetrie(E1,O);
    E2=symetrie(E4,O);
    E5=pointarc(cc8,anglebase+90);
    E8=pointarc(cc8,anglebase+6+90);
    E7=symetrie(E5,O);
    E6=symetrie(E8,O);
    fill polygone(E1,E2,E3,E4) withcolor colbarre;
    fill polygone(E5,E6,E7,E8) withcolor colbarre;
    pair F[];
    F1=(E1--iso(E1,E2)) intersectionpoint cc9;
    F2=(E4--iso(E3,E4)) intersectionpoint cc9;
    F3=(E5--iso(E6,E5)) intersectionpoint cc9;
    F4=(E8--iso(E7,E8)) intersectionpoint cc9;
    F5=(E3--iso(E4,E3)) intersectionpoint cc9;
    F6=(E2--iso(E2,E1)) intersectionpoint cc9;
    F7=(E7--iso(E8,E7)) intersectionpoint cc9;
    F8=(E6--iso(E6,E5)) intersectionpoint cc9;
    trace E1--E4--F2--arccercle(F2,F3,O)--E5--E8--F4--arccercle(F4,F5,O)--E3--E2--F6--arccercle(F6,F7,O)--E7--E6--F8--arccercle(F8,F1,O)--cycle;
  \end{Geometrie}
}%

\NewDocumentCommand\PfC@BuildTableauDoubleEntreeDifferent{mmmm}{%
  % #1 : les labels en colonne
  % #2 : les labels en ligne
  % #3 : la répartition en colonne
  % #4 : la répartition en ligne
  \mplibforcehmode%
  \begin{mplibcode}
    u:=\useKV[PfCUrne]{Echelle}*1cm;
    numeric RetiensNumC[],RetiensNumL[];
    % 
    vardef RecupRepartition(text t)=
      n:=0;
      for p_=t:
        RetiensNumL[n]=p_;
        n:=n+1;
      endfor;
      totallignes=n;
    enddef;
    % 
    vardef RecupRepartitionC(text t)=
      n:=0;
      for p_=t:
        RetiensNumC[n]=p_;
        n:=n+1;
      endfor;
      totalcolonnes=n;
    enddef;
    % 
    string Colonnes[];
    vardef RecuperationColonnes(text t)=
      n:=0;
      for p_=t:
        n:=n+1;
        Colonnes[n]=p_;
      endfor;
    enddef;
    % 
    string Lignes[];
    vardef RecuperationLignes(text t)=
      n:=0;
      for p_=t:
        n:=n+1;
        Lignes[n]=p_;
      endfor;
    enddef;
    % 
    boolean Solution;%, Codes;
    Solution=\useKV[PfCUrne]{Solution};
    %Codes=\useKV[PfCUrne]{Codes};
    % 
    color ColLigne,ColColonne;
    ColLigne=\useKV[PfCUrne]{CouleurLigne};
    ColColonne=\useKV[PfCUrne]{CouleurColonne};
    % 
    RecupRepartitionC(#3);
    RecupRepartition(#4);
    RecuperationColonnes(#1);
    RecuperationLignes(#2);
    
    pair A[][],C[][];
    for k=0 upto totallignes+1:
      for l=0 upto totalcolonnes+1:
        A[k][l]=(0,0) shifted(u*(l,-k));
        C[k][l]=A[k][l] shifted(u*(0.5,-0.5));
      endfor;
    endfor;

    fill polygone(A[0][1],A[0][totalcolonnes+1],A[1][totalcolonnes+1],A[1][1]) withcolor ColLigne;
    fill polygone(A[1][0],A[totallignes+1][0],A[totallignes+1][1],A[1][1]) withcolor ColColonne;
    for k=1 upto totalcolonnes:
      label(TEX(Colonnes[RetiensNumC[k-1]]),iso(A[1][k],A[0][k+1]));
      trace segment(A[0][k],A[totallignes+1][k]);
    endfor;
    for k=1 upto totallignes:
      label(TEX(Lignes[RetiensNumL[k-1]]),iso(A[k][0],A[k+1][1]));
      trace segment(A[k][0],A[k][totalcolonnes+1]);
    endfor;
    % 
    trace A[1][0]--A[totallignes+1][0]--A[totallignes+1][totalcolonnes+1]--A[0][totalcolonnes+1]--A[0][1];
    labeloffset:=labeloffset*4;
    label.top(TEX("Tirage 1"),iso(A[0][1],A[0][totalcolonnes+1]));
    label.lft(TEX("Tirage 2") rotated 90,iso(A[totallignes+1][0],A[1][0]));
    labeloffset:=labeloffset/4;
    
    path ccsol[][];
    
    if Solution:
      for k=1 upto totallignes:
        for l=1 upto totalcolonnes:
          label(TEX(Colonnes[RetiensNumC[l-1]]&"--"&Lignes[RetiensNumL[k-1]]),iso(A[k][l],A[k+1][l+1]));
        endfor;
      endfor;
    fi;

    \ifemptyKV[PfCUrne]{Traces}{}{\useKV[PfCUrne]{Traces};}%
  \end{mplibcode}%
}%

\NewDocumentCommand\PfC@BuildTableauDoubleEntree{mmm}{%
  \mplibforcehmode%
  \begin{mplibcode}
    u:=\useKV[PfCUrne]{Echelle}*1cm;
    numeric RetiensNum[];
    % 
    vardef RecupRepartition(text t)=
      n:=0;
      for p_=t:
        RetiensNum[n]=p_;
        n:=n+1;
      endfor;
      totalboules=n;
    enddef;
    % 
    color Col[];
    vardef RecuperationCouleurs(text t)=
      n:=0;
      for p_=t:
        n:=n+1;
        Col[n]=p_;
      endfor;
    enddef;
    % 
    string Nombres[];
    vardef RecuperationNombres(text t)=
      n:=0;
      for p_=t:
        n:=n+1;
        Nombres[n]=p_;
      endfor;
    enddef;
    % 
    numeric Rayon;
    Rayon=\useKV[PfCUrne]{Rayon};
    % 
    boolean Couleurs, Nombres, Roue, Solution, SansRemise;
    Couleurs=\useKV[PfCUrne]{Couleurs};
    Nombres=\useKV[PfCUrne]{Nombres};
    Roue=\useKV[PfCUrne]{Roue};
    Solution=\useKV[PfCUrne]{Solution};
    SansRemise=\useKV[PfCUrne]{SansRemise};
    % 
    color ColLigne,ColColonne;
    ColLigne=\useKV[PfCUrne]{CouleurLigne};
    ColColonne=\useKV[PfCUrne]{CouleurColonne};

    RecupRepartition(#3);
    if Couleurs:
      RecuperationCouleurs(#1);
    fi;
    if Nombres:
      RecuperationNombres(#2);
    fi;

    pair A[][],C[][];
    for k=0 upto totalboules+1:
      for l=0 upto totalboules+1:
        A[k][l]:=(0,0) shifted(u*(l,-k));
      endfor;
    endfor;

    for k=0 upto totalboules:
      for l=0 upto totalboules:
        C[k][l]=A[k][l] shifted(u*(0.5,-0.5));
      endfor;
    endfor;

    if Couleurs:
      drawoptions(withpen pencircle scaled 0.75);
      for k=1 upto totalboules:
        fill cercles(iso(A[1][k],A[0][k+1]),0.35u) withcolor Col[RetiensNum[k-1]];
        fill cercles(iso(A[k][0],A[k+1][1]),0.35u) withcolor Col[RetiensNum[k-1]];
        trace cercles(iso(A[1][k],A[0][k+1]),0.35u);
        trace cercles(iso(A[k][0],A[k+1][1]),0.35u);
      endfor;
      drawoptions();
    else:
      fill polygone(A[0][1],A[0][totalboules+1],A[1][totalboules+1],A[1][1]) withcolor ColLigne;
      fill polygone(A[1][0],A[totalboules+1][0],A[totalboules+1][1],A[1][1]) withcolor ColColonne;
      for k=1 upto totalboules:
        label(TEX(Nombres[RetiensNum[k-1]]),iso(A[1][k],A[0][k+1]));
        label(TEX(Nombres[RetiensNum[k-1]]),iso(A[k][0],A[k+1][1]));
      endfor;
    fi;
    if SansRemise:
      for k=1 upto totalboules:
        draw 1/8[A[k][k],A[k+1][k+1]]--7/8[A[k][k],A[k+1][k+1]];
        draw 1/8[A[k+1][k],A[k][k+1]]--7/8[A[k+1][k],A[k][k+1]];
      endfor;
    fi;
    for k=1 upto totalboules:
      trace segment(A[k][0],A[k][totalboules+1]);
      trace segment(A[0][k],A[totalboules+1][k]);
    endfor;
    trace A[1][0]--A[totalboules+1][0]--A[totalboules+1][totalboules+1]--A[0][totalboules+1]--A[0][1];
    labeloffset:=labeloffset*4;
    label.top(TEX("Tirage 1"),iso(A[0][1],A[0][totalboules+1]));
    label.lft(TEX("Tirage 2") rotated 90,iso(A[totalboules+1][0],A[1][0]));
    labeloffset:=labeloffset/4;
    
    path ccsol[][];

    if Solution:
      if Couleurs:
        drawoptions(withpen pencircle scaled 0.75);
        for k=1 upto totalboules:
          for l=1 upto totalboules:
            ccsol[k][l]=cercles(iso(A[k][l],A[k+1][l+1]),0.25u);
            if SansRemise:
              if k<>l:
                fill arccercle(pointarc(ccsol[k][l],315),pointarc(ccsol[k][l],135),iso(A[k][l],A[k+1][l+1]))--iso(A[k][l],A[k+1][l+1])--cycle withcolor Col[RetiensNum[l-1]];
                fill arccercle(pointarc(ccsol[k][l],135),pointarc(ccsol[k][l],315),iso(A[k][l],A[k+1][l+1]))--iso(A[k][l],A[k+1][l+1])--cycle withcolor Col[RetiensNum[k-1]];
                trace segment(pointarc(ccsol[k][l],135),pointarc(ccsol[k][l],315));
                trace ccsol[k][l];
              fi;
            else:
              fill arccercle(pointarc(ccsol[k][l],315),pointarc(ccsol[k][l],135),iso(A[k][l],A[k+1][l+1]))--iso(A[k][l],A[k+1][l+1])--cycle withcolor Col[RetiensNum[l-1]];
              fill arccercle(pointarc(ccsol[k][l],135),pointarc(ccsol[k][l],315),iso(A[k][l],A[k+1][l+1]))--iso(A[k][l],A[k+1][l+1])--cycle withcolor Col[RetiensNum[k-1]];
              trace segment(pointarc(ccsol[k][l],135),pointarc(ccsol[k][l],315));
              trace ccsol[k][l];
            fi;
          endfor;
        endfor;
        drawoptions();
      else:
        for k=1 upto totalboules:
          for l=1 upto totalboules:
            if SansRemise:
              if k<>l:
                label(TEX(Nombres[RetiensNum[l-1]]&"--"&Nombres[RetiensNum[k-1]]),iso(A[k][l],A[k+1][l+1]));
              fi;
            else:
              label(TEX(Nombres[RetiensNum[l-1]]&"--"&Nombres[RetiensNum[k-1]]),iso(A[k][l],A[k+1][l+1]));
            fi;
          endfor;
        endfor;
      fi;
    fi;

    \ifemptyKV[PfCUrne]{Traces}{}{\useKV[PfCUrne]{Traces};}%
  \end{mplibcode}%
}%

% Source - https://tex.stackexchange.com/a/763104
% Posted by Explorer, modified by community. See post 'Timeline' for change history
% Retrieved 2026-05-28, License - CC BY-SA 4.0
\begin{luacode*}
    physics = physics or {}

    function physics.trapezoid_walls(left_top, left_bottom, right_bottom, right_top)
        return {
            {left_top[1], left_top[2], left_bottom[1], left_bottom[2]},
            {left_bottom[1], left_bottom[2], right_bottom[1], right_bottom[2]},
            {right_bottom[1], right_bottom[2], right_top[1], right_top[2]},
        }
    end

    function physics.prepare_walls(raw_walls)
        local walls = {}
        for _, raw in ipairs(raw_walls) do
            local x1, y1, x2, y2 = raw[1], raw[2], raw[3], raw[4]
            local dx = x2 - x1
            local dy = y2 - y1
            local len = math.sqrt(dx * dx + dy * dy)
            local nx = -dy / len
            local ny = dx / len
            table.insert(walls, {
                x1 = x1, y1 = y1, x2 = x2, y2 = y2,
                dx = dx, dy = dy, len = len,
                nx = nx, ny = ny,
                c = nx * x1 + ny * y1,
            })
        end
        return walls
    end

    function physics.draw_packed_balls(num_balls, r, raw_walls, options)
        if type(options) ~= "table" then
            options = {seed = options}
        end

        local seed = options.seed
        local ball_style_draw = options.ball_style_draw or 'withcolor mplibcolor "orange!80!yellow"'
        local ball_style_fill = options.ball_style_fill or 'withcolor mplibcolor "orange!60!yellow"'
        local wall_style = options.wall_style or "ultra thick, line cap=rect"
        local highlight_style = options.highlight_style or "fill=white, opacity=0.6"
        local draw_highlight = options.draw_highlight
        if draw_highlight == nil then
            draw_highlight = true
        end

        if seed then math.randomseed(seed) end
        local walls = physics.prepare_walls(raw_walls)
        local placed_balls = {}

        local eps = 1e-7
        local contact_dist = 2 * r
        local x_left = math.huge
        local x_right = -math.huge
        for _, wall in ipairs(walls) do
            x_left = math.min(x_left, wall.x1, wall.x2)
            x_right = math.max(x_right, wall.x1, wall.x2)
        end

        local function wall_projection(wall, x, y)
            return ((x - wall.x1) * wall.dx + (y - wall.y1) * wall.dy) / (wall.len * wall.len)
        end

        local function touches_wall_segment(wall, x, y)
            local t = wall_projection(wall, x, y)
            return t >= -eps and t <= 1 + eps
        end

        local function inside_container(x, y)
            for _, wall in ipairs(walls) do
                if wall.nx * x + wall.ny * y < wall.c + r - eps then
                    return false
                end
            end
            return true
        end

        local function overlaps_any(x, y)
            for _, ball in ipairs(placed_balls) do
                local dx = x - ball.x
                local dy = y - ball.y
                if dx * dx + dy * dy < contact_dist * contact_dist - eps then
                    return true
                end
            end
            return false
        end

        local function add_candidate(candidates, x, y, kind)
            if inside_container(x, y) and not overlaps_any(x, y) then
                table.insert(candidates, {x = x, y = y, kind = kind})
            end
        end

        local function add_two_ball_candidates(candidates, a, b)
            local dx = b.x - a.x
            local dy = b.y - a.y
            local d2 = dx * dx + dy * dy
            local d = math.sqrt(d2)
            if d < eps or d > 2 * contact_dist + eps then
                return
            end

            local mx = (a.x + b.x) / 2
            local my = (a.y + b.y) / 2
            local h2 = contact_dist * contact_dist - (d / 2) * (d / 2)
            if h2 < -eps then
                return
            end

            local h = math.sqrt(math.max(0, h2))
            local px = -dy / d
            local py = dx / d

            local x1 = mx + h * px
            local y1 = my + h * py
            local x2 = mx - h * px
            local y2 = my - h * py

            if y1 > a.y + eps and y1 > b.y + eps then
                add_candidate(candidates, x1, y1, "two-balls")
            end
            if y2 > a.y + eps and y2 > b.y + eps then
                add_candidate(candidates, x2, y2, "two-balls")
            end
        end

        local function add_wall_wall_candidate(candidates, a, b)
            local det = a.nx * b.ny - a.ny * b.nx
            if math.abs(det) < eps then
                return
            end

            local ca = a.c + r
            local cb = b.c + r
            local x = (ca * b.ny - a.ny * cb) / det
            local y = (a.nx * cb - ca * b.nx) / det
            if touches_wall_segment(a, x, y) and touches_wall_segment(b, x, y) then
                add_candidate(candidates, x, y, "two-walls")
            end
        end

        local function add_wall_drop_candidate(candidates, wall, x_start)
            if wall.ny <= 0.9 or math.abs(wall.ny) < eps then
                return
            end

            local y = (wall.c + r - wall.nx * x_start) / wall.ny
            if touches_wall_segment(wall, x_start, y) then
                add_candidate(candidates, x_start, y, "floor-wall")
            end
        end

        local function add_wall_ball_candidate(candidates, wall, ball)
            local signed_dist = wall.nx * ball.x + wall.ny * ball.y - (wall.c + r)
            local h2 = contact_dist * contact_dist - signed_dist * signed_dist
            if h2 < -eps then
                return
            end

            local base_x = ball.x - signed_dist * wall.nx
            local base_y = ball.y - signed_dist * wall.ny
            local h = math.sqrt(math.max(0, h2))
            local tx = wall.dx / wall.len
            local ty = wall.dy / wall.len

            local x1 = base_x + h * tx
            local y1 = base_y + h * ty
            local x2 = base_x - h * tx
            local y2 = base_y - h * ty

            if y1 > ball.y + eps and touches_wall_segment(wall, x1, y1) then
                add_candidate(candidates, x1, y1, "wall-ball")
            end
            if y2 > ball.y + eps and touches_wall_segment(wall, x2, y2) then
                add_candidate(candidates, x2, y2, "wall-ball")
            end
        end

        local function choose_candidate(candidates, x_start)
            local best = nil
            for _, candidate in ipairs(candidates) do
                if not best
                    or candidate.y < best.y - eps
                    or (math.abs(candidate.y - best.y) <= eps
                        and math.abs(candidate.x - x_start) < math.abs(best.x - x_start)) then
                    best = candidate
                end
            end
            return best
        end

        for i = 1, num_balls do
            local x_start = x_left + math.random() * (x_right - x_left)

            local candidates = {}
            for _, wall in ipairs(walls) do
                add_wall_drop_candidate(candidates, wall, x_start)
            end
            for a = 1, #walls - 1 do
                for b = a + 1, #walls do
                    add_wall_wall_candidate(candidates, walls[a], walls[b])
                end
            end
            for _, ball in ipairs(placed_balls) do
                for _, wall in ipairs(walls) do
                    add_wall_drop_candidate(candidates, wall, ball.x - contact_dist)
                    add_wall_drop_candidate(candidates, wall, ball.x + contact_dist)
                    add_wall_ball_candidate(candidates, wall, ball)
                end
            end
            for a = 1, #placed_balls - 1 do
                for b = a + 1, #placed_balls do
                    add_two_ball_candidates(candidates, placed_balls[a], placed_balls[b])
                end
            end

            local best = choose_candidate(candidates, x_start)
            if not best then
                tex.error("no stable position found for ball " .. i)
                return
            end

            local best_x = best.x
            local best_y = best.y
            table.insert(placed_balls, {x = best_x, y = best_y})
            tex.print(string.format("A[nbc]=u*(%.3f,%.3f);nbc:=nbc+1;", best_x, best_y))
        end

    end
\end{luacode*}

\NewDocumentCommand\PfC@BuildUrnePhysic{mmm}{%
  \edef\TotalBoulesMP{0}%
  \xintFor ##1 in {#3}\do{%
    \edef\TotalBoulesMP{\fpeval{\TotalBoulesMP+1}}%
  }%
  \mplibforcehmode%
  \begin{mplibcode}
    u:=\useKV[PfCUrne]{Echelle}*1cm;
    numeric RetiensNum[];
    vardef RecupRepartition(text t)=
      n:=0;
      for p_=t:
        RetiensNum[n]=p_;
        n:=n+1;
      endfor;
    enddef;
    totalboules=\TotalBoulesMP;

    color Col[];
    vardef RecuperationCouleurs(text t)=
      n:=0;
      for p_=t:
        n:=n+1;
        Col[n]=p_;
      endfor;
    enddef;

    string Nombres[];
    vardef RecuperationNombres(text t)=
      n:=0;
      for p_=t:
        n:=n+1;
        Nombres[n]=p_;
      endfor;
    enddef;

    numeric Rayon,CoefEcart;
    CoefEcart=\useKV[PfCUrne]{CoefEcart};
    Rayon=\useKV[PfCUrne]{Rayon};

    boolean Couleurs, Nombres, Roue, Orientation;
    Couleurs=\useKV[PfCUrne]{Couleurs};
    Nombres=\useKV[PfCUrne]{Nombres};
    Roue=\useKV[PfCUrne]{Roue};
    Orientation=\useKV[PfCUrne]{Orientation};

    RecupRepartition(#3);
    if Couleurs:
      RecuperationCouleurs(#1);
    fi;
    if Nombres:
      RecuperationNombres(#2);
    fi;

    pair O;
    pair A[],B[];
    if Roue:
        O=(0,0);
        path cc;
        cc=cercles(O,Rayon*u);
        angd=180/totalboules;
        angr=360/totalboules;
        for k=1 upto totalboules:
          A[k]=(CoefEcart/20)[O,pointarc(cc,angd+(k-1)*angr)];
        endfor;
        drawarrow rotation((O+u*(0,1.35*Rayon))--(O+u*(0,1.1*Rayon)),O,angd);
        % trace cc;
        B[0]=pointarc(cc,0);
        for k=1 upto totalboules:
          B[k]=pointarc(cc,k*angr);
          if Couleurs:
            fill O--arccercle(B[k-1],B[k],O)--cycle withcolor if unknown Col[RetiensNum[k-1]]:white else: Col[RetiensNum[k-1]] fi;
          else:
            if Orientation:
              % label(TEX(Nombres[RetiensNum[k-1]]) rotated angle(A[k]-O),iso(O,A[k]));
              marque_my:=marque_my/10;
              Mylabel(TEX(Nombres[RetiensNum[k-1]]),O--A[k],0.8);
              marque_my:=marque_my*10;
            else:
              label(TEX(Nombres[RetiensNum[k-1]]),A[k]);
            fi;
          fi;
        endfor;
        trace cc;
        for k=1 upto totalboules:
          trace O--B[k];
        endfor;
      else:
    nbc:=0;
    % Déterminer les centres des cercles.
    \directlua{
      physics.draw_packed_balls(\TotalBoulesMP, 0.5,
      physics.trapezoid_walls({0, \useKV[PfCUrne]{HauteurMur}},{0, 0}, {\useKV[PfCUrne]{LargeurMur}, 0}, {\useKV[PfCUrne]{LargeurMur}, \useKV[PfCUrne]{HauteurMur}}),
      {
        seed = \useKV[PfCUrne]{Graine},
      })
    }
    % Afficher les cercles et les labels éventuels.
    for k=0 upto totalboules-1:
      if Couleurs:
        fill cercles(A[k],0.5u) withcolor if unknown Col[RetiensNum[k]]:white else: Col[RetiensNum[k]] fi;
      else:
        label(TEX(Nombres[RetiensNum[k]]),A[k]);
      fi;
      trace cercles(A[k],0.5u);
    endfor;
    %
    drawoptions(withpen pencircle scaled 1.2);
    bboxmargin:=0;
    path CadreBox;
    CadreBox=bbox currentpicture;
    trace (ulcorner CadreBox)--(point(0) of CadreBox)--(point(1) of CadreBox)--(point(2) of CadreBox);
    drawoptions();
    fi;
  \end{mplibcode}
}%

\NewDocumentCommand\PfC@BuildUrneDouble{mmmm}{%
  % #1 Liste Couleurs
  % #2 Liste Nombres
  % #3 Repartition des couleurs
  % #4 Repartition des nombres
  \edef\TotalBoulesMP{0}%
  \xintFor ##1 in {#3}\do{%
    \edef\TotalBoulesMP{\fpeval{\TotalBoulesMP+1}}%
  }%
  \mplibforcehmode
  \begin{mplibcode}
    u:=\useKV[PfCUrne]{Echelle}*1cm;
    numeric RetiensC[],RetiensNum[];
    %
    vardef RecupRepartitionC(text t)=
      n:=0;
      for p_=t:
        RetiensC[n]=p_;
        n:=n+1;
      endfor;
    enddef;
    totalboules=\TotalBoulesMP;
    %
    vardef RecupRepartition(text t)=
      n:=0;
      for p_=t:
        RetiensNum[n]=p_;
        n:=n+1;
      endfor;
    enddef;

    color Col[];
    vardef RecuperationCouleurs(text t)=
      n:=0;
      for p_=t:
        n:=n+1;
        Col[n]=p_;
      endfor;
    enddef;

    string Nombres[];
    vardef RecuperationNombres(text t)=
      n:=0;
      for p_=t:
        n:=n+1;
        Nombres[n]=p_;
      endfor;
    enddef;

    numeric Rayon;
    Rayon=\useKV[PfCUrne]{Rayon};

    boolean Roue,Orientation,Ameliore;
    Roue=\useKV[PfCUrne]{Roue};
    Orientation=\useKV[PfCUrne]{Orientation};
    Ameliore=\useKV[PfCUrne]{Ameliore};

    RecupRepartitionC(#3);
    RecupRepartition(#4);
    RecuperationCouleurs(#1);
    RecuperationNombres(#2);

    pair O;
    pair A[],B[];
    %
    nbc:=0;
    % Afficher les cercles et les labels éventuels.
    if Roue:
      O=(0,0);
      path cc;
      cc=cercles(O,Rayon*u);
      angd=180/totalboules;
      angr=360/totalboules;
      B[0]=pointarc(cc,0);
      for k=1 upto totalboules:
        A[k]=17/20[O,pointarc(cc,angd+(k-1)*angr)];
        B[k]=pointarc(cc,k*angr);
        fill O--arccercle(B[k-1],B[k],O)--cycle withcolor if unknown Col[RetiensC[k-1]]:white else: Col[RetiensC[k-1]] fi;
        if Orientation:
          marque_my:=marque_my/10;
          Mylabel(TEX(Nombres[RetiensNum[k-1]]),O--A[k],0.8);
          marque_my:=marque_my*10;
        else:
          label(TEX(Nombres[RetiensNum[k-1]]),A[k]);
        fi;
      endfor;
      for k=1 upto totalboules:
        trace O--B[k] if Ameliore:withpen pencircle scaled 1.05 withcolor white fi;
      endfor;
      if Ameliore:
        fill cercles(O,3mm);
        trace cercles(O,3mm) withpen pencircle scaled 1.05 withcolor white;
      fi;
      trace cc if Ameliore:withpen pencircle scaled 1.2 fi;
      drawarrow rotation((O+u*(0,1.35*Rayon))--(O+u*(0,1.1*Rayon)),O,angd);
    else:
      % Déterminer les centres des cercles.
      \directlua{
        physics.draw_packed_balls(\TotalBoulesMP, 0.5,
        physics.trapezoid_walls({0, 0}, {0, -\useKV[PfCUrne]{HauteurMur}}, {\useKV[PfCUrne]{LargeurMur}, -\useKV[PfCUrne]{HauteurMur}}, {\useKV[PfCUrne]{LargeurMur}, 0}),
        {
          seed = \useKV[PfCUrne]{Graine},
        })
      }
      for k=0 upto totalboules-1:
        fill cercles(A[k],0.5u) withcolor if unknown Col[RetiensC[k]]:white else: Col[RetiensC[k]] fi;
        label(TEX(Nombres[RetiensNum[k]]),A[k]);
        trace cercles(A[k],0.5u);
      endfor;
      drawoptions(withpen pencircle scaled 1.2);
      bboxmargin:=0;
      path CadreBox;
      CadreBox=bbox currentpicture;
      trace (ulcorner CadreBox)--(point(0) of CadreBox)--(point(1) of CadreBox)--(point(2) of CadreBox);
      drawoptions();
    fi;
  \end{mplibcode}%
}%

\NewDocumentCommand\SchemaProba{o}{%
  \useKVdefault[PfCUrne]%
  \setKV[PfCUrne]{#1}%
  \tokUrneListeCouleurs{}%
  \tokUrneListeNombres{}%
  \tokUrneListeColonnes{}%
  \ifemptyKV[PfCUrne]{ListeCouleurs}{}{\setKV[PfCUrne]{Couleurs}\edef\PfCTestCouleurs{\useKV[PfCUrne]{ListeCouleurs}}\setsepchar{,}\ignoreemptyitems\readlist*\ListeCouleursAv{\PfCTestCouleurs}\reademptyitems}%
  \ifemptyKV[PfCUrne]{ListeNombres}{}{\setKV[PfCUrne]{Nombres}\edef\PfCTestNombres{\useKV[PfCUrne]{ListeNombres}}\setsepchar{,}\ignoreemptyitems\readlist*\ListeNombresAv{\PfCTestNombres}\reademptyitems}%
  \ifemptyKV[PfCUrne]{ListeColonne}{}{\edef\PfCTestColonnes{\useKV[PfCUrne]{ListeColonne}}\setsepchar{,}\ignoreemptyitems\readlist*\ListeCouleursAv{\PfCTestColonnes}\reademptyitems}%
  \ifemptyKV[PfCUrne]{ListeLigne}{}{\edef\PfCTestLignes{\useKV[PfCUrne]{ListeLigne}}\setsepchar{,}\ignoreemptyitems\readlist*\ListeNombresAv{\PfCTestLignes}\reademptyitems}%
  \ifboolKV[PfCUrne]{Casino}{%
    \PfC@BuildRoulette%
  }{%
    \ifboolKV[PfCUrne]{Tableau}{%
      \ifboolKV[PfCUrne]{Different}{%
        \edef\PfCFooRepartitionC{\useKV[PfCUrne]{RepartitionColonne}}%
        \edef\PfCFooRepartitionL{\useKV[PfCUrne]{RepartitionLigne}}%
        \setsepchar{,}\ignoreemptyitems%
        \readlist*\ListeRepartitionCAv{\PfCFooRepartitionC}%
        \readlist*\ListeRepartitionLAv{\PfCFooRepartitionL}%
        \reademptyitems%
        % Repartition : \showitems\ListeRepartitionAv[]%
        \edef\PfCFooListeRepartitionC{}%
        \edef\PfCFooListeRepartitionL{}%
        \edef\PfCTotalC{0}%
        \edef\PfCTotalL{0}%
        \xintFor* ##1 in{\xintSeq{1}{\ListeRepartitionCAvlen}}\do{%
          \xintFor* ##2 in{\xintSeq{1}{\ListeRepartitionCAv[##1]}}\do{%
            \edef\PfCFooListeRepartitionC{\PfCFooListeRepartitionC,##1}%
            \edef\PfCTotalC{\fpeval{\PfCTotalC+1}}%
          }%
        }%
        \xintFor* ##1 in{\xintSeq{1}{\ListeRepartitionLAvlen}}\do{%
          \xintFor* ##2 in{\xintSeq{1}{\ListeRepartitionLAv[##1]}}\do{%
            \edef\PfCFooListeRepartitionL{\PfCFooListeRepartitionL,##1}%
            \edef\PfCTotalL{\fpeval{\PfCTotalL+1}}%
          }%
        }%
        \foreachitem\compteur\in\ListeCouleursAv{\expandafter\UpdatetoksUrneColonnes\compteur\nil}%
        \foreachitem\compteur\in\ListeNombresAv{\expandafter\UpdatetoksUrneNombres\compteur\nil}%
        \PfC@BuildTableauDoubleEntreeDifferent{\the\tokUrneListeColonnes}{\the\tokUrneListeNombres}{\PfCFooListeRepartitionC}{\PfCFooListeRepartitionL}%
     }{%
       \edef\PfCFooRepartition{\useKV[PfCUrne]{Repartition}}%
       \setsepchar{,}\ignoreemptyitems%
       \readlist*\ListeRepartitionAv{\PfCFooRepartition}%
       \reademptyitems%
       \edef\PfCFooListeRepartition{}%
       \edef\PfCTotal{0}%
       \xintFor* ##1 in{\xintSeq{1}{\ListeRepartitionAvlen}}\do{%
         \xintFor* ##2 in{\xintSeq{1}{\ListeRepartitionAv[##1]}}\do{%
           \edef\PfCFooListeRepartition{\PfCFooListeRepartition,##1}%
           \edef\PfCTotal{\fpeval{\PfCTotal+1}}%
         }%
       }%
       \ifboolKV[PfCUrne]{Couleurs}{%
         \foreachitem\compteur\in\ListeCouleursAv{\expandafter\UpdatetoksUrneCouleurs\compteur\nil}%
         \PfC@BuildTableauDoubleEntree{\the\tokUrneListeCouleurs}{}{\PfCFooListeRepartition}%
       }{%
         \ifboolKV[PfCUrne]{Nombres}{%
           \foreachitem\compteur\in\ListeNombresAv{\expandafter\UpdatetoksUrneNombres\compteur\nil}%
           \PfC@BuildTableauDoubleEntree{}{\the\tokUrneListeNombres}{\PfCFooListeRepartition}%
         }{}%
       }%
     }%
   }{%
     \ifboolKV[PfCUrne]{Double}{%
       \edef\PfCFooRepartitionC{\useKV[PfCUrne]{RepartitionC}}%
       \edef\PfCFooRepartitionN{\useKV[PfCUrne]{RepartitionN}}%
       \setsepchar{,}\ignoreemptyitems%
       \readlist*\ListeRepartitionCAv{\PfCFooRepartitionC}%
       \readlist*\ListeRepartitionNAv{\PfCFooRepartitionN}%
       % Repartition : \showitems\ListeRepartitionAv[]%
       \reademptyitems%
       \edef\PfCFooListeRepartitionC{}%
       \edef\PfCFooListeRepartitionN{}%
       \edef\PfCTotalC{0}%
       \edef\PfCTotalN{0}%
       \xintFor* ##1 in{\xintSeq{1}{\ListeRepartitionCAvlen}}\do{%
         \xintFor* ##2 in{\xintSeq{1}{\ListeRepartitionCAv[##1]}}\do{%
           \edef\PfCFooListeRepartitionC{\PfCFooListeRepartitionC,##1}%
           \edef\PfCTotalC{\fpeval{\PfCTotalC+1}}%
         }%
       }%
       \xintFor* ##1 in{\xintSeq{1}{\ListeRepartitionNAvlen}}\do{%
         \xintFor* ##2 in{\xintSeq{1}{\ListeRepartitionNAv[##1]}}\do{%
           \edef\PfCFooListeRepartitionN{\PfCFooListeRepartitionN,##1}%
           \edef\PfCTotalN{\fpeval{\PfCTotalN+1}}%
         }%
       }%
       \MelangeListe{\PfCFooListeRepartitionC}{\PfCTotalC}%
       \edef\ListeRepartitionCouleurs{\faa}%
       %Repartition Couleurs : \ListeRepartitionCouleurs\par%
       \foreachitem\compteur\in\ListeCouleursAv{\expandafter\UpdatetoksUrneCouleurs\compteur\nil}%
       %Association : \useKV[PfCUrne]{Association}\par
       \ifboolKV[PfCUrne]{Association}{%
         \edef\ListeRepartitionNombres{\ListeRepartitionCouleurs}%
       }{%
         \MelangeListe{\PfCFooListeRepartitionN}{\PfCTotalN}%
         \edef\ListeRepartitionNombres{\faa}%
       }%
       \foreachitem\compteur\in\ListeNombresAv{\expandafter\UpdatetoksUrneNombres\compteur\nil}%
       %Repartition Nombres : \ListeRepartitionNombres\par%
       \PfC@BuildUrneDouble{\the\tokUrneListeCouleurs}{\the\tokUrneListeNombres}{\ListeRepartitionCouleurs}{\ListeRepartitionNombres}%
     }{%
       \edef\PfCFooRepartition{\useKV[PfCUrne]{Repartition}}%
       \setsepchar{,}\ignoreemptyitems%
       \readlist*\ListeRepartitionAv{\PfCFooRepartition}%
       % Repartition : \showitems\ListeRepartitionAv[]%
       \reademptyitems%
       \edef\PfCFooListeRepartition{}%
       \edef\PfCTotal{0}%
       \xintFor* ##1 in{\xintSeq{1}{\ListeRepartitionAvlen}}\do{%
         \xintFor* ##2 in{\xintSeq{1}{\ListeRepartitionAv[##1]}}\do{%
           \edef\PfCFooListeRepartition{\PfCFooListeRepartition,##1}%
           \edef\PfCTotal{\fpeval{\PfCTotal+1}}%
         }%
       }%
       \ifboolKV[PfCUrne]{Couleurs}{%
         \edef\ListeAvantCouleurs{\useKV[PfCUrne]{ListeCouleurs}}%
         % Couleurs = \ListeAvantCouleurs
         \MelangeListe{\PfCFooListeRepartition}{\PfCTotal}%
         \edef\ListeRepartitionCouleurs{\faa}%
         % \foreachitem\compteur\in\ListeCouleursAv{\expandafter\UpdatetoksUrneCouleurs\compteur\nil}%
         % Couleurs :\\
         % La répartition est : \ListeRepartitionCouleurs\\
         % Les couleurs sont : \the\tokUrneListeCouleurs.\\
         % \BuildUrne{\the\tokUrneListeCouleurs}{}{\ListeRepartitionCouleurs}%
         \PfC@BuildUrnePhysic{\ListeAvantCouleurs}{}{\ListeRepartitionCouleurs}%
       }{%
         \ifboolKV[PfCUrne]{Nombres}{%
           \MelangeListe{\PfCFooListeRepartition}{\PfCTotal}%
           \edef\ListeRepartitionNombres{\faa}%
           \foreachitem\compteur\in\ListeNombresAv{\expandafter\UpdatetoksUrneNombres\compteur\nil}%
%            Nombres :\\
%            La répartition est : \ListeRepartitionNombres\\
%            Les nombres sont : \the\tokUrneListeNombres.\\
           \PfC@BuildUrnePhysic{}{\the\tokUrneListeNombres}{\ListeRepartitionNombres}%
         }{}%
       }%
     }%
   }%
 }%
}%
\makeatother
