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

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

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

  1. Есть ли ошибки?
  2. Является ли структура вложенных if-clauses ок? Можно ли улучшить его?
  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 . Вы найдете конкретную реализацию этого моделирования в этом файле , если кому-то это интересно.

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

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

    Сначала я бы напечатал переменные в параметрах. Возможно, это не обязательно сделает ваш код быстрее, но это упростит чтение и отладку. Затем я удаляю параметры $ teamname_att, $ teamname_def и просто получаю их как значения в ассоциативных массивах $ strength_att, $ strong_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']); 

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

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

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

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

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

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

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

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

    Yous, кажется, отсутствует: –

     #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, я вижу, что вы много едите и работаете довольно медленно.

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

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