足球模拟游戏

时间:2009-09-15 13:02:23

标签: php simulation

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


我建议你最初有几分钟的行动。

$ 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的比率。我认为我可以轻易地将这个机会倍增,以便整合战术影响力。但是有一个问题已经演变:如果我将机会乘以2或更多的战术值,它可以高于100%(例如60 x 1.5 x 1.5)。所以我不能用这种方式整合战术。我还能做什么?


非常感谢!

更新(2014年):几年后,我现在已经发布了游戏的完整代码库作为开源on GitHub。如果有兴趣的话,你会发现这个模拟的具体实现in this file

4 个答案:

答案 0 :(得分:35)

答案 1 :(得分:8)

这很复杂,但如果你想真实地模拟足球比赛,你需要投入更多的变量。并非所有的球队都会进攻,你会有防守者,而这些后卫将会减轻对方球队进攻的力量。

我建议使用更像这样的流程:

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:严重失败:球员失去球权并立即向对方球队产生进球
  7. 2)如果是1,再次滚动,但现在有一组不同的选项可以在对方。在偶数2中,再次在桌子上滚动。如果是三个,则为对方球队制作相同的掷骰,但使用不同的桌子,因为他们更接近目标。如果是4,则再次滚动,但将球员的统计数据更改为A队的球员2,并假设数字更接近目标。在5的情况下,根据随机玩家的技能滚动一个桌子,对方队伍成功或失败。如果是六个,立即给对方球队一个目标(在足球比赛中这种情况发生的时间不到5%,这更像是.01%,但你也可以在另一个桌子上滚动重大失误,包括伤害,或看起来愚蠢十秒钟)。

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

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

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

    1)你的计算基本上是假设每隔这么多分钟尝试一次目标,并且在那时有一组复杂的计算试图模拟一个球员将会或不会得分的机会。我的计算将假设球在不断发挥作用,并根据一系列统计数据从一组可能的结果移动到下一组,而不是被视为目标上的一系列来回射门。这在概念上是不同的,因为它跟随球而不是球员,并且球将被分配给由上述因素加权的一定数量的可能性。

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

    为了做到这一点,你有基础机会,然后加权,这给你增长的空间。例如,假设球得分的基本机会是10/100。如果有人是1,那么它变为5. 2,它保持为10. 3,它变为15.所以现在,将0-14卷灵活地分配给这些值,并且命中表中的其他值移动以适应。这会引发概率问题,因为你应该假设增长表,但是当你从10/100到15/105时(从所有其他可能的结果中考虑),被动地减少击中的几率。

    如果你想继续沿着你已经开始的道路走下去,我认为我在这里说的大部分内容都无法奏效,除非你只是将这些值扔进一张桌子并在每次攻击时计算出来已经做到了。

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

答案 2 :(得分: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的球队对5-3-2球队的进球机会少于3-3-4球队的进球机会。假设这些位置总是三连胜(X-Y-Z),那么比较哪支球队在防守,传球和得分方面表现最佳就很容易了。

一个简单的公式可能是这样的:

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。

答案 3 :(得分:0)

这是真正的伎俩不是吗?也许开始考虑玩家和团队可能影响行动成功和可能性的变量。

程序流程可能如下所示: 1.根据变量计算发生的事件,并在那里也有一些随机性 2.计算事件的成功率。

我担心你必须自己完成这项工作和编程;)