2009-09-17 1 views
6

In un'altra domanda, mi hai aiutato a creare un algoritmo di simulazione per il calcio. I got some very good answers there. Grazie ancora!Miglioramento dell'algoritmo di simulazione calcistica

Ora ho codificato questo algoritmo. Mi piacerebbe migliorarlo e trovare piccoli errori che potrebbero esserci. Non voglio discutere su come risolverlo, come abbiamo fatto nell'ultima domanda. Ora voglio solo migliorarlo. Puoi aiutarmi di nuovo per favore?

  1. Ci sono errori?
  2. La struttura delle clausole if annidate è ok? Potrebbe essere migliorato?
  3. Le tattiche sono integrate correttamente secondo la mia descrizione?

impostazioni tattiche che dovrebbero avere un'influenza sulla casualità:

  • $ tattiche [x] [0] di regolazione (1 = difensiva, 2 = neutro, 3 = offensivo): più alta il valore è il più debole è la difesa e il più forte è l'attacco
  • $ tattiche x velocità di gioco (1 = lento, 2 = medio, 3 = veloce): maggiore è il valore è il migliore sono le opportunità ma più alto è il rischio di ottenere un rapido contrattacco
  • $ tattica x distanza dei passaggi (1 = corto, 2 = medio, 3 = lungo): maggiore è il valore è minore ma migliori opportunità si ottiene e più spesso si è in fuorigioco
  • $ tattiche x creazione di modifiche (1 = sicuro, 2 = medio, 3 = rischioso: più alto è il valore, migliori sono le tue opportunità ma maggiore è il rischio di ottenere un rapido contrattacco
  • $ tattica [x] [4] pressione in difesa (1 = basso, 2 = medio, 3 = alto): maggiore è il valore è il più rapido contrattacco che avrai
  • $ tattica [x] [5] aggressività (1 = bassa, 2 = media, 3 = alta) : maggiore è il valore, maggiore è il numero di attacchi che si interrompono per i falli

Nota: La tattica 0 e la tattica 4 sono parzialmente integrate nel resto del motore, non necessarie in questa funzione.

L'algoritmo corrente:

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

Update (2014): Pochi anni dopo, ho rilasciato il codice di base completa del gioco come open-source on GitHub. Troverai l'implementazione specifica di questa simulazione in this file, se qualcuno è interessato.

+1

Sono certo tempo StackOverflow è il posto giusto per discutere di 191 LOC. Soprattutto perché probabilmente sei l'unico a sapere se il tuo codice è corretto al 100% semanticamente. Suggerimento: decidi per una lingua, non mescolare inglese e tedesco nel codice. – middus

+0

@middus: mi dispiace. Ho scritto il codice in tedesco, ma ho tradotto tutte le parti importanti in inglese per te. Forse una domanda stupida: cos'è "191 LOC"? Pensavo che qualcuno potesse aiutarmi perché tutti i dati necessari sono nella domanda. Vediamo ... – caw

+1

LOC = Linee di codice –

risposta

8

In generale, sembra che questo sia un problema abbastanza complicato e non sono sicuro di quanto sia efficiente.

Detto questo, ho visto alcune cose che avrebbero sicuramente aiutato.

Prima vorrei digitare le variabili nei parametri. Questo potrebbe non rendere il tuo codice più veloce, ma renderà più facile la lettura e il debug. Successivamente, rimuoverei i parametri $ teamname_att, $ teamname_def e li ho semplicemente come valori negli array $ strength_att, $ strength_def associativi. Dato che questi dati sono sempre associati, questo ridurrà il rischio di utilizzare accidentalmente il nome di una squadra come riferimento per l'altra squadra.

In questo modo sarà in modo da non dover cercare continuamente i valori in array:

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

avete tre funzioni di aiuto che hanno tutti il ​​modello:

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

Dal momento che questo significa che devi creare una variabile extra (qualcosa che può essere costoso) ogni volta che esegui la funzione, usale invece:

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

Non ho potuto fare a meno di notare questo modello in arrivo in modo coerente:

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

La mia esperienza generale è che se si sposta la concatenazione di $ matchReport in comment_action, allora sarà solo leggermente più più veloce (generalmente meno di una decina di millisecondi, ma dal momento che la funzione viene chiamata una mezza dozzina di volte all'interno di una funzione ricorsiva, questo potrebbe radere un paio di decimi di secondo per esecuzione).

Penso che questo sarebbe il flusso molto meglio (sia dal punto di vista di un lettore, e da

Infine, ci sono molte volte in cui si intende utilizzare la stessa chiamata alla stessa funzione con lo stesso parametro. Fare quella chiamata in attacco:.

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

Spero che questo aiuti

+0

Grazie mille! I tuoi suggerimenti velocizzano lo script e lo rendono più chiaro. Implementerò tutte le tue proposte che penso. – caw

0

Con quale frequenza vengono controllati questi valori? Se sarà utilizzato da molte persone e ricorrere costantemente a quelle if/else, posso vederti consumare molta memoria e correre abbastanza lentamente.

Forse potreste fare un paio di interruttori per sostituire alcune delle if?

Questo è tutto ciò che posso vedere per il miglioramento della velocità. Per quanto riguarda l'algoritmo stesso, dovrò esaminarlo un po 'più tardi se nessun altro lo fa.

+0

Grazie mille, BraedenP! Gli switch sono davvero più veloci di if/else? Penso di non poter usare gli switch poiché tutte le istruzioni condizionali sono nidificate. Non ho idea di come usare gli interruttori qui ragionevolmente. Sarebbe bello se potessi dire qualcosa anche all'algoritmo stesso. – caw

+0

Perché considerare l'ottimizzazione? Ha chiesto miglioramenti per il suo algoritmo. –

+0

E l'ottimizzazione non è un miglioramento? – BraedenP

5

I (rapidamente) letto attraverso di essa e ho notato un paio di cose:

  • La percentuale di una carta rossa/gialla è la stessa in tutti i terzi del campo, è intenzionale? Non sono un ragazzo di calcio, ma direi che è più probabile che le offese avvengano nell'ultimo terzo del campo, piuttosto che sul primo. (Perché se sei il primo, probabilmente stai difendendo)

  • La percentuale per determinare che viene inflitta una penalità è la stessa per ogni squadra, tuttavia alcune squadre, o piuttosto i giocatori, hanno maggiori probabilità di segnare una penalità rispetto ad altri.

  • Non stai prendendo in considerazione calci d'angolo, possibili infortuni dopo un fallo, o gol segnati usando la testa (che potrebbe valere la pena menzionare nella relazione).

Oltre a questo, avrete solo bisogno di eseguire questa simulazione un sacco di volte e vedere se i valori scelti sono corretti; modificare l'algoritmo. La cosa migliore da fare è modificarla a mano (ad esempio leggere tutte le costanti da un file ed eseguire un paio di centinaia di simulazioni con valori diversi e diversi team), la cosa più semplice da fare è probabilmente implementare un algoritmo genetico per cercare di trovare valori migliori.

Fondamentalmente quello che hai qui è un vero codice gameplay/ai, quindi potresti voler leggere le tecniche usate dagli studi di gioco per gestire questo tipo di codice. (Una cosa è mettere le variabili in un foglio di calcolo di google che puoi poi condividere/modificare più facilmente, ad esempio).

Inoltre, anche se ti mancano alcune cose che una vera partita di calcio ha, non ha senso cercare di essere il più realistico possibile perché generalmente in questi casi è più importante fornire un gameplay piacevole che quello di fornire un accurato simulazione.

+0

Grazie, suggerimenti molto carini! :) Darò un'occhiata a tutti loro. Penso di poter migliorare la qualità della simulazione con i tuoi suggerimenti. – caw

+0

"esegui questa simulazione molte volte e verifica se i valori che hai scelto sono corretti" Come posso fare questo? Basta dare un'occhiata a tutti i report delle partite e decidere se sono realistici o no?- "La cosa più facile da fare è probabilmente implementare un Algoritmo Genetico per cercare di trovare valori migliori" Come dovrebbe fare un Algoritmo Genetico? Come misurare la qualità/idoneità/successo di ogni popolazione? – caw

+0

Quello che fai è trovare alcuni valori per alcuni gruppi ben noti (o meglio, squadre che vincono la maggior parte del tempo e squadre che ti aspetteresti di perdere sempre). E poi decidi quali risultati ti piacciono di più. Ora il problema con questo è, naturalmente, che la tua interpretazione dei risultati può essere molto soggettiva. –

5

Yous sembrano mancare: - Non

#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 Molto divertente, forse lo implementerò come un uovo di Pasqua o per giochi divertenti. ;) – caw