凉凉 具体的代码实现可能如下:

MMA Notebook 的链接 (建议把 Notebook 下载到本地使用, 因为在线的速度好像有点慢), 或者你也可以直接用下面的纯代码:
ClearAll[makeUrinalSeats];
makeUrinalSeats::usage = "创建一个数据结构用来储存当前的如厕状态
+ stat -> List[Real] 值在 0-1 中取值, 表示每个坑位剩余的如厕时间;
+ wait -> Integer 表示正在排队的人数";
makeUrinalSeats :=
Function[{seats}, <|"stat" -> Table[0, seats], "wait" -> 0|>];
plotUrinalSeats[urinalSeats_, w_] :=
Grid[{
{"Waiting: " <> ToString[urinalSeats["wait"]]},
{Grid[{
Graphics[{
Blend[{White, RGBColor[0.3, 0.5, 0.99]}, #],
Disk[{0, 0}, 0.5],
Black,
Style[
Text[ToString[Round[#, 0.01]]],
Larger
]},
ImageSize -> w] & /@
urinalSeats["stat"]},
Frame -> All]}
}];
plotUrinalSeats[urinalSeats_] := plotUrinalSeats[urinalSeats, 30];
ClearAll[urinalSeatsEnergies];
urinalSeatsEnergies::usage = "返回 UrinalSeats 每个位置上能量
\!\(\*SubscriptBox[\(E\), \(i\)]\) = \!\(\*SubscriptBox[\(w\), \(Left\
\)]\)*\!\(\*SubscriptBox[\(s\), \(i - 1\)]\) + \!\(\*SubscriptBox[\(w\
\), \(Middle\)]\)*\!\(\*SubscriptBox[\(s\), \(i\)]\) + \
\!\(\*SubscriptBox[\(w\), \(Right\)]\)*\!\(\*SubscriptBox[\(s\), \(i \
+ 1\)]\) + \!\(\*SubscriptBox[\(w\), \
\(Boundary\)]\)*boundary[\!\(\*SubscriptBox[\(s\), \(i\)]\)] + \
\!\(\*SubscriptBox[\(w\), \(Waiting\)]\)*\!\(\*SubscriptBox[\(n\), \
\(Wait\)]\)
+ wMiddle 默认 999 (也不是没有概率嘛... )
+ wLeft, wRight, wBoundary 默认为 5
+ wWaiting 默认为 -5";
urinalSeatsEnergies[urinalSeats_, wLeft_, wMiddle_, wRight_,
wBoundary_, wWaiting_] :=
Module[{
stat = Ceiling /@ urinalSeats["stat"],
wait = urinalSeats["wait"]
},
Module[{energyWithin =
MapThread[(#1*wLeft + #2*wMiddle + #3*wRight) &,
{stat[[1 ;; -3]], RotateLeft[stat][[1 ;; -3]],
RotateLeft[stat, 2][[1 ;; -3]]}]},
(wWaiting*wait + #) & /@ Flatten@List[
wBoundary + wMiddle*stat[[1]] + wRight*stat[[2]],
energyWithin,
wBoundary + wLeft*stat[[-2]] + wMiddle*stat[[-1]]]]];
urinalSeatsEnergies[urinalSeats_] :=
urinalSeatsEnergies[urinalSeats, 10, 100, 10, 1, -5];
plotUrinalSeatsPossibility[urinalSeats_, w_] := Grid[
{
{Grid[{
Graphics[{
Blend[{RGBColor[0.91, 0.12, 0.29],
RGBColor[0.65, 0.9, 0.41]}, #],
Disk[{0, 0}, 0.5],
Black,
Style[
Text[ToString[Round[#, 0.01]]],
Larger
]},
ImageSize -> w] & /@
(Exp[-#] & /@ (urinalSeatsEnergies[urinalSeats]))
},
Frame -> All]}
}];
plotUrinalSeatsPossibility[urinalSeats_] :=
plotUrinalSeatsPossibility[urinalSeats, 30];
ClearAll[luckP];
luckP::usage = "根据概率返回 True 或 False";
luckP = Function[{p}, RandomReal[] < p];
ClearAll[pickFromEneriesList];
pickFromEneriesList::usage = "从能量列表中计算概率然后选择可以填充的位置
返回一个 概率权重 -> 可能填充位置";
pickFromEneriesList = Function[{energyList},
Reap[MapIndexed[
If[luckP[Exp[-#1]],
Sow[Exp[-#1], weight];
Sow[#2[[1]], index];] &,
energyList],
_, #2 &][[2]]];
ClearAll[urinalSeatsAdd];
urinalSeatsAdd::usage = "往 stat 中添加一个座位
返回一个新的添加后的 urinalSeat
+ 若失败, 则 wait + 1
+ 若成功, 则 stat 修改";
urinalSeatsAdd[urinalSeat_] :=
Module[{
stat = urinalSeat["stat"],
wait = urinalSeat["wait"],
pick = pickFromEneriesList@urinalSeatsEnergies[urinalSeat],
pos
},
If[Length[pick] == 0,
<|"stat" -> stat, "wait" -> wait + 1|>,
pos = RandomChoice[pick[[1]] -> pick[[2]]];
stat[[pos]] = stat[[pos]] + 1;
<|"stat" -> stat, "wait" -> wait|>]];
ClearAll[urinalSeatsMCStep];
urinalSeatsMCStep::usage = "对输入的 urinalSeats 进行一次蒙卡模拟的 step
返回下一时刻的 urinalSeats
+ dt 为间隔时间
+ t0 为平均蓄力时间
单次 step 进行:
+ 对 stat 中的所有值: x -> Max[x - dt, 0];
+ 按照 P(dt/t0) 增加 wait;
+ 若 wait > 0, 则尝试找一个坑位, wait - 1;
+ 若找不到坑位, wait 不变; ";
urinalSeatsMCStep[urinalSeats_, dt_, t0_] :=
Module[{
stat = Max[# - dt, 0] & /@ urinalSeats["stat"],
wait = urinalSeats["wait"],
urinalSeat
},
If[wait > 0,
urinalSeat = urinalSeatsAdd[<|"stat" -> stat, "wait" -> wait - 1|>],
urinalSeat = <|"stat" -> stat, "wait" -> wait|>];
If[luckP[dt/t0],
urinalSeatsAdd[urinalSeat],
urinalSeat]];
Module[{urinalSeat = makeUrinalSeats[4]},
Manipulate[
Grid[{
{
"stat",
Dynamic[plotUrinalSeats[urinalSeat]],
Button["步进", urinalSeat = urinalSeatsMCStep[urinalSeat, dt, t0]]
},
{
"possibility",
Dynamic[plotUrinalSeatsPossibility[urinalSeat]],
Button["雅座一位", urinalSeat = urinalSeatsAdd[urinalSeat]]
}
}],
{{dt, 0.1}, 0.01, 0.5},
{{t0, 1}, 0.01, 2}]]