28

サッカー(連想サッカー)の試合をシミュレートできるシミュレーションエンジンを構築したいと思います。あなたが私を助けてくれたら素晴らしいと思います。私にとって重要なのは、どのアクションが発生するかを決定することです。各アクションのイベントリスナーは、後で簡単に実装できます。この関数は、ゲームの結果と発生したアクションへのコメントのみをシミュレートする必要があります。2D/3Dグラフィックスは必要ありません。私たちはハットトリックのようなゲームについて話している。


私はあなたが最初に行動を伴う一連の議事録を持っていることを提案します。

$ 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 =攻撃):値が高いほど防御は弱く、攻撃は強くなります
  • プレイの速度(1 =遅い、2 =中、3 =速い):値が高いほどチャンスは高くなりますが、迅速なカウンター攻撃を受けるリスクは高くなります
  • パスの距離(1 =短い、2 =中、3 =長い):値が高いほど、得られる機会は少なくなりますが、より良い機会が得られ、オフサイドになることが多くなります。
  • 変更の作成(1 =安全、2 =中、3 =危険):値が高いほどチャンスは高くなりますが、迅速な反撃を受けるリスクは高くなります
  • 防御のプレッシャー(1 =低、2 =中、3 =高):値が高いほど、カウンター攻撃が速くなります
  • 攻撃性(1 =低、2 =中、3 =高):値が高いほど、ファウルによって阻止される攻撃が多くなります。

戦術設定の統合:

すべての戦術設定には、「1」、「2」、または「3」の値があります。「2」は常にニュートラル/ミディアムです。したがって、値を2で割ります。0.5または1または1.5の比率が得られます。そうすれば、戦術的な影響力を統合するために、チャンスを簡単に増やすことができると思いました。しかし、1つの問題が発生しました。チャンスに2つ以上の戦術値を掛けると、100%より高くなる可能性があります(たとえば、60 x 1.5 x 1.5)。だから私はこのように戦術を統合することはできません。他に何ができますか?


どうもありがとうございます!

アップデート(2014):数年後、GitHubでゲームの完全なコードベースをオープンソースとしてリリースしました。興味のある方は、このファイルでこのシミュレーションの特定の実装を見つけることができます。

4

4 に答える 4

35

「重み」ベースのシミュレーションを構築します (ええ、私はちょうど今その用語を発明しました)。各変数 (そのタイプに関係なく) には「重み」があります。たとえば、プレーヤーには体重があります。良い選手は余分な体重を持っています。怪我をした選手は、体重が少ないか、まったく待機していません (または負の体重ですか?)。

すべての重みを一緒に追加します (サッカーの試合なので、両方のチームの)。その重みは、勝率に似ています。例えば;

チーム Aの体重= 56チーム B の体重 = 120

重量はすでに、一方のチームが他方よりもはるかに優れていることを示しています (重量がどのように確立されたかに関係なく.. 気にする人は非常に丸いボールを持っているかもしれません)。

重みに基づいて、勝率を計算できます。チーム Aの勝率= 32%チーム B の勝率 = 68% .

これで、勝率に影響される試合をシミュレートするアルゴリズムを作成できるようになりました。広告を描画するために、このようなアルゴリズムを一度書きました。私の場合、広告のクリック数が重みでした。重みが大きいほど、広告がアルゴリズムによって選択される可能性が高くなります。

大きな数 (1000 など) を取得してアルゴリズムを作成し、重みのパーセンテージに基づいて、その数の範囲を各広告に割り当てました。この場合、チーム A は 1000の32% の範囲( 0 - 320 ) を取得し、チーム B は 68% の範囲 ( 321 - 1000 ) を取得します。次に、私のアルゴリズムは 0 から 1000 の間の数字を (ランダムに) 描画します。最大の範囲 (したがって最大の勝率) を持つ広告 (またはあなたのチーム) は、アルゴリズムによって選択される可能性が最も高くなりますが、結果は異なる可能性があります。 .

この種のアルゴリズムは、バランスの取れた結果 (ユーザーが独自のチームを作成したり、より優れたプレーヤーを購入したりできる場合) には優れています (完全ではありませんが)。また、イベントにウェイトを追加するだけで、このアルゴリズムによって描かれたゲーム内のイベントを作成することもできます..

そのチーム内の他の重み要因 (連続してプレーした試合数、医療スタッフの能力 (または体重) の程度) に基づいて、チームごとにイベント (チームメイトの負傷など) に重みを追加できます。など)。重み付けを正しく行うと、非常にバランスの取れた (そして簡単に拡張可能な) シミュレーション アルゴリズムが得られます。これは、予測可能 (実際の試合のように) にも、まったく驚くべき (これも、実際の試合のように) にもなります。

更新: 戦術 的影響 戦術的影響に加えて、「どのようにしますか?」という質問を追加したので、詳しく説明します。あなたが現在行っていることは(私が理解しているように)、パーセンテージ(何かが発生する可能性)を取り、それを比率で掛けて、それがより多く/より少なく発生するようにすることです.

ただし、複数の比率を持つことができるため、100% を超える可能性があります。

まず第一に、チームのすべての戦術的アドバンテージに対して、(おそらく) 他のチームにはカウンター アドバンテージがあります。たとえば、チーム A がゴールを決めることに重みを持っている場合、チーム B はゴールを止めることにカウンターウェイトを持っています。この合計がユニバース (100%) です。現在、両方の戦術的利点の重みは、その宇宙の一部、または合計の重みを構成しています (上で説明したように)。

チーム Aが特定の 1 分間にゴールを決める確率が 80%で、チーム B がゴールを止める確率が 20%であるとします (重量システムに基づく)。しかし、チーム B は非常に優れたキーパーを獲得したばかりなので、チーム B 側に戦術的な影響があります。この影響により、イベントの可能性が変化するはずですが、宇宙自体は変化しません! 言い換えれば、合計確率が 100% を超えてしまうべきではありません (ただし、場合によっては、これは必ずしも悪いことではありません)。

したがって、戦術的な影響に基づいてチーム B に重みを追加し、新しい重みに基づいてチャンスを再計算する必要があります。

重み付け

さて、あなたがコメントしたように、重みを割り当てるのは簡単ではありません。プレイヤーの資質を「比較検討」する必要がある場合は、もちろんそうではありません。体重測定とは、選手が「悪い」または「良い」と言うだけではなく、実際にそれらを評価する必要があります (高校のように!)。最高グレードが大きいほど、重み付けシステムの精度が高くなります。

これで、戦術的影響力への重みの割り当てがもう少し簡単になりました。次の影響があるとします。

  • ゴールを止める
  • ゴールを決める
  • 防衛
  • 攻撃

次に、総重量のプールを作成します (たとえば、1000、私はその数が好きです)。これらは、割り当てることができる「戦術ポイント」です。これら 4 つの影響が一致するため、各影響に 250 ポイントを割り当てることができます。この数 (250) は、それぞれの影響力の宇宙です。

チームごとのこれらのポイントの割り当ては、チームの重み係数 (優れたキーパーがいるかどうかなど) によって異なります。

たとえば、キーパーは対戦相手のキーパー (および、キーパーと対戦相手の間にいる人々も同様かもしれませんが、単純にしておきましょう) に対して重さを量ります。チームAのキーパーの体重が全体の80%で、チーム B のキーパーの体重が 20% であるとします。これは、彼らがどれだけ優れているかを評価し、獲得する戦術ポイントに直接関係しています。したがって、チーム A は 250 のストップ ゴール ポイントの 80% を獲得し、チーム B はそれらのポイントの 20% を獲得します。

残りのポイントは均等に割り当てることができます。私の例では、ゴールが止められるかどうかの世界として、キーパーを 2 人だけ取りました。実際には、もっと多くの重み係数が存在する可能性があります (あなたが把握する必要があります)。

それらがすべて分割されたら、戦術的なポイントを使用して試合を行うことができます. 毎分、勝つチャンスを再計算できます。毎分、戦術的な影響を再計算することもできます (別のプレーヤーがフィールドに入る、またはプレーヤーが負傷したなど)。

はい、多くの変数を取得します。しかし、獲得すればするほど、より良い試合ができます。変数 (またはウェイト / カウンター ウェイト) が多ければ多いほど、実際の生活のように感じられます。

于 2009-09-15T13:45:58.510 に答える
2

すべての確率をパーセンテージに変換することをお勧めします。

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のチームに対してゴールを決める可能性が低くなります。プレースメントが常にトリプレット(XYZ)であると仮定すると、防御、パス、スコアリングでどのチームが最高のパフォーマンスを発揮するかを比較するのは非常に簡単です。

簡単な式は次のようになります。

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人少ない)はずです。

于 2009-09-15T14:50:17.113 に答える
0

これが本当のトリックですよね?おそらく、プレイヤーとチームがアクションの成功と確率に影響を与える可能性のある変数について考え始めるでしょう。

プログラム フローは次のようになります。 1. 変数に基づいてどのイベントが発生するかを計算し、ランダム性もそこにあるようにします。 2. イベントの成功率を計算します。

私はあなたがこれとプログラミングを最も確実にあなた自身でしなければならないことを恐れています;)

于 2009-09-15T13:08:43.983 に答える