7

別の質問では、サッカーのシミュレーション アルゴリズムの構築を手伝ってくれました。私はそこにいくつかの非常に良い答えを得ました. 再度、感謝します!

これで、このアルゴリズムをコーディングしました。私はそれを改善し、そこにある可能性のある小さな間違いを見つけたいと思っています. 前回の質問で行ったように、解決方法については議論したくありません。今はそれを改善したいだけです。もう一度私を助けてもらえますか?

  1. 間違いはありますか?
  2. ネストされた if 節の構造は大丈夫ですか? 改善できますか?
  3. 私の説明に従って、戦術は正しく統合されていますか?

ランダム性に影響を与える戦術設定:

  • $tactics[x][0] 調整 (1=防御、2=中立、3=攻撃): 値が高いほど防御が弱く、攻撃が強い
  • $tactics xプレーの速さ (1=遅い、2=中程度、3=速い): 値が高いほど機会は多くなりますが、素早い反撃を受けるリスクが高くなります。
  • $tactics xパスの距離 (1 = ショート、2 = ミディアム、3 = ロング): 値が大きいほどチャンスは少なくなりますが、オフサイドになる頻度が高くなります。
  • $tactics x変更の作成 (1 = 安全、2 = 中、3 = 危険): 値が高いほどチャンスは多くなりますが、迅速な反撃を受けるリスクが高くなります。
  • $tactics[x][4] 防御におけるプレッシャー (1=低、2=中、3=高): 値が高いほど、カウンター攻撃が速くなります。
  • $tactics[x][5] 攻撃性 (1=低、2=中、3=高): 値が高いほど、ファウルによって阻止される攻撃が多くなります

注: 戦術 0 と戦術 4 は、エンジンの残りの部分に部分的に統合されており、この機能では必要ありません。

現在のアルゴリズム:

<?php
function tactics_weight($wert) {
    $neuerWert = $wert*0.1+0.8;
    return $neuerWert;
}
function strengths_weight($wert) {
    $neuerWert = log10($wert+1)+0.35;
    return $neuerWert;
}
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, $shots, $tactics;
    // 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
    $matchReport .= '<p>'.$minute.'\': '.comment_action($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*tactics_weight($tactics[$teamname_att][1])/tactics_weight($tactics[$teamname_att][2]))) {
        // attacking team passes 1st third of opponent's field side
        $matchReport .= ' '.comment_action($teamname_def, 'advance');
        if (Chance_Percent(25*tactics_weight($tactics[$teamname_def][5]))) {
            // the defending team fouls the attacking team
            $fouls[$teamname_def]++;
            $matchReport .= ' '.comment_action($teamname_def, 'foul');
            if (Chance_Percent(43)) {
                // yellow card for the defending team
                $yellowCards[$teamname_def]++;
                $matchReport .= ' '.comment_action($teamname_def, 'yellow');
            }
            elseif (Chance_Percent(3)) {
                // red card for the defending team
                $redCards[$teamname_def]++;
                $matchReport .= ' '.comment_action($teamname_def, 'red');
            }
            // indirect free kick
            $matchReport .= ' '.comment_action($teamname_att, 'iFreeKick');
            if (Chance_Percent(25*strengths_weight($strength_att['forwards']))) {
                // shot at the goal
                $shots[$teamname_att]++;
                $matchReport .= ' '.comment_action($teamname_att, 'iFreeKick_shot');
                if (Chance_Percent(25/strengths_weight($strength_def['goalkeeper']))) {
                    // attacking team scores
                    $goals[$teamname_att]++;
                    $matchReport .= ' '.comment_action($teamname_att, 'shot_score');
                }
                else {
                    // defending goalkeeper saves
                    $matchReport .= ' '.comment_action($teamname_def, 'iFreeKick_shot_save');
                }
            }
            else {
                // defending team cleares the ball
                $matchReport .= ' '.comment_action($teamname_def, 'iFreeKick_clear');
            }
        }
        elseif (Chance_Percent(17)*tactics_weight($tactics[$teamname_att][2])) {
            // attacking team is caught offside
            $offsides[$teamname_att]++;
            $matchReport .= ' '.comment_action($teamname_def, 'offside');
        }
        else {
            // attack isn't interrupted
            // attack passes the 2nd third of the opponent's field side - good chance
            $matchReport .= ' '.comment_action($teamname_def, 'advance_further');
            if (Chance_Percent(25*tactics_weight($tactics[$teamname_def][5]))) {
                // the defending team fouls the attacking team
                $fouls[$teamname_def]++;
                $matchReport .= ' '.comment_action($teamname_def, 'foul');
                if (Chance_Percent(43)) {
                    // yellow card for the defending team
                    $yellowCards[$teamname_def]++;
                    $matchReport .= ' '.comment_action($teamname_def, 'yellow');
                }
                elseif (Chance_Percent(3)) {
                    // red card for the defending team
                    $redCards[$teamname_def]++;
                    $matchReport .= ' '.comment_action($teamname_def, 'red');
                }
                if (Chance_Percent(19)) {
                    // penalty for the attacking team
                    $shots[$teamname_att]++;
                    $matchReport .= ' '.comment_action($teamname_att, 'penalty');
                    if (Chance_Percent(77)) {
                        // attacking team scores
                        $goals[$teamname_att]++;
                        $matchReport .= ' '.comment_action($teamname_att, 'shot_score');
                    }
                    elseif (Chance_Percent(50)) {
                        // shot misses the goal
                        $matchReport .= ' '.comment_action($teamname_att, 'penalty_miss');
                    }
                    else {
                        // defending goalkeeper saves
                        $matchReport .= ' '.comment_action($teamname_def, 'penalty_save');
                    }
                }
                else {
                    // direct free kick
                    $matchReport .= ' '.comment_action($teamname_att, 'dFreeKick');
                    if (Chance_Percent(33*strengths_weight($strength_att['forwards']))) {
                        // shot at the goal
                        $shots[$teamname_att]++;
                        $matchReport .= ' '.comment_action($teamname_att, 'dFreeKick_shot');
                        if (Chance_Percent(33/strengths_weight($strength_def['goalkeeper']))) {
                            // attacking team scores
                            $goals[$teamname_att]++;
                            $matchReport .= ' '.comment_action($teamname_att, 'shot_score');
                        }
                        else {
                            // defending goalkeeper saves
                            $matchReport .= ' '.comment_action($teamname_def, 'dFreeKick_shot_save');
                        }
                    }
                    else {
                        // defending team cleares the ball
                        $matchReport .= ' '.comment_action($teamname_def, 'dFreeKick_clear');
                    }
                }
            }
            elseif (Chance_Percent(62*strengths_weight($strength_att['forwards'])*tactics_weight($tactics[$teamname_att][2])*tactics_weight($tactics[$teamname_att][3]))) {
                // shot at the goal
                $shots[$teamname_att]++;
                $matchReport .= ' '.comment_action($teamname_att, 'shot');
                if (Chance_Percent(30/strengths_weight($strength_def['goalkeeper']))) {
                    // the attacking team scores
                    $goals[$teamname_att]++;
                    $matchReport .= ' '.comment_action($teamname_att, 'shot_score');
                }
                else {
                    if (Chance_Percent(50)) {
                        // the defending defenders block the shot
                        $matchReport .= ' '.comment_action($teamname_def, 'shot_block');
                    }
                    else {
                        // the defending goalkeeper saves
                        $matchReport .= ' '.comment_action($teamname_def, 'shot_save');
                    }
                }
            }
            else {
                // attack is stopped
                $matchReport .= ' '.comment_action($teamname_def, 'stopped');
                if (Chance_Percent(15*$defense_strength*tactics_weight($tactics[$teamname_att][1])*tactics_weight($tactics[$teamname_att][3])*tactics_weight($tactics[$teamname_def][4]))) {
                    // quick counter attack - playing on the break
                    $strength_att['defenders'] = $strength_att['defenders']*0.8; // weaken the current attacking team's defense
                    $matchReport .= ' '.comment_action($teamname_def, '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
                }
            }
        }
    }
    // attacking team doesn't pass 1st third of opponent's field side
    elseif (Chance_Percent(15*$defense_strength*tactics_weight($tactics[$teamname_att][1])*tactics_weight($tactics[$teamname_att][3])*tactics_weight($tactics[$teamname_def][4]))) {
        // attack is stopped
        // quick counter attack - playing on the break
        $matchReport .= ' '.comment_action($teamname_def, 'stopped');
        $strength_att['defenders'] = $strength_att['defenders']*0.8; // weaken the current attacking team's defense
        $matchReport .= ' '.comment_action($teamname_def, '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_action($teamname_def, 'throwIn');
        if (Chance_Percent(33)) {
            // if a new chance is created
            if (Chance_Percent(50)) {
                // throw-in for the attacking team
                $matchReport .= ' '.comment_action($teamname_def, '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_action($teamname_def, '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
}

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

4

4 に答える 4

8

一般に、これはかなり複雑な問題のように見えますが、どれだけ効率的に解けるかわかりません。

そうは言っても、私は明らかにあなたを助けるいくつかのものを見てきました.

まず、パラメーターに変数を入力します。これにより、必ずしもコードが高速になるとは限りませんが、読みやすく、デバッグしやすくなります。次に、$teamname_att、$teamname_def パラメーターを削除し、それらを連想配列 $strength_att、$strength_def の値として単純に保持します。いずれにせよ、このデータは常に対になっているため、一方のチームの名前を別のチームへの参照として誤って使用するリスクが軽減されます。

これにより、配列内の値を継続的に検索する必要がなくなります。

// replace all $tactics[$teamname_att] with $attackers
$attackers = $tactics[$teamname_att]; 
$defenders = $tactics[$teamname_def];
// Now do the same with arrays like $_POST[ "team1" ];

すべてパターンを持つ 3 つのヘルパー関数があります。

function foo( $arg ){
    $bar = $arg * $value;
    return $bar;
}

これは、関数を実行するたびに追加の変数 (コストがかかる可能性があるもの) を作成する必要があることを意味するため、代わりにこれらを使用します。

function tactics_weight($wert) {
    return $wert*0.1+0.8;
}

function strengths_weight($wert) {
    return log10($wert+1)+0.35;
}

/*
 Perhaps I missed it, but I never saw Chance_Percent( $num1, $num2 )
 consider using this function instead: (one line instead of four, it also
 functions more intuitively, Chance_Percent is your chance out of 100 
 (or per cent)

 function Chance_Percent( $chance ) {
     return (mt_rand(1, 100) <= $chance);
 }    

*/
function Chance_Percent($chance, $universe = 100) {
    $chance = abs(intval($chance)); // Will you always have a number as $chance?
                                    // consider using only abs( $chance ) here.
    $universe = abs(intval($universe));
    return (mt_rand(1, $universe) <= $chance);
}

私は、このパターンが一貫して出てくることに気がつかずにはいられませんでした:

$matchReport .= ' ' . comment_action($teamname_att, 'attack');

私の一般的な経験では、$matchReport の連結を comment_action に移動すると、わずか速くなります (通常は 12 ミリ秒未満ですが、再帰関数内でその関数を半ダース回呼び出しているため、これにより、1 回の実行でコンマ数秒短縮できます)。

私はこれがより良い流れになると思います(読者の観点からも、

最後に、同じパラメータで同じ関数を同じ呼び出しを使用する場合が数回あります。その呼び出しを前もって行います。

$goalieStrength = strengths_weight($strength_def['goalkeeper']);

お役に立てれば。

于 2009-09-23T21:33:06.760 に答える
5

私はそれを(素早く)読んで、いくつかのことに気付きました:

  • レッド/イエロー カードが配られる割合は、フィールドのすべての 3 分の 1 で同じですが、これは意図的なものですか? 私はサッカー好きではありませんが、攻撃はフィールドの最初よりも最後の 3 分の 1 で発生する可能性が高いと思います。(最初にいる場合は防御している可能性が高いため)

  • ペナルティが与えられたと判断するパーセンテージは各チームで同じですが、一部のチーム、またはプレーヤーは、他のチームよりもペナルティを与える可能性が高くなります。

  • コーナー キック、ファウル後の負傷の可能性、ヘッドを使用して得点したゴール (レポートで言及する価値があるかもしれません) は考慮されていません。

それとは別に、このシミュレーションを何度も実行して、選択した値が正しいかどうかを確認する必要があります。アルゴリズムを微調整します。最善の方法は、手動で調整することです (たとえば、ファイルからすべての定数を読み取り、さまざまな値とさまざまなチームで数百回のシミュレーションを実行します)。最も簡単な方法は、おそらく遺伝的アルゴリズムを実装して試して見つけることです。より良い値。

基本的に、ここにあるのは本物のゲームプレイ/AI コードなので、このタイプのコードを管理するためにゲーム スタジオが使用する手法を読みたいと思うかもしれません。(たとえば、Google スプレッドシートに変数を配置して、共有や調整をより簡単に行うことができます)。

また、実際のサッカーの試合に欠けているものもいくつかありますが、可能な限りリアルにしようとしても意味がありません。一般に、このような場合、正確なシミュレーションを提供することよりも、優れたゲームプレイを提供することが重要になるためです。

于 2009-09-23T21:54:17.840 に答える
5

あなたが行方不明のようです:-

#include oscar.h;
void function dive (int ball_location, int[] opposition, int[] opposition_loc) {
    if (this.location != PenaltyBox || ball_location != PenatlyBox)
       return;
    } else {
       for (x = 0; x < 11; x++) {
           if ( opposition_loc[x] = PenaltyBox ) {
               scream(loudly);
               falldown();
               roll_around();
               cry();
               roll_around();
               scream(patheticaly);
               plead_with_ref();
               return;
            }
     }
     return;
}
于 2009-09-25T01:29:01.857 に答える
0

これらの値はどのくらいの頻度でチェックされますか? 多くの人が使用し、if/else ステートメントを常に再帰的に使用する場合、大量のメモリを消費し、実行速度が非常に遅くなることがわかります。

おそらく、if のいくつかを置き換えるためにそこにいくつかのスイッチを入れることはできますか?

速度の向上について私が見ることができるのはそれだけです。アルゴリズム自体については、他の人がいない場合は、少し後で熟読する必要があります。

于 2009-09-17T14:20:52.133 に答える