Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Soccer simulation for a game

Tags:

php

simulation

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.


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!


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.