足球模拟游戏

caw*_*caw 28 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
}
?>
Run Code Online (Sandbox Code Playgroud)

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

  • 调整(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上发布了游戏的完整代码库作为开源.如果有兴趣的话,您可以在此文件中找到此模拟的具体实现.

Jak*_*ake 35

建立一个基于'权重'的模拟(是的,我刚刚发明了这个术语).每个变量(不论其类型)都有"权重".例如,玩家有权重.一个好的球员有额外的重量.受伤的球员体重较轻甚至根本没有等待(或者可能是负重?).

你把所有的重量加在一起(两队都是,因为这是一场足球比赛).这个重量类似于获胜机会百分比.例如;

A队的重量= 56,B队的重量= 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%的点数.

其余的点可以平均分配.在我的例子中,我只带了两个守护者,因为一个目标停止或没有停止的宇宙.实际上,可能会有更多的权重因素(你要弄清楚).

一旦他们全部分裂,你可以使用战术点来完成比赛.每分钟你都可以重新计算获胜的机会.每一分钟,你也可以重新计算战术影响(比如说另一名球员进场,或者球员受伤).

是的,你会得到很多变数.但是你得到的越多,比赛就越好.变量(或重量/计数器重量)越多,它就越像现实生活.

  • +1为超长而详细的答案 (16认同)

Nat*_*int 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:严重失败:球员失去球权并立即向对方球队产生进球

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时(从所有其他可能的结果中考虑),被动地减少击中的几率.

如果你想继续你已经开始的路径,我认为我在这里说的大部分内容是行不通的,除非你只是将这些值扔到一个表中并按照你已经做的那样计算每次攻击.

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