改进足球模拟算法

时间:2009-09-17 14:04:12

标签: php simulation

在另一个问题中,你帮我建立了足球模拟算法。 I got some very good answers there.再次感谢!

现在我编写了这个算法。我想改进它并找到可能存在的小错误。我不想讨论如何解决它 - 正如我们在上一个问题中所做的那样。现在我只想改进它。你能再帮我一次吗?

  1. 有任何错误吗?
  2. 嵌套if子句的结构是否正常?可以改进吗?
  3. 根据我的描述,战术是否正确整合?
  4. 应该对随机性产生影响的战术设置:

    • $ tactics [x] [0]调整(1 =防守,2 =中立,3 =进攻):价值越高,防守越弱,进攻越强
    • $ tactics x游戏速度(1 =慢,2 =中等,3 =快):值越高,机会越多,但获得快速反击的风险越高< / LI>
    • $ tactics x传球距离(1 =短,2 =中,3 =长):值越高越少但获得的机会越多,越位越快
    • $ tactics x创建变化(1 =安全,2 =中等,3 =有风险):值越大,您的机会越多,但获得快速反击的风险越高< / LI>
    • $ 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年):几年后,我现在已经发布了游戏的完整代码库open-source on GitHub。如果有兴趣的话,你会发现这个模拟的具体实现in this file

4 个答案:

答案 0 :(得分: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" ];

您有三个辅助函数,它们都具有以下模式:

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,那么它将只是稍微更快(通常不到十几毫秒,但因为你正在调用该函数一个在递归函数内部进行了六次,每次运行可能会减少十分之几秒。)

我认为这会更好(从读者的角度和

最后,有几次您将使用相同参数对同一函数使用相同的调用。事先打电话:

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

希望这有帮助。

答案 1 :(得分:5)

我(快速)通读它,我发现了一些事情:

  • 发出红色/黄色卡的百分比在所有三分之一的场地中是相同的,这是故意的吗?我不是一个足球运动员,但是我会说这场比赛的最后三分之一比第一场更容易发生。 (因为如果你是第一个,你可能会捍卫)

  • 确定罚分的百分比对于每支球队来说是相同的,但是有些球队,或者更确切地说是球员,比其他球队更有可能获得点球。

  • 你没有考虑角球,犯规后可能造成的伤病,或使用头部进球(这在报告中可能值得一提)。

除此之外,您只需要运行此模拟一次批次,看看您选择的值是否正确;调整算法。最好的办法是手动调整它(例如,从文件中读取所有常量并运行几百个具有不同值和不同团队的模拟),最简单的方法是实现遗传算法来尝试查找更好的价值观。

基本上你所拥有的是真正的游戏玩法/ ai代码,所以你可能想要阅读游戏工作室用来管理这类代码的技术。 (有一点是将变量放在谷歌电子表格中,然后你可以更容易地分享/调整)。

此外,即使你错过了真正的足球比赛所具有的一些东西,也没有必要尽量做到尽可能真实,因为通常在这些情况下提供漂亮的游戏玩法比提供精确的模拟游戏更重要。

答案 2 :(得分:5)

Yous似乎不见了: -

#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;
}

答案 3 :(得分:0)

这些值多久会被检查一次?如果它会被很多人使用并不断递归那些if / else语句,我会发现你占用了大量内存并且运行速度很慢。

也许你可以在那里用几个开关代替一些if?

这就是我所能看到的提速。至于算法本身,如果没有其他人那么我将不得不仔细阅读。