Улучшение алгоритма моделирования футбола

StackOverflow https://stackoverflow.com/questions/1439102

  •  10-07-2019
  •  | 
  •  

Вопрос

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

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

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

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

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

Это было полезно?

Решение

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

Тем не менее, я видел кое-что, что определенно могло бы вам помочь.

Сначала я бы ввел переменные в параметры.Это не обязательно ускорит ваш код, но облегчит его чтение и отладку.Далее я бы удалил параметры $teamname_att, $teamname_def и просто оставил их в качестве значений в ассоциативных массивах $strength_att, $strength_def.Поскольку эти данные в любом случае всегда объединены в пары, это снизит риск случайного использования имени одной команды в качестве ссылки на другую команду.

Благодаря этому вам не придется постоянно искать значения в массивах:

// replace all $tactics[$teamname_att] with $attackers
$attackers = $tactics[$teamname_att]; 
$defenders = $tactics[$teamname_def];
// Now do the same with arrays like $_POST[ "team1" ];

У вас есть три вспомогательные функции, каждая из которых имеет шаблон:

function foo( $arg ){
    $bar = $arg * $value;
    return $bar;
}

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

function tactics_weight($wert) {
    return $wert*0.1+0.8;
}

function strengths_weight($wert) {
    return log10($wert+1)+0.35;
}

/*
 Perhaps I missed it, but I never saw Chance_Percent( $num1, $num2 )
 consider using this function instead: (one line instead of four, it also
 functions more intuitively, Chance_Percent is your chance out of 100 
 (or per cent)

 function Chance_Percent( $chance ) {
     return (mt_rand(1, 100) <= $chance);
 }    

*/
function Chance_Percent($chance, $universe = 100) {
    $chance = abs(intval($chance)); // Will you always have a number as $chance?
                                    // consider using only abs( $chance ) here.
    $universe = abs(intval($universe));
    return (mt_rand(1, $universe) <= $chance);
}

Я не мог не заметить, что эта закономерность возникает постоянно:

$matchReport .= ' ' . comment_action($teamname_att, 'attack');

Мой общий опыт показывает, что если вы переместите объединение $matchReport в comment_action, то это будет просто немного быстрее (обычно менее дюжины миллисекунд, но поскольку вы вызываете эту функцию полдюжины раз внутри рекурсивной функции, это может сэкономить пару десятых секунды за один запуск).

Я думаю, что это выглядело бы намного лучше (как с точки зрения читателя, так и с точки зрения

Наконец, есть несколько случаев, когда вы будете использовать один и тот же вызов одной и той же функции с одним и тем же параметром.Сделайте этот звонок заранее:

$goalieStrength = strengths_weight($strength_def['goalkeeper']);

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

Другие советы

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

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

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

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

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

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

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

Кажется, тебя не хватает: -

#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;
}

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top