足球比赛模拟

发布于 2024-08-04 17:36:59 字数 13991 浏览 11 评论 0 原文

我想构建一个可以模拟足球(英式足球)比赛的模拟引擎。如果你能帮助我那就太好了。对我来说重要的是决定采取哪些行动。每个操作的事件侦听器可以在以后轻松实现。该功能应该只模拟游戏结果和对发生的动作的评论。不需要 2D/3D 图形。我们正在谈论像 Hattrick 这样的游戏。


我建议你首先有一系列的时间来采取行动。

$分钟 = 数组(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。我想我可以轻松地乘以这个机会来整合战术影响力。但一个问题已经出现:如果我将一个机会乘以 2 或更多战术值,它可能会高于 100%(例如 60 x 1.5 x 1.5)。所以我不能这样整合战术。我还能做什么?


非常感谢!

更新(2014):几年后,我现在将游戏的完整代码库作为开源发布GitHub 上。您将在此文件中找到此模拟的具体实现,如果有人感兴趣的话。

I would like to build a simulation engine which can simulate a soccer (association football) match. It would be cool great if you could help me. What is important to me is to decide which actions happen. The event listeners for each action can be implemented later easily. The function should only simulate the game results and comments to happening actions. There is no 2D/3D graphics needed. We're talking about games like Hattrick.


I would propose that you have an array of minutes with actions at first.

$minutes = array(1, 3, 4, 7, 11, 13, ..., 90, 92);

For each of these minutes, you could then simulate an attack.

The attacking team is determined by dice before: $attacking = mt_rand(1, 2);

So the part which is most important to me is the attack function.

Please edit my approach or use it as a sample. Can you help me to improve this? The function should be complex so that the results are as realistic as possible. But you need to find something between high predictability and too random results. I only want to improve this function.

My approach:

<?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
}
?>

Tactical settings which should have an influence on the randomness:

  • adjustment (1=defensive, 2=neutral, 3=offensive): the higher the value is the weaker is the defense and the stronger is the offense
  • speed of play (1=slow, 2=medium, 3=fast): the higher the value is the better are the opportunities but the higher is the risk of getting a quick counter attack
  • distance of passes (1=short, 2=medium, 3=long): the higher the value is the less but better opportunities you get and the more often you are offside
  • creation of changes (1=safe, 2=medium, 3=risky): the higher the value is the better are your opportunities but the higher is the risk of getting a quick counter attack
  • pressure in defense (1=low, 2=medium, 3=high): the higher the value is the more quick counter attacks you will have
  • aggressivity (1=low, 2=medium, 3=high): the higher the value is the more attacks you will stop by fouls

Integration of the tactical settings:

All the tactical settings have a value which can be "1", "2" or "3". "2" is always neutral/medium. So I divide the values by 2. I get a ratio which is 0.5 or 1 or 1.5. I thought that I could then easily multiply the chances by this in order to integrate tactical influence. But one problem has evolved: If I multiply a chance by 2 or more tactical values, it can be higher than 100% (60 x 1.5 x 1.5 for example). So I can't integrate the tactics this way. What else can I do?


Thank you very much!

Update (2014): A few years later, I have now released the full code base of the game as open-source on GitHub. You'll find the specific implementation of this simulation in this file, if anyone is interested.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

橘虞初梦 2024-08-11 17:36:59

构建一个基于“重量”的模拟(是的,我刚刚发明了这个术语)。每个变量(无论其类型如何)都有一个“权重”。例如,球员有体重。一个好的球员有额外的重量。受伤的球员体重减轻,甚至根本不需要等待(或者可能是负体重?)。

您将所有重量加在一起(两支球队的重量,因为这是一场足球比赛)。该权重类似于获胜机会百分比。例如;

A队的权重 = 56B队的权重 = 120

权重已经表明一支球队要好得多(无论权重是如何确定的..也许他们的球非常圆,谁在乎呢)比另一个。

根据重量,可以计算出中奖机会;
A队获胜几率 = 32%B队获胜几率 = 68%

现在您可以编写一个算法来模拟比赛,并受获胜百分比的影响。我曾经写过一个这样的算法来绘制广告。就我而言,广告的点击次数就是权重。权重越大,广告被我的算法选中的机会就越大。

我通过取一个大数字(例如 1000)来编写算法,然后根据权重百分比为每个广告分配该数字的范围。在本例中,A 队的范围为 1000 的 32%即 0 - 320,B 队的范围为 68%,即 321 - 1000。然后我的算法会(随机)抽取 0 到 1000 之间的数字。范围最大(因此获胜机会最大)的广告(或您的团队)最有可能被算法选中,尽管结果可能不同。

这种算法对于平衡结果来说非常好(尽管并不完美)(如果用户可以创建自己的球队,购买更好的球员等)。您还可以通过此算法绘制游戏中的任何事件,只需为事件添加权重即可。

您可以根据其他事件为每个团队添加事件权重(例如队友受伤)该队内的体重因素(连续打了多少场比赛,他们的医务人员有多好(或有多重),等等)。如果权重做得正确,您可以获得一个非常平衡(且易于扩展)的模拟算法,该算法既可以是可预测的(就像现实生活中的某些比赛),也可以完全令人惊讶(同样,就像现实生活中的比赛一样)。

更新:
战术影响
你添加了战术影响,再加上“你会怎么做?”的问题,所以我会详细说明。你目前正在做的(据我所知)是你取一个百分比(某事发生的机会)并将其乘以一个比率,这样它就会发生更多/更少。

然而,因为您可以有多个比率,所以您最终的机会超过 100%。

首先,对于一支球队的每一个战术优势,另一支球队(可能)都会有反击优势。例如,如果 A 队在进球方面具有权重,那么 B 队在阻止进球方面具有平衡权重。这个总和就是宇宙(100%)。现在,这两种战术优势的权重构成了该宇宙的一部分,或总权重(正如我上面所解释的)。

假设在某一分钟内,A 队有 80% 的把握进球,B 队有 20% 的把握阻止进球(基于权重系统)。但是,由于B队刚刚获得了一名非常优秀的门将,所以对B队来说是有战术上的影响的。这种影响力应该会改变事件发生的机会,但不会改变宇宙本身!换句话说,您最终的总机会不应该超过 100%(尽管在某些情况下,这不一定是坏事)

因此,您应该为 B 队增加权重 ,根据战术影响,然后根据新的权重重新计算机会。

分配权重

现在,就像您评论的那样,分配权重并不容易。如果你必须根据球员的素质来“衡量”他们,那当然不是。衡量不仅仅是说一个球员是“坏”或“好”,你必须真正给他们评分(就像在高中一样!)。最高等级越大,称重系统越准确。

现在,为战术影响分配权重变得更容易了。假设你有以下影响;

  • 阻止进球
  • 进球
  • 防守
  • 进攻

现在,创建一个总重量池(比如说 1000,我喜欢这个数字)。这些是您可以分配的“战术点”。这四种影响力相匹配,因此您可以为每种影响力分配 250 分。这个数字(250)是每个势力的宇宙。

每支球队的这些分数的分配取决于球队的权重因素(例如,他们是否有一个好的守门员?)

例如,守门员会与对手的守门员(也可能是介于守门员和守门员之间的人)进行权衡。对手,但让我们保持简单)。假设A 队的守门员占总体重的 80%B 队的守门员占总体重的 20%。这对他们的表现进行了评价,这与他们获得的战术分数直接相关。因此,A 队获得 250 个阻止进球得分中的 80%B 队获得其中的 20%

其余的分数可以平均分配。在我的例子中,我只选择了两名守门员作为进球是否被阻止的范围。实际上,可能还有更多的权重因素(供您计算)。

一旦他们全部分开,你就可以使用战术点来决定比赛。每分钟你都可以重新计算获胜的机会。每分钟,您还可以重新计算战术影响(例如另一名球员进入场地,或者一名球员受伤)。

是的,你会得到很多变量。但你得到的越多,比赛就越好。变量(或权重/配重)越多,感觉就越像现实生活。

Build a 'weight'-based-simulation (Yeah, I just now invented that term). Each variable (regardless of its type) has a 'weight'. For example, players have weights. A good player has extra weight. A player with an injury has less weight or even no wait at all (or maybe negative weight?).

You add all the weight together (of both teams, because it is a soccer match). That weight resembles a winning chance percentage. For example;

The weight of Team A = 56, the weight of Team B = 120

The weight already shows that one team is much better (regardless of how the weight was established .. maybe they have very round balls, who cares) than the other.

Based on the weight, you could calculate a winning chance;
The winning chance of Team A = 32%, The winning chance of Team B = 68%.

Now you could write an algorithm that simulates a match, influenced by the winning percentage. I wrote an algorithm like this once to draw advertisements. In my case, the number of clicks an advertisement had was the weight. The bigger the weight, the more chance the advertisement was picked by my algorithm.

I wrote the algorithm by taking a large number (like, 1000) and then assigned a range of that number to each advertisement, based on the weight percentage. In this case, Team A gets a range of 32% of 1000, which is 0 - 320, Team B gets a range of 68% which is 321 - 1000. Then my algorithm would draw a number (randomly) between 0 and 1000. The advertisement (or your teams) with the largest range (and thus largest winning chance) has the most chance of being picked by the algorithm, although it could turn out differently.

This kind of algorithm is great (although not perfect) for a balanced outcome (if users could create their own teams, buy better players, etc). You could also make any events within the game drawn by this algorithm, simply by adding a weight to the event as well..

You could add weight to an event (for example the injury of a team mate), per team, based on other weight factors within that team (how many matches played in a row, how good is (or how much weighs) their medic staff, etc). If you do the weight thing right, you could get a very balanced (and easily expandable) simulation algorithm that can both be predictable (just like some matches in real life) or totally surprising (again, just like a real life match).

UPDATE:
Tactical Influences
You added tactical influences, plus the question 'how would you do it?', so I will elaborate. What you are currently doing (as I understand it) is you take a percentage (the chance something occurs) and multiply that with a ratio, so that it will occur more/less.

However, because you can have multiple ratio's, you end up with a chance more then 100%.

First of all, for every tactical advantage of a team, there is (probably) a counter advantage on the other team. For example, if Team A has a weight in making goals, Team B has a counter weight in stopping goals. This sum is the universe (100%). Now the weight of both tactical advantages makes up a piece of that universe, or total weight (as I explained above).

Say that Team A is 80% certain of scoring a goal, in a certain minute, and Team B is 20% certain of stopping it (based on the weight system). But, because Team B just acquired a very good keeper, there is a tactical influence on Team B's side. This influence should shift the chance of an event, but not the universe itself! In other words, you shouldn't end up with a total chance of more then 100% (although in some cases, this isn't necessarily a bad thing)

So, you should add weight to Team B, based on the tactical influence and then re-calculate the chances based on the new weights.

Assigning Weight

Now, like you commented, assigning weight isn't easy. Certainly not if you have to 'weigh' players on their qualities. Weighing is about more then just saying that a player is 'bad' or 'good', you have to actually grade them (like in high school!). The bigger the highest grade, the more accurate the weighting system is.

Now, assigning weights to tactical influences is a bit more easier. Say that you have the following influences;

  • Stopping goals
  • Scoring goals
  • Defence
  • Attack

Now, create a pool of total weight (say, 1000, I like that number). These are 'tactical points' you could assign. These four influences make up a match, so you could assign 250 points to each influence. This number (250) is the universe of each influence.

The assignment of these points, per team, depends on the team's weight factors (like, do they have a good keeper?)

A keeper, for instance, weighs against the opponents keeper (and maybe also the people that are in between the keeper and the opponent, but let's keep it simple). Say the keeper of Team A weighs 80% of the total, and the keeper of Team B 20%. This rates how good they are, which is directly related to the tactical points they get. So Team A gets 80% of 250 stopping-goals-points and Team B gets 20% of those points.

The rest of the points can be assigned equally. In my example, I took only two keepers as the universe of wether a goal gets stopped or not. In reality, there could be a lot more weight factors (for you to figure out).

Once they are all divided, you can use the tactical points to make out the match. For each minute you could re-calculate the chance of winning. Each minute, you could also re-calculate the tactical influences (say another player enters the field, or a player is injured).

Yes, you will get a LOT of variables. But the more you get, the better a match plays. The more variables (or weights / counter weights) the more it feels like real life.

不必你懂 2024-08-11 17:36:59

嗯,这会很复杂,但如果你想真实地模拟一场足球比赛,你将需要更多的变量来发挥作用。并不是所有的球队都会进攻,你会有防守者,而这些防守者会削弱对方球队的进攻强度。

我推荐的流程更像是这样的:

1)A 队将球放在他们这边的场地上。它将尝试得分。生成一个从 1-100 (0-99) 的表格,并填充以下因素:A 队球员的技能、对方球员的防守能力、距球门的距离、疲劳程度(比赛持续时间)。该表看起来像这样(想象一下+1以使其更简单,因此1-100而不是0-99):

  1. 1-50:球员成功推进球
  2. 51-60:球员未能推进球但保持控球权
  3. 61-73:球员未能推进球并失去控球权
  4. 74-82:球员将球传给远前场的另一位进攻者
  5. 83-95:球员失去球权,敌人试图得分
  6. 95-100:严重失败:球员失去控球权并立即让对方进球

2) 如果是 1,则再次滚动,但现在有一组不同的选项可供对方选择。在2的偶数中,在桌子上再次制作相同的卷。如果是三人,则为对方球队进行相同的掷骰,但使用不同的桌子,因为他们更接近球门。如果是 4,则再次进行掷骰,但将玩家的统计数据更改为 A 队的玩家 2,并假设数字更接近目标。如果是 5,则根据随机玩家的技能滚动一张表,敌方队伍要么成功,要么失败。如果是 6 球,则立即给对方进球(在足球比赛中,这种情况发生的概率不到 5%,更像是 0.01%,但您也可以在另一张桌子上滚动)严重故障,包括受伤或看起来愚蠢十秒钟)。

3) 根据结果重复该过程。

我可以给你代码示例,但我认为你已经有了基本的想法。

更新:我认为其他人已经回答了如何使用您的方法来考虑权重。我的方法实际上会有所不同,我将在这里解释这些差异...

1)您的计算基本上假设每隔几分钟就尝试一次目标,此时有一组复杂的计算试图对目标进行建模球员得分或不得分的机会。我的计算假设球一直在比赛中,并根据一系列统计数据从一组可能的结果移动到下一组,而不是被视为一系列来回射门。这在概念上是不同的,因为它跟随球而不是球员,并且球将被分配给由上述因素加权的一定数量的可能性。

2)对事物进行加权的方法涉及多个权重,正如其他人所描述的,这会增加一定数量的百分比变化。在我的场景中,您将机会分解为一个表,以便绝对最多只有 100 个可能的结果,然后使用 mt_rand 命中这组结果中的一个数字,这通常称为命中表或彩票。

为了做到这一点,你需要有基本的机会,然后权衡它们,这给你成长的空间。例如,假设球得分的基本机会是 10/100。如果某人是 1,则变为 5。2,保持 10。3,变为 15。因此,现在,将 0-14 卷灵活分配给这些值,命中表中的其他值将进行调整以适应。这会在稍后带来概率问题,因为假设您也应该扩大表格,但这会被动地减少击中的机会,因为您会从 10/100 变为 15/105(考虑到所有其他可能的结果)。

如果您想继续沿着已经开始的道路前进,我认为我在这里所说的大部分内容都是行不通的,除非您只是将这些值放入表中并像您已经做的那样在每次攻击时计算它们。

如果您想坚持使用当前的嵌套随机语句,我会说采用其他人提供的解决方案之一。祝你好运!

Well it'll be complex, but if you want to realistically simulate a soccer match you'll need a lot more variables put into play. Not all of your team is going to be attacking, you'll have defenders, and those defenders will mitigate the strength of the opposing team's attack.

I'd recommend a flow something more like this :

1) Team A has the ball on their side of the field. It will attempt to score. Generate a table from 1-100 (0-99) and populate it with the following factors : Player from team A's skill, Opposing Player's defensive capability, distance from goal, amount of fatigue (duration of game). This table will look something like this (imagine +1 to make it simpler, so 1-100 not 0-99) :

  1. 1-50 : Player successfully advances the ball
  2. 51-60 : Player fails to advance the ball but maintains possession
  3. 61-73 : Player fails to advance the ball and loses possession
  4. 74-82 : Player passes the ball far upfield to another attacker
  5. 83-95 : Player loses possession of the ball and the enemy attempts to score
  6. 95-100 : Critical failure : The player loses possession of the ball and instantly yields a goal to the opposing team

2) In the event of 1, roll again, but now have a different set of options for being on the opposing side. In the even of 2, make the same roll on the table again. In the event of three, make the same rolls for the opposing team, but use a different table as they're closer to the goal. In the event of 4, make the rolls again but change the player's statistics to Player 2 on Team A, and assume numbers being closer to the goal. In the event of 5, roll a table where the opposing team either succeeds or fails based on the skill of a random player. In the event of six, instantly give a goal to the opposing team (in the game of soccer this happens way less than 5% of the time, it'd be more like .01%, but you could also roll on another table of critical failures that include injury, or looking stupid for ten seconds).

3) Repeat the process based on the results.

I could give you code examples, but I think you have the basic idea.

UPDATE: I think the others have answered how to factor in the weights using your method. My method would actually be different, and I'll explain the differences here...

1) Your calculations are basically assuming an attempt on goal every so many minutes, and at that point there is a complex set of calculations that attempt to model the chance that a player will or will not score. My calculations would assume that the ball is constantly in play, and moves from one set of possible outcomes to the next based on a series of statistics, rather than being considered a series of back and forth shots on the goal. This would conceptually be different as it's following the ball and not the players, and the ball would be assigned to a certain number of possibilities that are weighted by those aforementioned factors.

2) The method by which you are weighting things involves multiple weights, which as others have described increases your percentage changes over a certain amount. In my scenario, you break down the chances into a table so that there is only ever an absolute maximum of 100 possible outcomes, and then you use mt_rand to hit a number inside of this set of outcomes, which is often known as a hit table or a lottery.

In order to do this, you'd have base chances and then weight them, which gives you room to grow. For example, say the base chance of a ball to score is 10/100. If someone is a 1, this becomes 5. 2, it stays 10. 3, it becomes 15. So now, rolls 0-14 are flexibly assigned to those values, and the other values in the hit table shift to accommodate. This brings up probability issues later as you should hypothetically grow the table as well, but that passively reduces the chance of hitting as you'd go from 10/100 to 15/105 (factoring in all other possible outcomes).

If you want to continue down the path you've already started, I think a majority of what I'm saying here couldn't work, unless you simply threw these values into a table and calculated them on each attack as you already do.

If you want to stick with your current nested random statements, I'd say go with one of the solutions that the others have offered. Good luck!

清晨说晚安 2024-08-11 17:36:59

我建议你将所有概率转换为百分比:

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 阵型的球队对阵 5-3-2 阵型的球队比 3-3-4 阵型的球队进球的机会更少。假设排名始终是三重奏 (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:现在看来这没有多大意义,但我会尝试在早上再看一下。

还有一件事:在红牌之后,为什么犯错的球队保持不变?在我看来,它应该会变得更弱(少一名玩家)。

I would suggest you convert all your probabilities to percentages:

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%

Also I would only instantiate some probabilities with the conditions of others, example:

if ($attack === true)
{
    if (Chance(15 * $aggressivity) === true)
    {
        if (Chance(10 * $aggressivity) === true)
        {
            // red card
        }

        else
        {
            // yellow card
        }
    }
}

EDIT: I just home and I really need to go to sleep but after a quick glance at your edit I just had an idea that might interest you. What if, instead of using a adjustment value of 1, 2 or 3 don't you use the tactical position of the team? For instance, a team with a 4-4-2 would have less chances of scoring a goal against a 5-3-2 team than with a 3-3-4 team. Assuming that the placements are always triplets (X-Y-Z) it would be pretty easy to compare which team performs the best at defending, passing and scoring.

A simple formula could be something like this:

A: 4-4-2 (Defending Team)
B: 3-2-5 (Attacking Team)

The chance of B scoring a goal would be (4 / 5) ^ -1 = 0.2 = 20%, and the inverse (team A scoring) would be (3 / 2) ^ -1 = 0.5 = 50%. PS: This doesn't seem to make much sense now, but I'll try to give another look at it in the morning.

And another thing: after a red card why does the faulting team stays the same? It should get weaker (one player less) IMO.

晚雾 2024-08-11 17:36:59

这才是真正的伎俩不是吗?也许开始考虑球员和球队的哪些变量可能会影响行动的成功和概率。

程序流程可能如下所示:
1.根据变量计算哪个事件发生,并让其中存在一些随机性
2. 计算事件的成功率。

恐怕您必须自己完成此操作和编程;)

This is the real trick isn't it? Perhaps start to think about which variables players and teams have which could influence the success and probability of an action.

The program flow could look like:
1. Calculate which event happens on basis of the variables and let there some randomness be there too
2. Calculate the success-rate of the event.

I am afraid you will have to do this and the programming most certainly by yourself ;)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文