Улучшение алгоритма симуляции футбола - PullRequest
7 голосов
/ 17 сентября 2009

В другом вопросе вы помогли мне построить алгоритм симуляции для футбола. Я получил там очень хорошие ответы. Еще раз спасибо!

Теперь я закодировал этот алгоритм. Я хотел бы улучшить его и найти небольшие ошибки, которые могут быть в этом. Я не хочу обсуждать, как это решить - как мы это делали в последнем вопросе. Теперь я хочу только улучшить его. Можете ли вы помочь мне снова, пожалуйста?

  1. Есть ли ошибки?
  2. В порядке ли структура вложенных предложений if? Можно ли это улучшить?
  3. Правильно ли интегрирована тактика в соответствии с моим описанием?

Тактические настройки, которые должны влиять на случайность:

  • $ тактика [x] [0] корректировка (1 = оборонительный, 2 = нейтральный, 3 = наступательный): чем выше значение, тем слабее защита и сильнее нападение
  • $ тактика x скорость игры (1 = медленный, 2 = средний, 3 = быстрый): чем выше значение, тем лучше возможности, но тем выше риск получения быстрого счетчика атака
  • $ тактика x дистанция проходов (1 = короткий, 2 = средний, 3 = длинный): чем выше значение, тем меньше, но лучше возможностей, которые вы получаете, и тем чаще вы находитесь вне игры
  • $ тактика x создание изменений (1 = безопасное, 2 = среднее, 3 = рискованное): чем выше значение, тем лучше ваши возможности, но тем выше риск получения быстрого счетчика атака
  • $ тактика [x] [4] давление в обороне (1 = низкий, 2 = средний, 3 = высокий): чем выше значение, тем быстрее вы будете иметь контратаку
  • $ тактика [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): Несколько лет спустя я выпустил полную кодовую базу игры как с открытым исходным кодом на GitHub . Вы найдете конкретную реализацию этого моделирования в этом файле , если кому-то интересно.

Ответы [ 4 ]

8 голосов
/ 24 сентября 2009

В общем, похоже, что это довольно сложная проблема, и я не уверен, насколько эффективно вы ее получите.

Тем не менее, я видел некоторые вещи, которые определенно помогут вам.

Сначала я бы набрал переменные в параметрах. Это не обязательно сделает ваш код быстрее, но облегчит его чтение и отладку. Затем я бы удалил параметры $ teamname_att, $ teamname_def и просто использовал их в качестве значений в ассоциативных массивах $ strong_att, $ force_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']);

Надеюсь, это поможет.

5 голосов
/ 25 сентября 2009

Юс, похоже, отсутствует: -

#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;
}
5 голосов
/ 24 сентября 2009

Я (быстро) прочитал его и заметил несколько вещей:

  • Процент розданной красно-желтой карточки одинаков во всех третях поля, это намеренно? Я не футбольный парень, но я бы сказал, что нарушения чаще происходят на последней трети поля, чем на первой. (Потому что, если вы на первом, вы, вероятно, защищаетесь)

  • Процент для определения того, что пенальти начисляется, одинаков для каждой команды, однако некоторые команды, или, скорее, игроки, с большей вероятностью наберут пенальти, чем другие.

  • Вы не учитываете угловые удары, возможные травмы после фола или голы, забитые головой (о чем стоит упомянуть в отчете).

Кроме того, вам нужно будет просто запустить эту симуляцию лот раз и посмотреть, верны ли выбранные вами значения; настроить алгоритм. Лучше всего сделать это вручную (например, прочитать все константы из файла и запустить пару сотен симуляций с разными значениями и разными командами), проще всего, вероятно, реализовать генетический алгоритм, чтобы попытаться найти лучшие значения.

По сути, у вас есть настоящий геймплейный / ай-код, так что вы можете изучить методы, используемые игровыми студиями для управления этим типом кода. (Одна вещь - поместить переменные в электронную таблицу Google, которую вы, например, можете поделиться / настроить легче).

Кроме того, даже если вы упускаете некоторые вещи, которые есть в настоящем футбольном матче, нет смысла пытаться быть максимально реалистичным, потому что обычно в этих случаях важнее обеспечить хороший игровой процесс, чем обеспечить точную симуляцию. .

0 голосов
/ 17 сентября 2009

Как часто эти значения будут проверяться? Если он будет использоваться многими людьми и постоянно повторять эти операторы if / else, я вижу, как вы поглощаете много памяти и работаете довольно медленно.

Возможно, вы могли бы использовать несколько переключателей, чтобы заменить некоторые из "если"?

Это все, что я вижу для улучшения скорости. Что касается самого алгоритма, мне придется чуть позже ознакомиться с ним, если этого не сделает никто.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...