2009-09-17 24 views
6

En otra pregunta, me ayudaste a construir un algoritmo de simulación para el fútbol. I got some very good answers there. ¡Gracias de nuevo!Mejorando el algoritmo de simulación de fútbol

Ahora he codificado este algoritmo. Me gustaría mejorarlo y encontrar pequeños errores que podrían estar en él. No quiero discutir cómo resolverlo, como lo hicimos en la última pregunta. Ahora solo quiero mejorarlo. ¿Puedes ayudarme otra vez por favor?

  1. ¿Hay algún error?
  2. ¿Está bien la estructura de las cláusulas if anidadas? Podría ser mejorado?
  3. ¿Están las tácticas integradas correctamente según mi descripción?

ajustes tácticos que deben tener una influencia sobre la aleatoriedad:

  • $ tácticas [x] [0] ajuste (1 = defensiva, 2 = neutral, 3 = ofensivo): cuanto mayor el valor es más débil es la defensa y más fuerte es la ofensa
  • $ tactics x velocidad de juego (1 = lento, 2 = medio, 3 = rápido): cuanto mayor es el valor, mejores son las oportunidades pero mayor es el riesgo de obtener un contraataque rápido
  • $ tactics x distancia de pases (1 = short, 2 = medium, 3 = long): cuanto mayor sea el valor, menos oportunidades obtendrás y cuanto más a menudo estés fuera de juego
  • $ tactics x creación de cambios (1 = seguro, 2 = medio, 3 = arriesgado): cuanto mayor sea el valor, mejores serán sus oportunidades, pero mayor será el riesgo de obtener un contraataque rápido
  • $ tactics [x] [4] pressure in defense (1 = bajo, 2 = medio, 3 = alto): cuanto mayor sea el valor, más contraataques rápidos tendrá
  • $ tactics [x] [5] agresividad (1 = bajo, 2 = medio, 3 = alto) : cuanto mayor sea el valor, más ataques se detendrán por fouls

Nota: Tactic 0 y Tactic 4 están parcialmente integrados en el resto del motor, no son necesarios en esta función.

El algoritmo actual:

<?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 
} 

Actualización (2014): Unos años más tarde, me han dado a conocer ahora la base de código completo del juego como open-source on GitHub. Encontrará la implementación específica de esta simulación in this file, si alguien está interesado.

+1

No estoy seguro de Stackoverflow tiempo es el lugar adecuado para discutir 191 LOC. Especialmente ya que probablemente sea el único que sabe si su código es 100% semánticamente correcto. Sugerencia: elija un idioma, no mezcle inglés y alemán en su código. – middus

+0

@middus: Lo siento. Escribí el código en alemán pero traduje todas las partes importantes al inglés para ti. Quizás una pregunta estúpida: ¿Qué es "191 LOC"? Pensé que alguien podría ayudarme porque todos los datos necesarios están en la pregunta. Veamos ... – caw

+1

LOC = Líneas de código –

Respuesta

8

En general, parece que este es un problema bastante complicado, y no estoy seguro de qué tan eficiente lo conseguirá.

Dicho esto, he visto algunas cosas que definitivamente te ayudarían.

Primero escribiría las variables en los parámetros. Esto puede no necesariamente hacer que su código sea más rápido, pero sería más fácil de leer y depurar. A continuación, eliminaría los parámetros $ teamname_att, $ teamname_def y simplemente los incluiría como valores en las matrices asociativas $ strength_att, $ strength_def. Dado que estos datos siempre están emparejados de todos modos, esto reducirá el riesgo de utilizar accidentalmente el nombre de un equipo como referencia para el otro equipo.

Esto hará que sea por lo que no tendrá que buscar continuamente los valores de las matrices:

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

tiene tres funciones de ayuda que todos tienen el patrón:

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

Dado que esto significa que debe crear una variable adicional (algo que puede ser costoso) cada vez que ejecute la función, utilícelos en su lugar:

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

no pude dejar de notar este patrón viene constantemente:

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

Mi experiencia general es que si se mueve la concatenación de $ matchReport en comment_action, entonces será sólo ligeramente más rápido (generalmente menos de una docena de milisegundos, pero ya que está llamando a esa función media docena de veces dentro de una función recursiva, esto podría reducir un par de décimas de segundo por ejecución).

creo que esto fluya mucho mejor (tanto desde la perspectiva de un lector, y desde

Por último, hay varios momentos en los que va a utilizar la misma llamada a la misma función con el mismo parámetro. ¡Llama en la delantera:.

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

esperanza esto ayuda

+0

¡Muchas gracias! Sus sugerencias aceleran el guión y lo aclaran. Implementaré todas tus propuestas, creo. – caw

0

¿Con qué frecuencia se van a verificar estos valores? Si va a ser utilizado por muchas personas y recurre constantemente a esas declaraciones if/else, puedo verte consumir mucha memoria y correr bastante despacio.

¿Quizás podrías cambiar algunos de ellos para reemplazar algunos de los if?

Eso es todo lo que puedo ver para mejorar la velocidad. En cuanto al algoritmo en sí, tendré que leer más sobre eso un poco más tarde si nadie más lo hace.

+0

Muchas gracias, BraedenP! ¿Los conmutadores son realmente más rápidos que las sentencias if/else? Creo que no puedo usar switches ya que todos los enunciados condicionales están anidados. No tengo idea de cómo usar los interruptores aquí de manera razonable. Sería genial si también pudieras decir algo al algoritmo más tarde. – caw

+0

¿Por qué considerar la optimización? Pidió mejoras para su algoritmo. –

+0

Y una optimización no es una mejora? – BraedenP

5

I (rápidamente) leído a través de él y me di cuenta de un par de cosas:

  • El porcentaje en que se entrega una tarjeta roja/amarilla es el mismo en todos los tercios del campo, ¿es esto intencional? No soy futbolista, pero diría que es más probable que las ofensas ocurran en el último tercio del campo, que en el primero. (Porque si estás en el primero, probablemente estés defendiendo)

  • El porcentaje para determinar que se anota una penalización es el mismo para cada equipo, sin embargo, algunos equipos, o más bien jugadores, tienen más probabilidades de marcar una pena que otros.

  • No tiene en cuenta los tiros de esquina, las posibles lesiones después de una falta, o los goles marcados con la cabeza (que podría valer la pena mencionar en el informe).

Aparte de eso, usted sólo tiene que ejecutar esta simulación mucho de veces y ver si los valores que ha elegido son correctas; ajustar el algoritmo. Lo mejor que se puede hacer es ajustarlo manualmente (por ejemplo, leer todas las constantes de un archivo y ejecutar un par de cientos de simulaciones con diferentes valores y diferentes equipos), lo más fácil es implementar un algoritmo genético para intentar encontrar mejores valores

Básicamente lo que tienes aquí es código de juego genuino/ai, por lo que es posible que quieras leer sobre las técnicas utilizadas por los estudios de juegos para administrar este tipo de código. (Una cosa es poner las variables en una hoja de cálculo de Google que luego puede compartir/ajustar más fácilmente, por ejemplo).

Además, aunque faltan algunas cosas que un partido de fútbol real tiene, no tiene sentido tratar de ser lo más realista posible porque generalmente en estos casos es más importante proporcionar un buen juego que proporcionar un juego preciso. simulación.

+0

¡Gracias, muy buenas sugerencias! :) Voy a echar un vistazo a todos ellos. Creo que puedo mejorar la calidad de la simulación con tus consejos. – caw

+0

"ejecute esta simulación muchas veces y vea si los valores que eligió son correctos" ¿Cómo puedo hacer esto? Simplemente eche un vistazo a todos los informes de los partidos y decida si son realistas o no.- "lo más fácil es probablemente implementar un algoritmo genético para intentar encontrar mejores valores". ¿Cómo debería hacer eso un algoritmo genético? ¿Cómo medir la calidad/aptitud/éxito de cada población? – caw

+0

Lo que debes hacer es encontrar algunos valores para un grupo de equipos bien conocidos (o más bien, equipos que ganan la mayor parte del tiempo y equipos que esperarías perder todo el tiempo). Y luego decides qué resultados te gustan más. Ahora, el problema con esto es, por supuesto, que su interpretación de los resultados puede ser muy subjetiva. –

5

Yous parece que faltan: -

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

: D Muy gracioso, tal vez implementaré esto como un huevo de pascua o para juegos divertidos. ;) – caw

Cuestiones relacionadas