views:

1060

answers:

5

Hello!

I would like to build a simulation engine which can simulate a soccer (association football) match. It would be cool great if you could help me. What is important to me is to decide which actions happen. The event listeners for each action can be implemented later easily. The function should only simulate the game results and comments to happening actions. There is no 2D/3D graphics needed. We're talking about games like Hattrick.


I would propose that you have an array of minutes with actions at first.

$minutes = array(1, 3, 4, 7, 11, 13, ..., 90, 92);

For each of these minutes, you could then simulate an attack.

The attacking team is determined by dice before: $attacking = mt_rand(1, 2);

So the part which is most important to me is the attack function.

Please edit my approach or use it as a sample. Can you help me to improve this? The function should be complex so that the results are as realistic as possible. But you need to find something between high predictability and too random results. I only want to improve this function.

My approach:

<?php
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, $schuesse, $taktiken;
 // 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
 // ADJUSTMENT START
 switch ($taktiken[$teamname_att][0]) {
  case 1: $strength_att['defenders'] *= 1.1; $strength_att['forwards'] *= 0.9; break;
  case 3: $strength_att['defenders'] *= 0.9; $strength_att['forwards'] *= 1.1; break;
 }
 switch ($taktiken[$teamname_def][0]) {
  case 1: $strength_def['defenders'] *= 1.1; $strength_def['forwards'] *= 0.9; break;
  case 3: $strength_def['defenders'] *= 0.9; $strength_def['forwards'] *= 1.1; break;
 }
 // ADJUSTMENT END
 $matchReport .= '<p>'.$minute.'\': '.comment($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*($taktiken[$teamname_att][1]/2)*($taktiken[$teamname_att][2]/2))) {
  // attacking team passes 1st third of opponent's field side
  $matchReport .= ' '.comment($teamname_def, 'attack_advance');
  if (Chance_Percent(25*($taktiken[$teamname_def][4]/2))) {
   // the defending team fouls the attacking team
   $fouls[$teamname_def]++;
   $matchReport .= ' '.comment($teamname_def, 'attack_advance_foul');
   if (Chance_Percent(43)) {
    // yellow card for the defending team
    // chance is correct for my purpose
    $yellowCards[$teamname_def]++;
    $matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_yellow');
   }
   elseif (Chance_Percent(3)) {
    // red card for the defending team
    // chance is correct for my purpose (only 1.43% because it's an alternative way)
    $redCards[$teamname_def]++;
    $matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_red');
   }
   // indirect free kick
   // only 58.23% because it's an alternative way
   $matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_iFreeKick');
   if (Chance_Percent(25)) {
    // shot at the goal
    $schuesse[$teamname_att]++;
    $matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_iFreeKick_shot');
    if (Chance_Percent(25)) {
     // attacking team scores (6.25% chance)
     $goals[$teamname_att]++;
     $matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_iFreeKick_shot_score');
    }
    else {
     // defending goalkeeper saves
     // only 18.75% because it's an alternative way
     $matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_iFreeKick_shot_save');
    }
   }
   else {
    // defending team cleares the ball
    // only 75% because it's an alternative way
    $matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_iFreeKick_clear');
   }
  }
  elseif (Chance_Percent(17)) {
   // attacking team is caught offside
   // only 4.25% because it's an alternative way
   $offsides[$teamname_att]++;
   $matchReport .= ' '.comment($teamname_def, 'attack_advance_offside');
  }
  else {
   if (Chance_Percent(25*($taktiken[$teamname_def][4]/2))) {
    // the defending team fouls the attacking team
    $fouls[$teamname_def]++;
    $matchReport .= ' '.comment($teamname_def, 'attack_advance_foul');
    if (Chance_Percent(43)) {
     // yellow card for the defending team
     // chance is correct for my purpose
     $yellowCards[$teamname_def]++;
     $matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_yellow');
    }
    elseif (Chance_Percent(3)) {
     // red card for the defending team
     // chance is correct for my purpose (only 1.43% because it's an alternative way)
     $redCards[$teamname_def]++;
     $matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_red');
    }
    if (Chance_Percent(19)) {
     // penalty for the attacking team
     $schuesse[$teamname_att]++;
     $matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_penalty');
     if (Chance_Percent(77)) {
      // attacking team scores (77% chance according to Wikipedia)
      $goals[$teamname_att]++;
      $matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_penalty_score');
     }
     elseif (Chance_Percent(50)) {
      // shot misses the goal
      // only 11.5% because it's an alternative way
      $matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_penalty_miss');
     }
     else {
      // defending goalkeeper saves
      // only 11.5% because it's an alternative way
      $matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_penalty_save');
     }
    }
    elseif (Chance_Percent(28)) {
     // direct free kick
     // only 22.68% because it's an alternative way
     $matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_dFreeKick');
     if (Chance_Percent(33)) {
      // shot at the goal
      $schuesse[$teamname_att]++;
      $matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_dFreeKick_shot');
      if (Chance_Percent(33)) {
       // attacking team scores (10.89% chance)
       $goals[$teamname_att]++;
       $matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_dFreeKick_shot_score');
      }
      else {
       // defending goalkeeper saves
       $matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_dFreeKick_shot_save');
      }
     }
     else {
      // defending team cleares the ball
      // only 77% because it's an alternative way
      $matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_dFreeKick_clear');
     }
    }
    else {
     // indirect free kick
     // only 58.23% because it's an alternative way
     $matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_iFreeKick');
     if (Chance_Percent(25)) {
      // shot at the goal
      $schuesse[$teamname_att]++;
      $matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_iFreeKick_shot');
      if (Chance_Percent(25)) {
       // attacking team scores (6.25% chance)
       $goals[$teamname_att]++;
       $matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_iFreeKick_shot_score');
      }
      else {
       // defending goalkeeper saves
       // only 18.75% because it's an alternative way
       $matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_iFreeKick_shot_save');
      }
     }
     else {
      // defending team cleares the ball
      // only 75% because it's an alternative way
      $matchReport .= ' '.comment($teamname_def, 'attack_advance_foul_iFreeKick_clear');
     }
    }
   }
   else {
    // attack passes the 2nd third of the opponent's field side - good chance
    $matchReport .= ' '.comment($teamname_def, 'attack_advance_advance');
    if (Chance_Percent(62*($taktiken[$teamname_att][1]/2)*($taktiken[$teamname_att][2]/2)/($taktiken[$teamname_att][2]/2)*($taktiken[$teamname_att][3]/2)/($taktiken[$teamname_def][4]/2))) {
     // shot at the goal
     $schuesse[$teamname_att]++;
     $matchReport .= ' '.comment($teamname_def, 'attack_advance_advance_shot');
     if (Chance_Percent(30*$strength_def['goalkeeper']/7/($taktiken[$teamname_att][2]/2))) {
      // the attacking team scores
      // only 8.78% because it's an alternative way
      // if goalkeeper has strenth 7 then chance is 8.78% otherwise lower/higher
      $goals[$teamname_att]++;
      $matchReport .= ' '.comment($teamname_def, 'attack_advance_advance_shot_score');
     }
     else {
      if (Chance_Percent(50)) {
       // the defending defenders block the shot
       $matchReport .= ' '.comment($teamname_def, 'attack_advance_advance_shot_block');
      }
      else {
       // the defending goalkeeper saves
       $matchReport .= ' '.comment($teamname_def, 'attack_advance_advance_shot_save');
      }
     }
    }
   }
  }
 }
 // attacking team doesn't pass 1st third of opponent's field side
 elseif (Chance_Percent(15*$defense_strength*($taktiken[$teamname_att][1]/2)*($taktiken[$teamname_att][3]/2))) {
  // quick counter attack - playing on the break
  // only 7.5% because it's an alternative way
  // if defense has strength 7 then chance is 7.5% otherwise lower/higher
  $strength_att['defenders'] = $strength_att['defenders']*0.8; // weaken the current attacking team's defense
  $matchReport .= ' '.comment($teamname_def, 'attack_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($teamname_def, 'attack_throwIn');
  if (Chance_Percent(33)) {
   // if a new chance is created
   if (Chance_Percent(50)) {
    // throw-in for the attacking team
    $matchReport .= ' '.comment($teamname_def, 'attack_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($teamname_def, 'attack_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
}
?>

Tactical settings which should have an influence on the randomness:

  • adjustment (1=defensive, 2=neutral, 3=offensive): the higher the value is the weaker is the defense and the stronger is the offense
  • speed of play (1=slow, 2=medium, 3=fast): the higher the value is the better are the opportunities but the higher is the risk of getting a quick counter attack
  • distance of passes (1=short, 2=medium, 3=long): the higher the value is the less but better opportunities you get and the more often you are offside
  • creation of changes (1=safe, 2=medium, 3=risky): the higher the value is the better are your opportunities but the higher is the risk of getting a quick counter attack
  • pressure in defense (1=low, 2=medium, 3=high): the higher the value is the more quick counter attacks you will have
  • aggressivity (1=low, 2=medium, 3=high): the higher the value is the more attacks you will stop by fouls

Integration of the tactical settings:

All the tactical settings have a value which can be "1", "2" or "3". "2" is always neutral/medium. So I divide the values by 2. I get a ratio which is 0.5 or 1 or 1.5. I thought that I could then easily multiply the chances by this in order to integrate tactical influence. But one problem has evolved: If I multiply a chance by 2 or more tactical values, it can be higher than 100% (60 x 1.5 x 1.5 for example). So I can't integrate the tactics this way. What else can I do?


Thank you very much!

A: 

This is the real trick isn't it? Perhaps start to think about which variables players and teams have which could influence the success and probability of an action.

The program flow could look like: 1. Calculate which event happens on basis of the variables and let there some randomness be there too 2. Calculate the success-rate of the event.

I am afraid you will have to do this and the programming most certainly by yourself ;)

Mobbit
It's a pity :(This is the point where I have been stuck for several months now. My users complain that there is too much randomness in the simulation. I've added the factors which have an influence on the randomness now.
Now I've added "Integration of the tactical settings" to the question. Can you please have a look at this? Do you have a solution for my problem in that point?
+11  A: 

Build a 'weight'-based-simulation (Yeah, I just now invented that term). Each variable (regardless of its type) has a 'weight'. For example, players have weights. A good player has extra weight. A player with an injury has less weight or even no wait at all (or maybe negative weight?).

You add all the weight together (of both teams, because it is a soccer match). That weight resembles a winning chance percentage. For example;

The weight of Team A = 56, the weight of Team B = 120

The weight already shows that one team is much better (regardless of how the weight was established .. maybe they have very round balls, who cares) than the other.

Based on the weight, you could calculate a winning chance; The winning chance of Team A = 32%, The winning chance of Team B = 68%.

Now you could write an algorithm that simulates a match, influenced by the winning percentage. I wrote an algorithm like this once to draw advertisements. In my case, the number of clicks an advertisement had was the weight. The bigger the weight, the more chance the advertisement was picked by my algorithm.

I wrote the algorithm by taking a large number (like, 1000) and then assigned a range of that number to each advertisement, based on the weight percentage. In this case, Team A gets a range of 32% of 1000, which is 0 - 320, Team B gets a range of 68% which is 321 - 1000. Then my algorithm would draw a number (randomly) between 0 and 1000. The advertisement (or your teams) with the largest range (and thus largest winning chance) has the most chance of being picked by the algorithm, although it could turn out differently.

This kind of algorithm is great (although not perfect) for a balanced outcome (if users could create their own teams, buy better players, etc). You could also make any events within the game drawn by this algorithm, simply by adding a weight to the event as well..

You could add weight to an event (for example the injury of a team mate), per team, based on other weight factors within that team (how many matches played in a row, how good is (or how much weighs) their medic staff, etc). If you do the weight thing right, you could get a very balanced (and easily expandable) simulation algorithm that can both be predictable (just like some matches in real life) or totally surprising (again, just like a real life match).

UPDATE: Tactical Influences You added tactical influences, plus the question 'how would you do it?', so I will elaborate. What you are currently doing (as I understand it) is you take a percentage (the chance something occurs) and multiply that with a ratio, so that it will occur more/less.

However, because you can have multiple ratio's, you end up with a chance more then 100%.

First of all, for every tactical advantage of a team, there is (probably) a counter advantage on the other team. For example, if Team A has a weight in making goals, Team B has a counter weight in stopping goals. This sum is the universe (100%). Now the weight of both tactical advantages makes up a piece of that universe, or total weight (as I explained above).

Say that Team A is 80% certain of scoring a goal, in a certain minute, and Team B is 20% certain of stopping it (based on the weight system). But, because Team B just acquired a very good keeper, there is a tactical influence on Team B's side. This influence should shift the chance of an event, but not the universe itself! In other words, you shouldn't end up with a total chance of more then 100% (although in some cases, this isn't necessarily a bad thing)

So, you should add weight to Team B, based on the tactical influence and then re-calculate the chances based on the new weights.

Assigning Weight

Now, like you commented, assigning weight isn't easy. Certainly not if you have to 'weigh' players on their qualities. Weighing is about more then just saying that a player is 'bad' or 'good', you have to actually grade them (like in high school!). The bigger the highest grade, the more accurate the weighting system is.

Now, assigning weights to tactical influences is a bit more easier. Say that you have the following influences;

  • Stopping goals
  • Scoring goals
  • Defence
  • Attack

Now, create a pool of total weight (say, 1000, I like that number). These are 'tactical points' you could assign. These four influences make up a match, so you could assign 250 points to each influence. This number (250) is the universe of each influence.

The assignment of these points, per team, depends on the team's weight factors (like, do they have a good keeper?)

A keeper, for instance, weighs against the opponents keeper (and maybe also the people that are in between the keeper and the opponent, but let's keep it simple). Say the keeper of Team A weighs 80% of the total, and the keeper of Team B 20%. This rates how good they are, which is directly related to the tactical points they get. So Team A gets 80% of 250 stopping-goals-points and Team B gets 20% of those points.

The rest of the points can be assigned equally. In my example, I took only two keepers as the universe of wether a goal gets stopped or not. In reality, there could be a lot more weight factors (for you to figure out).

Once they are all divided, you can use the tactical points to make out the match. For each minute you could re-calculate the chance of winning. Each minute, you could also re-calculate the tactical influences (say another player enters the field, or a player is injured).

Yes, you will get a LOT of variables. But the more you get, the better a match plays. The more variables (or weights / counter weights) the more it feels like real life.

MiRAGe
Very good answer, thank you. This is how I do it now. But the difficult thing is finding the right weights :)
Now I've added "Integration of the tactical settings" to the question. Can you please have a look at this? Do you have a solution for my problem in that point?
I added an update..
MiRAGe
+1 for the super long and detailed answer
Alec Smart
@MiRAGe: Thanks alot for this detailed update! :) I've already built the basic construction which should simulate the match. You can see it in my question. There are chances in lots of situations. The tactical values should only influence/change these chances. You can see my tactical values in my question, too. I don't want to distribute tactical points or so.
Well the problem with your chance calculation is that you are trying to multiply apple's by banana's and that will give unexpected results. You should translate your ratio to percentages in order to use them.
MiRAGe
Why apples and bananas? Why shouldn't I multiply them? For me it's logical: If a tactical value is 3, the chances are increased, if it's 1 they are decreased and if it's 2 nothing is changed. Or: (x*0.1+0.8) would give a value between 0.9 and 1.1 which I could use as percentages, right? So don't multiply by (tacticalValue/2) but by (tacticalValue*0.1+0.8). Is this better?
Sorry, I used the apple's and banana's metaphor to point out that you are multiplying two 'things' that are not alike, which could have unexpected results. You should indeed first convert the tactical values to percentages and then use them to multiply, as you stated in your last comment. I think you'll get there just fine.
MiRAGe
+1 "maybe they have very round balls" :D
moxn
+4  A: 

Well it'll be complex, but if you want to realistically simulate a soccer match you'll need a lot more variables put into play. Not all of your team is going to be attacking, you'll have defenders, and those defenders will mitigate the strength of the opposing team's attack.

I'd recommend a flow something more like this :

1) Team A has the ball on their side of the field. It will attempt to score. Generate a table from 1-100 (0-99) and populate it with the following factors : Player from team A's skill, Opposing Player's defensive capability, distance from goal, amount of fatigue (duration of game). This table will look something like this (imagine +1 to make it simpler, so 1-100 not 0-99) :

  1. 1-50 : Player successfully advances the ball
  2. 51-60 : Player fails to advance the ball but maintains possession
  3. 61-73 : Player fails to advance the ball and loses possession
  4. 74-82 : Player passes the ball far upfield to another attacker
  5. 83-95 : Player loses possession of the ball and the enemy attempts to score
  6. 95-100 : Critical failure : The player loses possession of the ball and instantly yields a goal to the opposing team

2) In the event of 1, roll again, but now have a different set of options for being on the opposing side. In the even of 2, make the same roll on the table again. In the event of three, make the same rolls for the opposing team, but use a different table as they're closer to the goal. In the event of 4, make the rolls again but change the player's statistics to Player 2 on Team A, and assume numbers being closer to the goal. In the event of 5, roll a table where the opposing team either succeeds or fails based on the skill of a random player. In the event of six, instantly give a goal to the opposing team (in the game of soccer this happens way less than 5% of the time, it'd be more like .01%, but you could also roll on another table of critical failures that include injury, or looking stupid for ten seconds).

3) Repeat the process based on the results.

I could give you code examples, but I think you have the basic idea.

UPDATE: I think the others have answered how to factor in the weights using your method. My method would actually be different, and I'll explain the differences here...

1) Your calculations are basically assuming an attempt on goal every so many minutes, and at that point there is a complex set of calculations that attempt to model the chance that a player will or will not score. My calculations would assume that the ball is constantly in play, and moves from one set of possible outcomes to the next based on a series of statistics, rather than being considered a series of back and forth shots on the goal. This would conceptually be different as it's following the ball and not the players, and the ball would be assigned to a certain number of possibilities that are weighted by those aforementioned factors.

2) The method by which you are weighting things involves multiple weights, which as others have described increases your percentage changes over a certain amount. In my scenario, you break down the chances into a table so that there is only ever an absolute maximum of 100 possible outcomes, and then you use mt_rand to hit a number inside of this set of outcomes, which is often known as a hit table or a lottery.

In order to do this, you'd have base chances and then weight them, which gives you room to grow. For example, say the base chance of a ball to score is 10/100. If someone is a 1, this becomes 5. 2, it stays 10. 3, it becomes 15. So now, rolls 0-14 are flexibly assigned to those values, and the other values in the hit table shift to accommodate. This brings up probability issues later as you should hypothetically grow the table as well, but that passively reduces the chance of hitting as you'd go from 10/100 to 15/105 (factoring in all other possible outcomes).

If you want to continue down the path you've already started, I think a majority of what I'm saying here couldn't work, unless you simply threw these values into a table and calculated them on each attack as you already do.

If you want to stick with your current nested random statements, I'd say go with one of the solutions that the others have offered. Good luck!

NateDSaint
Thank you very much, nice and detailed explanation. This is what I'm already doing, isn't it? I just don't use tables but nested conditions with mt_rand!?
Now I've added "Integration of the tactical settings" to the question. Can you please have a look at this? Do you have a solution for my problem in that point?
Thank you! The edit has made several things clearer. But: The difference in point 1 (ball always in play) is clear. But I don't see any difference in point 2+3. You use a table and roll a dice which gives you a number. I use chances with if-clauses. This is almost the same, isn't it? And how would you code these tables? With switch statements?
[note: whoops, commented on the wrong answer, moved here] Well the point of assigning the values to the table is because there are a variety of outcomes, rather than just two outcomes that have weighted possibilities. And the way I would do it is write those values into some data structure like an an array, and load it up by looping through... for example a for loop, loading the iterator into the index, like $results[$i] = "miss" for $i 0-4, etc. Then you can do $results[rand(0,99)] to pull a result, and reuse that results table for that situation if need be. Make sense?
NateDSaint
Thank you, now I've completely understood your approach.
+1  A: 

I would suggest you convert all your probabilities to percentages:

function Chance($chance, $universe = 100)
{
    $chance = abs(intval($chance));
    $universe = abs(intval($universe));

    if (mt_rand(1, $universe) <= $chance)
    {
     return true;
    }

    return false;
}

Chance(25); // 25%
Chance(5, 1000); // 0.5%

Also I would only instantiate some probabilities with the conditions of others, example:

if ($attack === true)
{
    if (Chance(15 * $aggressivity) === true)
    {
     if (Chance(10 * $aggressivity) === true)
     {
      // red card
     }

     else
     {
      // yellow card
     }
    }
}

EDIT: I just home and I really need to go to sleep but after a quick glance at your edit I just had an idea that might interest you. What if, instead of using a adjustment value of 1, 2 or 3 don't you use the tactical position of the team? For instance, a team with a 4-4-2 would have less chances of scoring a goal against a 5-3-2 team than with a 3-3-4 team. Assuming that the placements are always triplets (X-Y-Z) it would be pretty easy to compare which team performs the best at defending, passing and scoring.

A simple formula could be something like this:

A: 4-4-2 (Defending Team)
B: 3-2-5 (Attacking Team)

The chance of B scoring a goal would be (4 / 5) ^ -1 = 0.2 = 20%, and the inverse (team A scoring) would be (3 / 2) ^ -1 = 0.5 = 50%. PS: This doesn't seem to make much sense now, but I'll try to give another look at it in the morning.

And another thing: after a red card why does the faulting team stays the same? It should get weaker (one player less) IMO.

Alix Axel
Thank you very much! :) The Chance() function is great, it's by far better than my mt_rand() solution with <=> operators. You recommend to instantiate most probabilities without conditions of others because it changes the percentage values, right? But I have to add all possibilities with conditions of others which can't happen simultaneously, haven't I?
Now I've added "Integration of the tactical settings" to the question. Can you please have a look at this? Do you have a solution for my problem in that point?
Thank you very much for the edit! I don't have different formations (4-4-2 etc) so I can't use them in tactics. The influence of the red card is done out of the function.
A: 

@ Marco...what game did you create? I am a huge soccer sim supporter and I would love to see what you were up to. Thanks

Koltrain