7

在另一个问题中,您帮助我构建了一个足球模拟算法。我在那里得到了一些很好的答案。再次感谢!

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

  1. 有没有错误?
  2. 嵌套 if 子句的结构是否正常?可以改进吗?
  3. 战术是否按照我的描述正确整合?

应该对随机性产生影响的战术设置:

  • $tactics[x][0] 调整(1=防守,2=中立,3=进攻):数值越高防守越弱,进攻越强
  • $tactics x speed of play (1=slow, 2=medium, 3=fast):数值越高,机会越大,但获得快速反击的风险越高
  • $tactics x传球距离(1=短,2=中,3=长):数值越高,你获得的机会越少但越位越好,越位越位
  • $tactics x创建变更(1=安全,2=中等,3=有风险):值越高,您的机会就越好,但获得快速反击的风险越高
  • $tactics[x][4] 防守压力(1=低,2=中,3=高):数值越高,反击越快
  • $tactics[x][5] aggressivity (1=low, 2=medium, 3=high):数值越高,越多的攻击你会被犯规阻止

注意: 策略 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" ];

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

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']);

希望这可以帮助。

于 2009-09-23T21:33:06.760 回答
5

我(很快)通读了一遍,发现了几件事:

  • 场上三分之二的红/黄牌出牌率都是一样的,这是故意的吗?我不是足球运动员,但我想说的是进攻更容易发生在球场的最后三分之一,而不是第一场。(因为如果你是第一个,你很可能会防守)

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

  • 您没有考虑角球、犯规后可能的受伤或使用头部得分的进球(这可能值得在报告中提及)。

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

基本上,您在这里拥有的是真正的游戏/人工智能代码,因此您可能想了解游戏工作室用于管理此类代码的技术。(一件事是将变量放在谷歌电子表格中,然后您可以更轻松地共享/调整,例如)。

此外,即使您遗漏了一些真实足球比赛所具有的东西,尝试尽可能逼真也没有意义,因为通常在这些情况下,提供出色的游戏玩法比提供准确的模拟更重要。

于 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 回答