サッカー(連想サッカー)の試合をシミュレートできるシミュレーションエンジンを構築したいと思います。あなたが私を助けてくれたら素晴らしいと思います。私にとって重要なのは、どのアクションが発生するかを決定することです。各アクションのイベントリスナーは、後で簡単に実装できます。この関数は、ゲームの結果と発生したアクションへのコメントのみをシミュレートする必要があります。 2D/3Dグラフィックスは必要ありません。 Hattrick のようなゲームについて話しています。
私はあなたが最初に行動を伴う一連の議事録を持っていることを提案します。
$ minutes = array(1、3、4、7、11、13、...、90、92);
次に、これらの各分について、攻撃をシミュレートできます。
攻撃側のチームは、前にサイコロで決定されます。$ attacking = mt_Rand(1、2);
ですから、私にとって最も重要なのは攻撃機能です。
私のアプローチを編集するか、サンプルとして使用してください。これを改善するのを手伝ってもらえますか?結果が可能な限り現実的になるように、関数は複雑である必要があります。しかし、高い予測可能性とあまりにもランダムな結果の間の何かを見つける必要があります。この機能を改善したいだけです。
私のアプローチ:
<?php
function Chance_Percent($chance, $universe = 100) {
$chance = abs(intval($chance));
$universe = abs(intval($universe));
if (mt_Rand(1, $universe) <= $chance) {
return true;
}
return false;
}
function simulate_attack($teamname_att, $teamname_def, $strength_att, $strength_def) {
global $minute, $goals, $_POST, $matchReport, $fouls, $yellowCards, $redCards, $offsides, $schuesse, $taktiken;
// input values: attacker's name, defender's name, attacker's strength array, defender's strength array
// players' strength values vary from 0.1 to 9.9
// ADJUSTMENT START
switch ($taktiken[$teamname_att][0]) {
case 1: $strength_att['defenders'] *= 1.1; $strength_att['forwards'] *= 0.9; break;
case 3: $strength_att['defenders'] *= 0.9; $strength_att['forwards'] *= 1.1; break;
}
switch ($taktiken[$teamname_def][0]) {
case 1: $strength_def['defenders'] *= 1.1; $strength_def['forwards'] *= 0.9; break;
case 3: $strength_def['defenders'] *= 0.9; $strength_def['forwards'] *= 1.1; break;
}
// ADJUSTMENT END
$matchReport .= '<p>'.$minute.'\': '.comment($teamname_att, 'attack');
$offense_strength = $strength_att['forwards']/$strength_def['defenders'];
$defense_strength = $strength_def['defenders']/$strength_att['forwards'];
if (Chance_Percent(50*$offense_strength*($taktiken[$teamname_att][2]/2)*($taktiken[$teamname_att][3]/2))) {
// attacking team passes 1st third of opponent's field side
$matchReport .= ' '.comment($teamname_def, 'attack_advance');
if (Chance_Percent(25*($taktiken[$teamname_def][4]/2))) {
// the defending team fouls the attacking team
$fouls[$teamname_def]++;
$matchReport .= ' '.comment($teamname_def, 'attack_advance_foul');
if (Chance_Percent(43)) {
// yellow card for the defending team
// chance is correct for my purpose
$yellowCards[$teamname_def]++;
$matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_yellow');
}
elseif (Chance_Percent(3)) {
// red card for the defending team
// chance is correct for my purpose (only 1.43% because it's an alternative way)
$redCards[$teamname_def]++;
$matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_red');
}
// indirect free kick
// only 58.23% because it's an alternative way
$matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_iFreeKick');
if (Chance_Percent(25)) {
// shot at the goal
$schuesse[$teamname_att]++;
$matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_iFreeKick_shot');
if (Chance_Percent(25)) {
// attacking team scores (6.25% chance)
$goals[$teamname_att]++;
$matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_iFreeKick_shot_score');
}
else {
// defending goalkeeper saves
// only 18.75% because it's an alternative way
$matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_iFreeKick_shot_save');
}
}
else {
// defending team cleares the ball
// only 75% because it's an alternative way
$matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_iFreeKick_clear');
}
}
elseif (Chance_Percent(17)) {
// attacking team is caught offside
// only 4.25% because it's an alternative way
$offsides[$teamname_att]++;
$matchReport .= ' '.comment($teamname_def, 'attack_advance_offside');
}
else {
if (Chance_Percent(25*($taktiken[$teamname_def][5]/2))) {
// the defending team fouls the attacking team
$fouls[$teamname_def]++;
$matchReport .= ' '.comment($teamname_def, 'attack_advance_foul');
if (Chance_Percent(43)) {
// yellow card for the defending team
// chance is correct for my purpose
$yellowCards[$teamname_def]++;
$matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_yellow');
}
elseif (Chance_Percent(3)) {
// red card for the defending team
// chance is correct for my purpose (only 1.43% because it's an alternative way)
$redCards[$teamname_def]++;
$matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_red');
}
if (Chance_Percent(19)) {
// penalty for the attacking team
$schuesse[$teamname_att]++;
$matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_penalty');
if (Chance_Percent(77)) {
// attacking team scores (77% chance according to Wikipedia)
$goals[$teamname_att]++;
$matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_penalty_score');
}
elseif (Chance_Percent(50)) {
// shot misses the goal
// only 11.5% because it's an alternative way
$matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_penalty_miss');
}
else {
// defending goalkeeper saves
// only 11.5% because it's an alternative way
$matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_penalty_save');
}
}
elseif (Chance_Percent(28)) {
// direct free kick
// only 22.68% because it's an alternative way
$matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_dFreeKick');
if (Chance_Percent(33)) {
// shot at the goal
$schuesse[$teamname_att]++;
$matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_dFreeKick_shot');
if (Chance_Percent(33)) {
// attacking team scores (10.89% chance)
$goals[$teamname_att]++;
$matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_dFreeKick_shot_score');
}
else {
// defending goalkeeper saves
$matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_dFreeKick_shot_save');
}
}
else {
// defending team cleares the ball
// only 77% because it's an alternative way
$matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_dFreeKick_clear');
}
}
else {
// indirect free kick
// only 58.23% because it's an alternative way
$matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_iFreeKick');
if (Chance_Percent(25)) {
// shot at the goal
$schuesse[$teamname_att]++;
$matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_iFreeKick_shot');
if (Chance_Percent(25)) {
// attacking team scores (6.25% chance)
$goals[$teamname_att]++;
$matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_iFreeKick_shot_score');
}
else {
// defending goalkeeper saves
// only 18.75% because it's an alternative way
$matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_iFreeKick_shot_save');
}
}
else {
// defending team cleares the ball
// only 75% because it's an alternative way
$matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_iFreeKick_clear');
}
}
}
else {
// attack passes the 2nd third of the opponent's field side - good chance
$matchReport .= ' '.comment($teamname_def, 'attack_advance_advance');
if (Chance_Percent(62*($taktiken[$teamname_att][6]/2)*($taktiken[$teamname_att][7]/2)/($taktiken[$teamname_att][8]/2)*($taktiken[$teamname_att][9]/2)/($taktiken[$teamname_def][10]/2))) {
// shot at the goal
$schuesse[$teamname_att]++;
$matchReport .= ' '.comment($teamname_def, 'attack_advance_advance_shot');
if (Chance_Percent(30*$strength_def['goalkeeper']/7/($taktiken[$teamname_att][11]/2))) {
// the attacking team scores
// only 8.78% because it's an alternative way
// if goalkeeper has strenth 7 then chance is 8.78% otherwise lower/higher
$goals[$teamname_att]++;
$matchReport .= ' '.comment($teamname_def, 'attack_advance_advance_shot_score');
}
else {
if (Chance_Percent(50)) {
// the defending defenders block the shot
$matchReport .= ' '.comment($teamname_def, 'attack_advance_advance_shot_block');
}
else {
// the defending goalkeeper saves
$matchReport .= ' '.comment($teamname_def, 'attack_advance_advance_shot_save');
}
}
}
}
}
}
// attacking team doesn't pass 1st third of opponent's field side
elseif (Chance_Percent(15*$defense_strength*($taktiken[$teamname_att][12]/2)*($taktiken[$teamname_att][13]/2))) {
// quick counter attack - playing on the break
// only 7.5% because it's an alternative way
// if defense has strength 7 then chance is 7.5% otherwise lower/higher
$strength_att['defenders'] = $strength_att['defenders']*0.8; // weaken the current attacking team's defense
$matchReport .= ' '.comment($teamname_def, 'attack_quickCounterAttack');
$matchReport .= ' ['.$goals[$_POST['team1']].':'.$goals[$_POST['team2']].']</p>'; // close comment line
return simulate_attack($teamname_def, $teamname_att, $strength_def, $strength_att); // new attack - this one is finished
}
else {
// ball goes into touch - out of the field
$matchReport .= ' '.comment($teamname_def, 'attack_throwIn');
if (Chance_Percent(33)) {
// if a new chance is created
if (Chance_Percent(50)) {
// throw-in for the attacking team
$matchReport .= ' '.comment($teamname_def, 'attack_throwIn_att');
$matchReport .= ' ['.$goals[$_POST['team1']].':'.$goals[$_POST['team2']].']</p>'; // close comment line
return simulate_attack($teamname_att, $teamname_def, $strength_att, $strength_def); // new attack - this one is finished
}
else {
// throw-in for the defending team
$matchReport .= ' '.comment($teamname_def, 'attack_throwIn_def');
$matchReport .= ' ['.$goals[$_POST['team1']].':'.$goals[$_POST['team2']].']</p>'; // close comment line
return simulate_attack($teamname_def, $teamname_att, $strength_def, $strength_att); // new attack - this one is finished
}
}
}
$matchReport .= ' ['.$goals[$_POST['team1']].':'.$goals[$_POST['team2']].']</p>'; // close comment line
return TRUE; // finish the attack
}
?>
ランダム性に影響を与えるはずの戦術設定:
戦術設定の統合:
すべての戦術設定には、「1」、「2」、または「3」の値があります。 「2」は常にニュートラル/ミディアムです。したがって、値を2で除算します。比率は0.5、1、または1.5になります。そうすれば、戦術的な影響力を統合するために、チャンスを簡単に増やすことができると思いました。しかし、1つの問題が発生しました。チャンスに2つ以上の戦術値を掛けると、100%を超える可能性があります(たとえば、60 x 1.5 x 1.5)。したがって、このように戦術を統合することはできません。他に何ができますか?
どうもありがとうございました!
更新(2014):数年後、私はゲームの完全なコードベースをオープンソースとしてリリースしました GitHubで 。誰かが興味を持っているなら、あなたはこのシミュレーションの特定の実装を見つけるでしょう このファイルで 。
「重み」ベースのシミュレーションを構築します(ええ、私はちょうど今その用語を発明しました)。各変数(タイプに関係なく)には「重み」があります。たとえば、プレーヤーには重みがあります。良い選手は余分な体重があります。怪我をしているプレーヤーは、体重が少ないか、まったく待つ必要がありません(または負の体重ですか?)。
すべての重みを合計します(サッカーの試合であるため、両方のチームの)。その重みは、勝率に似ています。例えば;
チームA = 56の重み、チームB = 12の重み
重みは、一方のチームがもう一方のチームよりもはるかに優れていることをすでに示しています(重みがどのように確立されたかに関係なく..多分彼らは非常に丸いボールを持っています)。
重みに基づいて、勝率を計算できます。 チームA = 32%の勝率、チームB = 68%の勝率。
これで、勝率に影響される一致をシミュレートするアルゴリズムを作成できます。私は広告を描くためにこのようなアルゴリズムを一度書いた。私の場合、広告のクリック数が重みでした。重みが大きいほど、私のアルゴリズムによって広告が選択される可能性が高くなります。
私は、大きな数(1000など)を取得してアルゴリズムを作成し、重みのパーセンテージに基づいて、その数の範囲を各広告に割り当てました。この場合、チームAは1000の32%の範囲を取得します、〜320、チームBは68%の範囲、321〜1000を取得します。次に、私のアルゴリズムは0から1000までの数値を(ランダムに)描画します。範囲が最大(したがって勝率が最大)の広告(またはチーム)は、アルゴリズムによって選択される可能性が最も高くなりますが、結果は異なる可能性があります。 。
この種のアルゴリズムは、バランスの取れた結果(ユーザーが独自のチームを作成したり、より優れたプレーヤーを購入したりできる場合など)に最適です(完全ではありませんが)。イベントに重みを追加するだけで、このアルゴリズムによって描画されたゲーム内のイベントを作成することもできます。
チーム内の他の重み要因(連続してプレイされた試合の数、医療スタッフの質(または重さ))に基づいて、チームごとにイベント(チームメイトの負傷など)に重みを追加できます。など)。重みを正しく行うと、非常にバランスの取れた(そして簡単に拡張できる)シミュレーションアルゴリズムを取得できます。このアルゴリズムは、予測可能(実際の一致のように)またはまったく驚くべき(実際の一致のように)ことができます。
更新:戦術的影響戦術的影響に加えて、「どうしますか?」という質問を追加したので、詳しく説明します。あなたが現在していること(私が理解しているように)は、パーセンテージ(何かが発生する可能性)を取り、それを比率で乗算して、それが多かれ少なかれ発生するようにすることです。
ただし、複数の比率を持つことができるため、100%を超える可能性があります。
まず第一に、チームのすべての戦術的アドバンテージに対して、(おそらく)他のチームにはカウンターアドバンテージがあります。たとえば、チームAが目標を立てるのに重みがある場合、チームBは目標を止めるのにカウンターウェイトがあります。この合計がユニバース(100%)です。これで、両方の戦術上の利点の重みがその宇宙の一部、つまり総重量を構成します(上記で説明したように)。
チームAは80%確実に特定の分にゴールを決め、チームBは20%確実に(ウェイトシステムに基づいて)ゴールを停止するとします。しかし、チームBは非常に優れたキーパーを獲得したばかりなので、チームBの側には戦術的な影響があります。この影響はイベントのチャンスを変えるはずですが、宇宙自体は変えません!言い換えれば、合計で100%を超える可能性があるわけではありません(ただし、場合によっては、これは必ずしも悪いことではありません)。
したがって、戦術的な影響に基づいてチームBに重みを追加してから、新しい重みに基づいてチャンスを再計算する必要があります。
重量の割り当て
さて、あなたがコメントしたように、重みを割り当てるのは簡単ではありません。確かに、プレーヤーの資質を「評価」する必要がある場合はそうではありません。計量とは、プレーヤーが「悪い」または「良い」と言うだけではなく、実際にそれらを採点する必要があります(高校のように!)。最高グレードが大きいほど、重み付けシステムはより正確になります。
これで、戦術的な影響に重みを割り当てるのが少し簡単になりました。次のような影響があるとしましょう。
次に、総重量のプールを作成します(たとえば、1000、その数が好きです)。これらはあなたが割り当てることができる「戦術的なポイント」です。これらの4つの影響が一致するため、各影響に250ポイントを割り当てることができます。この数(250)は、各影響の宇宙です。
チームごとのこれらのポイントの割り当ては、チームの重み要因によって異なります(たとえば、優れたキーパーがいますか?)
たとえば、キーパーは、対戦相手のキーパー(および、キーパーと対戦相手の間にいる人もいる可能性がありますが、単純に保ちましょう)と比較検討します。 チームAのキーパーの体重は80%全体のチームBのキーパーの20%と言います。これは彼らがどれだけ良いかを評価し、それは彼らが得る戦術的なポイントに直接関係しています。したがって、チームAは250の停止ゴールポイントの80%を取得しますそしてチームBは20%を取得しますこれらのポイントの。
残りのポイントは均等に割り当てることができます。私の例では、ゴールが停止するかどうかの宇宙として、2人のキーパーだけを取りました。実際には、(あなたが理解するために)もっと多くの重み要因があるかもしれません。
それらがすべて分割されたら、戦術的なポイントを使用して一致を見つけることができます。 1分ごとに、勝つ可能性を再計算できます。毎分、戦術的な影響を再計算することもできます(たとえば、別のプレーヤーがフィールドに入る、またはプレーヤーが負傷するなど)。
はい、たくさんの変数があります。しかし、あなたが得るほど、より良い試合が行われます。変数(またはウェイト/カウンターウェイト)が多いほど、実際の生活のように感じられます。
複雑になりますが、サッカーの試合をリアルにシミュレートする場合は、さらに多くの変数を使用する必要があります。すべてのチームが攻撃するわけではなく、ディフェンダーがいます。これらのディフェンダーは、相手チームの攻撃の強さを軽減します。
私はこのようなフローをお勧めします:
1)チームAはフィールドの彼らの側にボールを持っています。得点を試みます。 1〜100(0〜99)のテーブルを生成し、次の要素を入力します。チームAのスキルのプレーヤー、反対のプレーヤーの防御能力、ゴールからの距離、疲労の量(ゲームの期間)。このテーブルは次のようになります(単純にするために+1を想像してください。したがって、0-99ではなく1-100):
2)1の場合、もう一度ロールしますが、反対側にいるためのオプションのセットが異なります。 2の偶数で、テーブル上で同じロールを再度作成します。 3つの場合、相手チームに対して同じロールを作成しますが、ゴールに近いため、別のテーブルを使用します。 4の場合、もう一度ロールを行いますが、チームAでプレーヤーの統計をプレーヤー2に変更し、数字がゴールに近いと想定します。 5の場合、ランダムなプレーヤーのスキルに基づいて、相手チームが成功または失敗するテーブルをロールします。 6の場合、即座に相手チームにゴールを与えます(サッカーのゲームでは、これは5%未満の確率で発生し、0.01%のようになりますが、別のテーブルでロールすることもできます。怪我を含む重大な障害、または10秒間愚かに見える)。
3)結果に基づいてプロセスを繰り返します。
コード例をあげることはできますが、基本的な考え方はあると思います。
更新:他の人があなたの方法を使用して重みを考慮する方法に答えたと思います。私の方法は実際には違うでしょう、そして私はここで違いを説明します...
1)計算は基本的に、非常に多くの分ごとにゴールを試みることを前提としています。その時点で、プレーヤーが得点するかどうかをモデル化しようとする一連の複雑な計算があります。私の計算では、ボールは常にプレー中であり、ゴールでの一連の前後のショットと見なされるのではなく、一連の統計に基づいて、考えられる結果のセットから次のセットに移動すると想定します。これは、プレーヤーではなくボールをフォローしているため、概念的に異なり、ボールは、前述の要因によって重み付けされた特定の数の可能性に割り当てられます。
2)物事に重みを付ける方法には複数の重みが含まれ、他の人が説明しているように、特定の量を超える変化の割合が増加します。私のシナリオでは、可能性のある結果が絶対最大100になるようにチャンスをテーブルに分割し、mt_Randを使用して、この結果のセット内の数値をヒットします。これは、ヒットテーブルと呼ばれることがよくあります。または宝くじ。
これを行うには、基本的なチャンスがあり、それらに重みを付けて、成長する余地を与えます。たとえば、ボールが得点する基本的なチャンスが10/100であるとします。誰かが1の場合、これは5.2になり、10.3のままになり、15になります。したがって、ロール0〜14はこれらの値に柔軟に割り当てられ、ヒットテーブルの他の値はそれに対応するようにシフトします。これにより、後でテーブルも拡張する必要があるため、確率の問題が発生しますが、10/100から15/105に移行するときにヒットする可能性が受動的に減少します(他のすべての可能な結果を考慮に入れます)。
すでに開始したパスを続行したい場合は、これらの値をテーブルに入れて、攻撃ごとに計算しない限り、ここで言っていることの大部分は機能しなかったと思います。
現在のネストされたランダムステートメントを使い続けたい場合は、他のソリューションが提供しているソリューションの1つを使用すると思います。幸運を!
すべての確率をパーセンテージに変換することをお勧めします。
function Chance($chance, $universe = 100)
{
$chance = abs(intval($chance));
$universe = abs(intval($universe));
if (mt_Rand(1, $universe) <= $chance)
{
return true;
}
return false;
}
Chance(25); // 25%
Chance(5, 1000); // 0.5%
また、いくつかの確率を他の条件でインスタンス化するだけです。例:
if ($attack === true)
{
if (Chance(15 * $aggressivity) === true)
{
if (Chance(10 * $aggressivity) === true)
{
// red card
}
else
{
// yellow card
}
}
}
編集:私は家にいるだけで、本当に寝る必要がありますが、あなたの編集を一目見ただけで、あなたが興味を持つかもしれないアイデアが浮かびました。 1、2、または3の調整値を使用する代わりに、チームの戦術的な位置を使用しない場合はどうなりますか?たとえば、4-4-2のチームは、3-3-4チームのチームよりも5-3-2チームに対してゴールを決める可能性が低くなります。プレースメントが常にトリプレット(X-Y-Z)であると仮定すると、どのチームが防御、パス、スコアリングで最高のパフォーマンスを発揮するかを比較するのは非常に簡単です。
簡単な式は次のようになります。
A: 4-4-2 (Defending Team)
B: 3-2-5 (Attacking Team)
Bがゴールを決める可能性は(4/5)^ -1 = 0.2 = 20%であり、逆(チームAの得点)は(3/2)^ -1 = 0.5 = 50%です。 PS:これは今はあまり意味がないようですが、午前中にもう一度見てみます。
そして別のこと:レッドカードの後、なぜ障害のあるチームは同じままでいるのですか? IMOが弱くなる(プレイヤーが1人少なくなる)はずです。
これが本当のトリックですね。おそらく、アクションの成功と確率に影響を与える可能性のある、プレーヤーとチームが持つ変数について考え始めます。
プログラムフローは次のようになります。1。変数に基づいて発生するイベントを計算し、そこにもランダム性を持たせます。2。イベントの成功率を計算します。
私はあなたがこれとプログラミングをあなた自身で最も確実に行わなければならないのではないかと心配しています;)