<span><span><span class="hljs-meta"><?php</span></span><span>
</span><span><span class="hljs-keyword">echo</span></span><span> <span class="hljs-string"><<<HTML
<!--
Dieser Kommentar、Funktionen und Stile existieren nur zur Demonstration,Hat nichts mit dem Text zu tun。
Wenn Sie nur den Text benötigen,Bitte beginnen Sie von der folgenden horizontalen Linie zu lesen。
-->
<style>
body { font-family: system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial; line-height: 1.65; max-width: 820px; margin: 2rem auto; padding: 0 1rem; }
pre { overflow: auto; padding: .75rem; background: #f6f8fa; border-radius: 6px; }
code { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; }
</style>
<hr>
<h1>mt_srand Wie man Charakterattribute in der Spieleentwicklung zuweist,Zufällige, aber faire Einstellungen erreichen?</h1>
<p><strong>Zusammenfassung</strong>:<code>mt_srand()
HINWEIS : Verwenden Sie Time () nicht, um direkt zu säen. Andernfalls "schrauben Sie" in derselben Sekunde. Rufen Sie MT_Srand () nicht wiederholt in einem Zuweisungsprozess auf - säen Sie es zu Beginn eines Zuweisungsvorgangs einmal.
Szenario: Es gibt 6 Attribute (Kraft, Empfindlichkeit, Intelligenz, physische, Bewegung und Wille), die Gesamtzahl der Punkte wird auf 30 festgelegt, und jedes Element muss sich im Bereich [1,10] befinden.
/**
* Wille totalPoints Schneiden Sie es zufällig gleichmäßig auf n Aktie,满足每Aktie均 ≥ minVal、≤ maxVal,Und die Summe bleibt unverändert。
* Wenn die Einschränkungen zu eng sind, ist es nicht machbar,Automatischer Rollback -Versuch(am meisten retries Zweitklassifiziert)。
*/
function random_partition_constrained(int </span><span><span class="hljs-subst">$n</span></span><span>, int </span><span><span class="hljs-subst">$totalPoints</span></span><span>, int </span><span><span class="hljs-subst">$minVal</span></span><span>, int </span><span><span class="hljs-subst">$maxVal</span></span><span>, int </span><span><span class="hljs-subst">$retries</span></span><span> = 256): array {
for (</span><span><span class="hljs-subst">$t</span></span><span> = 0; </span><span><span class="hljs-subst">$t</span></span><span> < </span><span><span class="hljs-subst">$retries</span></span><span>; </span><span><span class="hljs-subst">$t</span></span><span>++) {
// Ziehen Sie zuerst die untere Grenze ab,Übrig R Freie Zuteilung machen
</span><span><span class="hljs-subst">$R</span></span><span> = </span><span><span class="hljs-subst">$totalPoints</span></span><span> - </span><span><span class="hljs-subst">$n</span></span><span> * </span><span><span class="hljs-subst">$minVal</span></span><span>;
if (</span><span><span class="hljs-subst">$R</span></span><span> < 0) throw new InvalidArgumentException('Die Summe der Untergrenze übersteigt die Gesamtzahl der Punkte');
// erzeugen n-1 indival“Schnittpunkt”,Rechts [0, R] Sogar Schneiden durchführen
</span><span><span class="hljs-subst">$cuts</span></span><span> = [];
for (</span><span><span class="hljs-subst">$i</span></span><span> = 0; </span><span><span class="hljs-subst">$i</span></span><span> < </span><span><span class="hljs-subst">$n</span></span><span> - 1; </span><span><span class="hljs-subst">$i</span></span><span>++) { </span><span><span class="hljs-subst">$cuts</span></span><span>[] = mt_rand(0, </span><span><span class="hljs-subst">$R</span></span><span>); }
sort(</span><span><span class="hljs-subst">$cuts</span></span><span>);
</span><span><span class="hljs-subst">$parts</span></span><span> = [];
</span><span><span class="hljs-subst">$prev</span></span><span> = 0;
foreach (</span><span><span class="hljs-subst">$cuts</span></span><span> as </span><span><span class="hljs-subst">$c</span></span><span>) { </span><span><span class="hljs-subst">$parts</span></span><span>[] = </span><span><span class="hljs-subst">$c</span></span><span> - </span><span><span class="hljs-subst">$prev</span></span><span>; </span><span><span class="hljs-subst">$prev</span></span><span> = </span><span><span class="hljs-subst">$c</span></span><span>; }
</span><span><span class="hljs-subst">$parts</span></span><span>[] = </span><span><span class="hljs-subst">$R</span></span><span> - </span><span><span class="hljs-subst">$prev</span></span><span>;
// Zurück in die untere Grenze hinzufügen,Und überprüfen Sie die Obergrenze
</span><span><span class="hljs-subst">$vals</span></span><span> = array_map(fn(</span><span><span class="hljs-subst">$x</span></span><span>) => </span><span><span class="hljs-subst">$x</span></span><span> + </span><span><span class="hljs-subst">$minVal</span></span><span>, </span><span><span class="hljs-subst">$parts</span></span><span>);
if (max(</span><span><span class="hljs-subst">$vals</span></span><span>) <= </span><span><span class="hljs-subst">$maxVal</span></span><span>) return </span><span><span class="hljs-subst">$vals</span></span><span>;
}
throw new RuntimeException('Trennung nicht unter Einschränkung gefunden,Bitte entspannen Sie die oberen und unteren Grenzen oder erhöhen Sie die Gesamtzahl der Punkte。');
}
// Beispiel:6 Elementeigenschaften,gesamt 30 Punkt,Jeder Artikel [1,10]
</span><span><span class="hljs-subst">$attrs</span></span><span> = random_partition_constrained(n: 6, totalPoints: 30, minVal: 1, maxVal: 10);
// </span><span><span class="hljs-subst">$attrs</span></span><span> Wie [7, 4, 2, 6, 3, 8],gesamt和恒为 30,Und alles innerhalb des Bereichs
Diese Methode hat drei Vorteile: strenge Kontrolle über die Summe , unvoreingenommene Elemente (unter der Prämisse, dass Einschränkungen machbar sind) und die Einfachheit erreicht . Es ist zu beachten, dass die realisierbare Domäne, wenn Maxval zu klein oder zu groß ist, sehr schmal ist, mehrere Resamplings verwendet werden können, um zu treffen.
Wenn verschiedene Attribute unterschiedliche "Gewichte" wollen (zum Beispiel "Glück" ist etwas selten), können Sie zusätzliche "Additionspunkte" nach Gewicht extrahieren. Das Folgende ist ein einfaches und leicht gelesenes segmentiertes Stichprobenschema (streng nach Gewichten ohne Voreingenommenheit):
/**
* Rückgabeindex basierend auf dem Gewichtsarray(Unvoreingenommen)
* @param array<float> </span><span><span class="hljs-subst">$weights</span></span><span> Nicht negativ,Mindestens einer > 0
*/
function weighted_pick(array </span><span><span class="hljs-subst">$weights</span></span><span>): int {
</span><span><span class="hljs-subst">$sum</span></span><span> = array_sum(</span><span><span class="hljs-subst">$weights</span></span><span>);
if (</span><span><span class="hljs-subst">$sum</span></span><span> <= 0) throw new InvalidArgumentException('权重gesamt和必须 > 0');
</span><span><span class="hljs-subst">$r</span></span><span> = mt_rand() / mt_getrandmax() * </span><span><span class="hljs-subst">$sum</span></span><span>; // [0, sum)
</span><span><span class="hljs-subst">$acc</span></span><span> = 0.0;
foreach (</span><span><span class="hljs-subst">$weights</span></span><span> as </span><span><span class="hljs-subst">$i</span></span><span> => </span><span><span class="hljs-subst">$w</span></span><span>) {
</span><span><span class="hljs-subst">$acc</span></span><span> += </span><span><span class="hljs-subst">$w</span></span><span>;
if (</span><span><span class="hljs-subst">$r</span></span><span> < </span><span><span class="hljs-subst">$acc</span></span><span>) return </span><span><span class="hljs-subst">$i</span></span><span>;
}
return array_key_last(</span><span><span class="hljs-subst">$weights</span></span><span>); // Driftschutz
}
// Beispiel:Zufällige Segmentierung geben 6 Elemente hinzufügen zu 3 Punkt“Seltener Bonus”,Gewichtsverzerrung 6 Artikel(Wille)
</span><span><span class="hljs-subst">$weights</span></span><span> = [1,1,1,1,1,2.5];
</span><span><span class="hljs-subst">$bonus</span></span><span> = [0,0,0,0,0,0];
for (</span><span><span class="hljs-subst">$k</span></span><span> = 0; </span><span><span class="hljs-subst">$k</span></span><span> < 3; </span><span><span class="hljs-subst">$k</span></span><span>++) {
</span><span><span class="hljs-subst">$idx</span></span><span> = weighted_pick(</span><span><span class="hljs-subst">$weights</span></span><span>);
</span><span><span class="hljs-subst">$bonus</span></span><span>[</span><span><span class="hljs-subst">$idx</span></span><span>] += 1;
}
Manchmal willst du "meistens gemein, nur wenige Extreme". Verwenden Sie Box -Müller, um die gleichmäßige Verteilung in eine Normalverteilung umzuwandeln und dann in das Intervall einzuschneiden:
// erzeugen ~N(0,1)
function randn(): float {
do {
</span><span><span class="hljs-subst">$u</span></span><span> = mt_rand() / mt_getrandmax();
</span><span><span class="hljs-subst">$v</span></span><span> = mt_rand() / mt_getrandmax();
} while (</span><span><span class="hljs-subst">$u</span></span><span> == 0.0); // vermeiden log(0)
return sqrt(-2.0 * log(</span><span><span class="hljs-subst">$u</span></span><span>)) * cos(2.0 * M_PI * </span><span><span class="hljs-subst">$v</span></span><span>);
}
// existieren [min, max] Generiert auf“Glockenform”verteilt
function randn_clamped(float </span><span><span class="hljs-subst">$min</span></span><span>, float </span><span><span class="hljs-subst">$max</span></span><span>, float </span><span><span class="hljs-subst">$mean</span></span><span>, float </span><span><span class="hljs-subst">$std</span></span><span>): float {
</span><span><span class="hljs-subst">$x</span></span><span> = </span><span><span class="hljs-subst">$mean</span></span><span> + </span><span><span class="hljs-subst">$std</span></span><span> * randn();
return max(</span><span><span class="hljs-subst">$min</span></span><span>, min(</span><span><span class="hljs-subst">$max</span></span><span>, </span><span><span class="hljs-subst">$x</span></span><span>));
}
Methode: Verwenden Sie zunächst zufälliges Schneiden, um "Gesamtmenge Fairness" zu gewährleisten, und fügen Sie zu jedem Attribut (positiver und negativer Offset, die Summe unverändert) eine normale Feinabstimmung zu, um die somatosensorische "meiste Mäßigung und eine kleine Menge prominent" zu formen.
Zum Beispiel nehmen 4 Spieler 4 Sätze von "vorgenerierten" Attributvorlagen, Sie können:
// Fisher–Yates Schrumpfen:Unvoreingenommen
function shuffle_unbiased(array &</span><span><span class="hljs-subst">$arr</span></span><span>): void {
</span><span><span class="hljs-subst">$n</span></span><span> = count(</span><span><span class="hljs-subst">$arr</span></span><span>);
for (</span><span><span class="hljs-subst">$i</span></span><span> = </span><span><span class="hljs-subst">$n</span></span><span> - 1; </span><span><span class="hljs-subst">$i</span></span><span> > 0; </span><span><span class="hljs-subst">$i</span></span><span>--) {
</span><span><span class="hljs-subst">$j</span></span><span> = mt_rand(0, </span><span><span class="hljs-subst">$i</span></span><span>);
[</span><span><span class="hljs-subst">$arr</span></span><span>[</span><span><span class="hljs-subst">$i</span></span><span>], </span><span><span class="hljs-subst">$arr</span></span><span>[</span><span><span class="hljs-subst">$j</span></span><span>]] = [</span><span><span class="hljs-subst">$arr</span></span><span>[</span><span><span class="hljs-subst">$j</span></span><span>], </span><span><span class="hljs-subst">$arr</span></span><span>[</span><span><span class="hljs-subst">$i</span></span><span>]];
}
}
// 预erzeugen模板 + Schrumpfen分配
</span><span><span class="hljs-subst">$seed</span></span><span> = seed_from_context('ROOM-9F2A', 12, 'ALL'); // verwenden ALL Repräsentiert das ganze Spiel
mt_srand(</span><span><span class="hljs-subst">$seed</span></span><span>);
</span><span><span class="hljs-subst">$templates</span></span><span> = [];
for (</span><span><span class="hljs-subst">$t</span></span><span> = 0; </span><span><span class="hljs-subst">$t</span></span><span> < 4; </span><span><span class="hljs-subst">$t</span></span><span>++) {
</span><span><span class="hljs-subst">$templates</span></span><span>[] = random_partition_constrained(6, 30, 1, 10);
}
shuffle_unbiased(</span><span><span class="hljs-subst">$templates</span></span><span>);
// 之后按玩家顺序一人取一indival模板(或verwenden玩家ID再做一Zweitklassifiziert稳定Schrumpfen)
Überprüfen Sie Monte Carlo, bevor Sie online gehen:
// Grobe statistische Mittelwert(Schematisch)
function simulate_means(int </span><span><span class="hljs-subst">$runs</span></span><span> = 100000): array {
</span><span><span class="hljs-subst">$sum</span></span><span> = array_fill(0, 6, 0.0);
for (</span><span><span class="hljs-subst">$i</span></span><span> = 0; </span><span><span class="hljs-subst">$i</span></span><span> < </span><span><span class="hljs-subst">$runs</span></span><span>; </span><span><span class="hljs-subst">$i</span></span><span>++) {
mt_srand(</span><span><span class="hljs-subst">$i</span></span><span>); // Verschiedene Samen
</span><span><span class="hljs-subst">$vals</span></span><span> = random_partition_constrained(6, 30, 1, 10);
for (</span><span><span class="hljs-subst">$k</span></span><span> = 0; </span><span><span class="hljs-subst">$k</span></span><span> < 6; </span><span><span class="hljs-subst">$k</span></span><span>++) { </span><span><span class="hljs-subst">$sum</span></span><span>[</span><span><span class="hljs-subst">$k</span></span><span>] += </span><span><span class="hljs-subst">$vals</span></span><span>[</span><span><span class="hljs-subst">$k</span></span><span>]; }
}
return array_map(fn(</span><span><span class="hljs-subst">$x</span></span><span>) => </span><span><span class="hljs-subst">$x</span></span><span> / </span><span><span class="hljs-subst">$runs</span></span><span>, </span><span><span class="hljs-subst">$sum</span></span><span>);
}
function assign_attributes(string </span><span><span class="hljs-subst">$matchId</span></span><span>, int </span><span><span class="hljs-subst">$season</span></span><span>, string </span><span><span class="hljs-subst">$playerId</span></span><span>): array {
// 1) Aussaat
mt_srand(seed_from_context(</span><span><span class="hljs-subst">$matchId</span></span><span>, </span><span><span class="hljs-subst">$season</span></span><span>, </span><span><span class="hljs-subst">$playerId</span></span><span>, 'attr-v1'));
// 2) Grundsegmentierung:6 Artikel、gesamt 30、Jeder Artikel [1, 10]
</span><span><span class="hljs-subst">$attrs</span></span><span> = random_partition_constrained(6, 30, 1, 10);
// 3) Seltener Bonus:Zuerst bevorzugt 6 Artikel
</span><span><span class="hljs-subst">$weights</span></span><span> = [1,1,1,1,1,2.5];
for (</span><span><span class="hljs-subst">$i</span></span><span> = 0; </span><span><span class="hljs-subst">$i</span></span><span> < 3; </span><span><span class="hljs-subst">$i</span></span><span>++) { </span><span><span class="hljs-subst">$attrs</span></span><span>[weighted_pick(</span><span><span class="hljs-subst">$weights</span></span><span>)] += 1; }
// 4) Zerosum-Feinabstimmung(保持gesamt和不变,Form“Am mittelmäßigsten”)
</span><span><span class="hljs-subst">$mean</span></span><span> = array_sum(</span><span><span class="hljs-subst">$attrs</span></span><span>) / count(</span><span><span class="hljs-subst">$attrs</span></span><span>);
</span><span><span class="hljs-subst">$delta</span></span><span> = 0.0;
for (</span><span><span class="hljs-subst">$k</span></span><span> = 0; </span><span><span class="hljs-subst">$k</span></span><span> < count(</span><span><span class="hljs-subst">$attrs</span></span><span>); </span><span><span class="hljs-subst">$k</span></span><span>++) {
</span><span><span class="hljs-subst">$adj</span></span><span> = (int) round(randn() * 0.6); // Kleine Schwankungen,Einstellbare Standardabweichung
</span><span><span class="hljs-subst">$attrs</span></span><span>[</span><span><span class="hljs-subst">$k</span></span><span>] += </span><span><span class="hljs-subst">$adj</span></span><span>;
</span><span><span class="hljs-subst">$delta</span></span><span> += </span><span><span class="hljs-subst">$adj</span></span><span>;
}
// 抵消gesamt和偏移(Return -Rundungsfehler gleichmäßig)
while (</span><span><span class="hljs-subst">$delta</span></span><span> != 0) {
</span><span><span class="hljs-subst">$idx</span></span><span> = mt_rand(0, count(</span><span><span class="hljs-subst">$attrs</span></span><span>)-1);
if (</span><span><span class="hljs-subst">$delta</span></span><span> > 0 && </span><span><span class="hljs-subst">$attrs</span></span><span>[</span><span><span class="hljs-subst">$idx</span></span><span>] > 1) { </span><span><span class="hljs-subst">$attrs</span></span><span>[</span><span><span class="hljs-subst">$idx</span></span><span>]--; </span><span><span class="hljs-subst">$delta</span></span><span>--; }
elseif (</span><span><span class="hljs-subst">$delta</span></span><span> < 0) { </span><span><span class="hljs-subst">$attrs</span></span><span>[</span><span><span class="hljs-subst">$idx</span></span><span>]++; </span><span><span class="hljs-subst">$delta</span></span><span>++; }
}
// 5) Ernteintervall(Wenn geschnitten,Gleicher Betrag von/向其他Artikel借还,保持gesamt和)
</span><span><span class="hljs-subst">$min</span></span><span> = 1; </span><span><span class="hljs-subst">$max</span></span><span> = 12;
</span><span><span class="hljs-subst">$sumBefore</span></span><span> = array_sum(</span><span><span class="hljs-subst">$attrs</span></span><span>);
</span><span><span class="hljs-subst">$attrs</span></span><span> = array_map(fn(</span><span><span class="hljs-subst">$v</span></span><span>) => max(</span><span><span class="hljs-subst">$min</span></span><span>, min(</span><span><span class="hljs-subst">$max</span></span><span>, </span><span><span class="hljs-subst">$v</span></span><span>)), </span><span><span class="hljs-subst">$attrs</span></span><span>);
</span><span><span class="hljs-subst">$sumAfter</span></span><span> = array_sum(</span><span><span class="hljs-subst">$attrs</span></span><span>);
// Zurückkehren oder wieder auffüllen
</span><span><span class="hljs-subst">$diff</span></span><span> = </span><span><span class="hljs-subst">$sumBefore</span></span><span> - </span><span><span class="hljs-subst">$sumAfter</span></span><span>;
while (</span><span><span class="hljs-subst">$diff</span></span><span> != 0) {
</span><span><span class="hljs-subst">$i</span></span><span> = mt_rand(0, count(</span><span><span class="hljs-subst">$attrs</span></span><span>)-1);
if (</span><span><span class="hljs-subst">$diff</span></span><span> > 0 && </span><span><span class="hljs-subst">$attrs</span></span><span>[</span><span><span class="hljs-subst">$i</span></span><span>] < </span><span><span class="hljs-subst">$max</span></span><span>) { </span><span><span class="hljs-subst">$attrs</span></span><span>[</span><span><span class="hljs-subst">$i</span></span><span>]++; </span><span><span class="hljs-subst">$diff</span></span><span>--; }
elseif (</span><span><span class="hljs-subst">$diff</span></span><span> < 0 && </span><span><span class="hljs-subst">$attrs</span></span><span>[</span><span><span class="hljs-subst">$i</span></span><span>] > </span><span><span class="hljs-subst">$min</span></span><span>) { </span><span><span class="hljs-subst">$attrs</span></span><span>[</span><span><span class="hljs-subst">$i</span></span><span>]--; </span><span><span class="hljs-subst">$diff</span></span><span>++; }
}
return </span><span><span class="hljs-subst">$attrs</span></span><span>;
}
Das Binden des "Samens" von mt_srand () mit dem Spielkontext kann zu reproduzierbarem Pseudo-Random führen; Mit zufälliger Schnitt, Gewichtsabtastung und Feinabstimmung mit Null-Sum und anderen Methoden kann eine zufällige, aber faire Attributallokation auf der Prämisse der erfüllenden Einschränkungen aufgebaut werden. Wenn es sich um Value -Spiele oder starke Konfrontationsszenarien handelt, sollten Sie auf zufällige Quellen wie Random_int () umstellen und "Algorithmus Version + Seed + Input" aufnehmen, um Beweise für die Handhabung und Anzeige von Streitigkeiten zu liefern.
Html;