Drill IV or Combat IV? You decide! Includes graphs

After considering the data below, which would you say is the better promotion?

  • Generally Drill IV is the better promotion.

    Votes: 47 19.3%
  • Generally Combat IV is the better promotion.

    Votes: 76 31.3%
  • Both the Combat and Drill promotion lines have their own merits. Neither is better than the other.

    Votes: 95 39.1%
  • I'm not sure or I can't decide.

    Votes: 22 9.1%
  • Other (please explain in your reply)

    Votes: 3 1.2%

  • Total voters
    243
Yakk explained that pretty well in his post (which you referred to). He said that the code to pick the best defender could be accessed pretty often during a game turn and thus it needed to be fast. At least faster than the odds calculation algorithm. But I do think the algorithm could be improved upon in a similar way as explained by Yakk in the suggestion in his post. I agree with his assessment of how to calculate the damage that an immortal unit would receive when trying to kill another unit and that it is a good measure for the 'power' of a unit.



:confused:

What goes wrong? Does the calculation consider one extra round or one fewer round? I vaguely recall reading about this in your combat calculator mod thread.

example:
Suppose a catapult is attacking a 100HP unit and will deal 25HP per hit. To reduce the defender to 25HP of health would take 3 successful hits. However, it turns out the catapult needs to hit the defender a fourth time (for 0HP of damage) before it can withdraw. However, the game's odds calculator does not account for this, and assumes that only 3 hits are needed. As a result, the odds display over estimates the catapult's odds of retreating. But the bug only occurs when damage that needs to be done to the defender for withdrawal is a multiple of the damage done per hit by the catapult. So it happens relatively infrequently and when it does happen the incorrect odds are not that far off, but it's wrong nonetheless. This would more likely qualify as a gameplay bug than an odds-calculator bug, but for now it is treated as a calculator bug in ACO (ie. it now shows the right odds for the strange game mechanics).

By the way... you're absolutely right about the speed of the algorithm being important. I forgot about this and that would be a fine reason for not using the normal odds calculation. However the one used in the game is not all that slow IMO. I haven't really properly checked the time-complexity of either algorithm though, I admit.
 
example:
Suppose a catapult is attacking a 100HP unit and will deal 25HP per hit. To reduce the defender to 25HP of health would take 3 successful hits. However, it turns out the catapult needs to hit the defender a fourth time (for 0HP of damage) before it can withdraw. However, the game's odds calculator does not account for this, and assumes that only 3 hits are needed. As a result, the odds display over estimates the catapult's odds of retreating. But the bug only occurs when damage that needs to be done to the defender for withdrawal is a multiple of the damage done per hit by the catapult. So it happens relatively infrequently and when it does happen the incorrect odds are not that far off, but it's wrong nonetheless. This would more likely qualify as a gameplay bug than an odds-calculator bug, but for now it is treated as a calculator bug in ACO (ie. it now shows the right odds for the strange game mechanics).

Thanks for the information. And I agree, it's more of a game mechanic issue.

By the way... you're absolutely right about the speed of the algorithm being important. I forgot about this and that would be a fine reason for not using the normal odds calculation. However the one used in the game is not all that slow IMO. I haven't really properly checked the time-complexity of either algorithm though, I admit.

You're right, the normal algorithm to calculate the odds of a unit winning shouldn't be too taxing for a modern computer even if it had to do it thousands of times in the interturn. Maybe it has to do with the fact that the odds calculator wasn't a part of the game from the start. It was added in a patch and I vaguely recall that the algorithm itself was created by someone outside Firaxis.

In my opionion, Firaxis doesn't have employees who know enough about mathematics. There are various weird formulas in the game and the approximations that they use are sometimes also quite weird. If a game designer wants some game element to have certain effects and results but can't design a formula that has these effects nor can find someone to help him create such a formula then that's an issue for such a company.
 
In my opionion, Firaxis doesn't have employees who know enough about mathematics. There are various weird formulas in the game and the approximations that they use are sometimes also quite weird. If a game designer wants some game element to have certain effects and results but can't design a formula that has these effects nor can find someone to help him create such a formula then that's an issue for such a company.

Unfortunately, people who really know and understand math are exceptionally rare. I'm a high school math teacher now, but before that, I worked for about a decade for a mortgage loan software company and I was the go-to guy for any math questions that pretty much anyone in the company couldn't deal with (about 30 employees when I started in 1996 and 150 employees when I left in 2005).

The math questions that most people couldn't figure out weren't really all that hard for me, but I was still the only person in my department and one of about 5 people in the company who could deal with them. The problem wasn't that the other folks in my department couldn't do the number crunching that was involved. The problem was that they didn't understand the reasons why the number crunching worked, so when they ran into an odd situation that didn't behave the way that they expected, then they couldn't adjust the formulae to compensate for it.

One example was the Housing Expense Ratio (HER) and the Total Expense Ratio(TER). Both of these were calculated using expense and income values from after the purchase of the house.
HER = [monthly cost of primary residence]/[monthly income]

TER = [total monthly payment for all credit]/[monthly income]

Now, if you are buying a home to live in, then the new mortgage will show up in the HER and in the TER. If you are buying a rental property or a vacation property, then your first home will show up in the HER and the rental or vacation property expense will only show up in the TER. Most people were okay with this and they could deal with the calculations once they had been explained a few times and they had someone do the calculations with them a few times.

Example 1:
Buying a new home in which to live.
New Mortgage = $500 per month.
Other debt = $700 per month.
Income = $2000 per month.

HER = 500/2000 = 25%
TER = (500+700)/2000 = 60%

Example 2:
Now the person buy a Buying a rental property
New Mortgage = $700 per month.
Primary Residence = $500 per month.
Other debt = $700 per month.
Employment Income = $2000 per month.
Rental Income = 600 per month.

You might think that the rental property would show up as a $100 expense per month because 700-600 = 100, but that's not what happens. Instead, the rental income is added to income and the mortgage is added to the debt.

HER = 500/2600
TER = (700+500+700)/(2000+600) = 1900/2600

If someone is buying a vacation or rental property while they rent an apartment, however, things get a little weird. In this case, your Housing Expense is your Rent because you obviously don't have a mortgage on the house that you are living in when you're a renter. That rent doesn't show up in your Total Expense Ratio, however, because it is not actually a debt that you owe (i.e. you didn't borrow money and promise to pay it back). If you live with your parents and don't pay any rent at all, the software assumes that the person entering the data forgot to put the monthly rent in, so just put $1. :)

Example 3.
someone pays $100 per month to live with their parents and buys a rental property. Yes, this does happen. Those parents don't know when to let go of their babies. :rolleyes:

New Mortgage = $700
Monthly Rent = $100
Other Debt = $700
Income = $2000.

HER = 100/2000
TER = (700+700)/2000
Note that the $100 is not included in the TER.

If you thought that was pretty straightforward and not too difficult to understand, then you have a much better grasp of mathematics than 75% of the country. If you could actually do these calculations with real numbers now and then if you can do more of the same calculations tomorrow without needing someone to re-explain them to you again, then you're better off than 90% of the country.

I picked this example because I always thought it was pretty straightforward. It's not like calculating the Annual Percentage Rate that a mortgage has when you include points, fees, etc. That one I can certainly do on my own, but it takes a lot of thought ahead of time and I wouldn't even bother trying it with just a calculator - there are enough recursive calculations that I would break out the MS Excel spreadsheet I wrote to run the numbers.


I guess what I'm really saying here is "play the map." Um, okay, I guess not. Maybe what I'm really saying is that it's entirely reasonable that Firaxis doesn't have a whole lot of people who really have the deep understanding of probability to put a good odds calculator in the program and put a 100% complete stack defender choice algorithm and actually get the game out the door to the consumer in any reasonable amount of time. These kinds of bugs are the bugs that my former customers would sometimes ask us not to fix. They're rare, they're not hugely significant and any time you make a code change, there's a possibility that you'll break something else in the process. It's just not worth the time, expense of coding, expense of QA and expense of client acceptance testing (customer side QA) even if you discount the risk of breaking something else in the process.
 
I guess what I'm really saying here is "play the map." Um, okay, I guess not. Maybe what I'm really saying is that it's entirely reasonable that Firaxis doesn't have a whole lot of people who really have the deep understanding of probability to put a good odds calculator in the program and put a 100% complete stack defender choice algorithm and actually get the game out the door to the consumer in any reasonable amount of time. These kinds of bugs are the bugs that my former customers would sometimes ask us not to fix. They're rare, they're not hugely significant and any time you make a code change, there's a possibility that you'll break something else in the process. It's just not worth the time, expense of coding, expense of QA and expense of client acceptance testing (customer side QA) even if you discount the risk of breaking something else in the process.

That was a long post to make a simple point. :D ;)

You're right, there are a lot of people who don't understand basic mathematics. And these issues that we're talking about in this thread aren't really that important. On the other hand, there have been far more serious bugs caused by a lack of knowledge of mathematics that have really hurt the game. Bugs that wouldn't have occurred when you or PieceofMind or I or another random person with some background in even basic mathematics would have looked at those formulas for a minute of two.

I'll give 2 examples of bugs that were discovered shortly after BTS came on the market and really hurt the game experience for lots of players. I joined or started the discussion of these bugs in the bug reports forum here on this site and I'm fairly certain that the Firaxis programmers based their fixed formulas directly on these discussions.

1) The espionage missions in BTS where you spread unhappiness or unhealth in a city give 8 unhappiness or 8 unhealth which decreases by 1 per turn. In BTS version 1.00, these missions were scaled by gamespeed in both severity and length so that they gave 24 unhappiness and 24 unhealth which decreases by 1 per turn on marathon speed. Guess what, marathon players didn't really appreciate this.

(There have been more issues with gamespeed scaling in Civ4, this wasn't the first.)

2) In BTS, they introduced a new maintenance: colonial maintenance. The maintenance per city was calculated by a formula with a factor that was quadratic with respect to the number of cities on another landmass than the one where your capital was. The maximum colonial maintenance was 100. Anyone with a basic knowledge of mathematics now directly understands that when you were colonising an island with 6 cities, then this would be 4 times as expensive per city in colonial maintenance than an island of 3 cities (all other things being equal) and the formula was such that the colonial maintenance could easily reach the 100 gold per city when you colonised a sizeable island. Guess what, this again wasn't appreciated by the gamers.

There were more bugs like this when BTS first arrived on the market. While the features of the expansion pack were great, the community here thought it was really buggy. I really think, the negative publicity around the bugs cost Firaxis some sales, especially the early full priced sales. Most bugs have been squashed by now which is great, however the damage in sales income has already occurred.

So my point was more general and not really based on these smaller bugs in this thread. A game with a complex economic model like Civ4 really needs someone in the design team that takes a look at the various formulas and knows how they will behave in various circumstances.
 
If you thought that was pretty straightforward and not too difficult to understand, then you have a much better grasp of mathematics than 75% of the country. If you could actually do these calculations with real numbers now and then if you can do more of the same calculations tomorrow without needing someone to re-explain them to you again, then you're better off than 90% of the country.

It's easy for me to understand it, but the hard part for people in this case isn't the MATH, it's the rules in the first place. Finance and accounting are applied fields - the math in them is frequently trivial (certainly nothing compared to what you'd see in engineering for example). The challenge in the case of applied mathematics fields in business isn't the math, it's the rules/laws that apply it. Your example has painfully easy math only - arithmetic (arguably algebraic using TER and HER as variables, but either way very simple).

But FIN and ACC type people aren't paid for their math abilities, they're paid for their knowledge and CONSISTENTLY CORRECT application of that math, based on laws or their business knowledge.

Simply giving somebody an integration problem is higher level math than the ratios you describe, but that doesn't mean it's harder.

I make this distinction because it's important. Being good at math does not necessarily equal applying it well, and even if you're not good at the higher-level math logic and rule memory might still suffice for most applications.

Although it's a fairly good example in the context of civ nonetheless, since the combat odds calculation is also simple math with rules that are difficult for people to apply.
 
Somewhat off-topic; PoM, Roland:

The best defender code is not meant to always pick the best defender anyway (take loaded transports as an example) so it would invite arguments (perhaps) if it was changed.


I understand, but I consider the situation with loaded transports very very different. In that case, the game also considers what you would lose when the transport would sink with all units in it. A very sensible consideration. (However, there has been some discussion about this with missile carrying missile cruisers.)

I feel like a n00b, but: I wasn't aware that transports (OK, so far I've only had galleons anyway) wouldn't be the defenders in some situations. Which situations? How can I make sure that having an escort will actually work?
 
jmas,
I'm not entirely sure, but there is some code in the bestdefender function that evaluates the "asset value" of a unit. I forget how much it weighs into the calculation but it's precisely there to limit the number of times your loaded galleon will be killed when defended by caravel escorts. I don't have time right now but if you wanted to check I think it's somewhere in CvUnit.
 
It means that for instance that a caravel with no promotions will defend before your combat II galleon which is carrying 3 macemen will defend. It also means that a galleon carrying 1 maceman will defend before a galleon carrying 3 macemen will defend. In essence, the game doesn't only look at the chances of victory but also at what one would lose when the battle is lost.

I don't know the exact formulas. It's rarely relevant to know these formulas in a game (unlike many other formulas.)
 
It means that for instance that a caravel with no promotions will defend before your combat II galleon which is carrying 3 macemen will defend. It also means that a galleon carrying 1 maceman will defend before a galleon carrying 3 macemen will defend. In essence, the game doesn't only look at the chances of victory but also at what one would lose when the battle is lost.

I don't know the exact formulas. It's rarely relevant to know these formulas in a game (unlike many other formulas.)

That sounds interesting. So, for example, in a situation where your enemy has an empty Galleon and you have a Galleon with 3 Pikemen and a Galley with 2 Pikemen, the Galley would defend even though it has much bigger chance of losing its Pikemen than your Galleon has? Does only the number of units aboard matter or also their strength (probably meaning use of soldier values)?
 
That sounds interesting. So, for example, in a situation where your enemy has an empty Galleon and you have a Galleon with 3 Pikemen and a Galley with 2 Pikemen, the Galley would defend even though it has much bigger chance of losing its Pikemen than your Galleon has? Does only the number of units aboard matter or also their strength (probably meaning use of soldier values)?

PieceOfMind above mentions the asset value of the units involved. The asset value of a unit is a value that is somewhat proportional to its building cost. As said before, I don't know the exact formulas and in the above described situation, the chances of the galley winning are a lot worse while the potential losses are just slightly less. I don't know which unit would defend. You'd need the exact formulas (or test it in the game) to know.
 
Relevant parts of code:

In CvPlot...
Code:
CvUnit* CvPlot::getBestDefender(PlayerTypes eOwner, PlayerTypes eAttackingPlayer, const CvUnit* pAttacker, bool bTestAtWar, bool bTestPotentialEnemy, bool bTestCanMove) const
{
	CLLNode<IDInfo>* pUnitNode;
	CvUnit* pLoopUnit;
	CvUnit* pBestUnit;

	pBestUnit = NULL;

	pUnitNode = headUnitNode();

	while (pUnitNode != NULL)
	{
		pLoopUnit = ::getUnit(pUnitNode->m_data);
		pUnitNode = nextUnitNode(pUnitNode);

		if ((eOwner == NO_PLAYER) || (pLoopUnit->getOwnerINLINE() == eOwner))
		{
			if ((eAttackingPlayer == NO_PLAYER) || !(pLoopUnit->isInvisible(GET_PLAYER(eAttackingPlayer).getTeam(), false)))
			{
				if (!bTestAtWar || eAttackingPlayer == NO_PLAYER || pLoopUnit->isEnemy(GET_PLAYER(eAttackingPlayer).getTeam(), this) || (NULL != pAttacker && pAttacker->isEnemy(GET_PLAYER(pLoopUnit->getOwnerINLINE()).getTeam(), this)))
				{
					if (!bTestPotentialEnemy || (eAttackingPlayer == NO_PLAYER) ||  pLoopUnit->isPotentialEnemy(GET_PLAYER(eAttackingPlayer).getTeam(), this) || (NULL != pAttacker && pAttacker->isPotentialEnemy(GET_PLAYER(pLoopUnit->getOwnerINLINE()).getTeam(), this)))
					{
						if (!bTestCanMove || (pLoopUnit->canMove() && !(pLoopUnit->isCargo())))
						{
							if ((pAttacker == NULL) || (pAttacker->getDomainType() != DOMAIN_AIR) || (pLoopUnit->getDamage() < pAttacker->airCombatLimit()))
							{
								if (pLoopUnit->[B]isBetterDefenderThan[/B](pBestUnit, pAttacker))
								{
									pBestUnit = pLoopUnit;
								}
							}
						}
					}
				}
			}
		}
	}

	return pBestUnit;
}

Code:
bool CvUnit::isBetterDefenderThan(const CvUnit* pDefender, const CvUnit* pAttacker) const
{
	int iOurDefense;
	int iTheirDefense;

	if (pDefender == NULL)
	{
		return true;
	}

	TeamTypes eAttackerTeam = NO_TEAM;
	if (NULL != pAttacker)
	{
		eAttackerTeam = pAttacker->getTeam();
	}

	if (canCoexistWithEnemyUnit(eAttackerTeam))
	{
		return false;
	}

	if (!canDefend())
	{
		return false;
	}

	if (canDefend() && !(pDefender->canDefend()))
	{
		return true;
	}

	if (pAttacker)
	{
		if (isTargetOf(*pAttacker) && !pDefender->isTargetOf(*pAttacker))
		{
			return true;
		}

		if (!isTargetOf(*pAttacker) && pDefender->isTargetOf(*pAttacker))
		{
			return false;
		}

		if (pAttacker->canAttack(*pDefender) && !pAttacker->canAttack(*this))
		{
			return false;
		}

		if (pAttacker->canAttack(*this) && !pAttacker->canAttack(*pDefender))
		{
			return true;
		}
	}

	iOurDefense = currCombatStr(plot(), pAttacker);
	if (::isWorldUnitClass(getUnitClassType()))
	{
		iOurDefense /= 2;
	}

	if (NULL == pAttacker)
	{
		if (pDefender->collateralDamage() > 0)
		{
			iOurDefense *= (100 + pDefender->collateralDamage());
			iOurDefense /= 100;
		}

		if (pDefender->currInterceptionProbability() > 0)
		{
			iOurDefense *= (100 + pDefender->currInterceptionProbability());
			iOurDefense /= 100;
		}
	}
	else
	{
		if (!(pAttacker->immuneToFirstStrikes()))
		{
			iOurDefense *= ((((firstStrikes() * 2) + chanceFirstStrikes()) * ((GC.getDefineINT("COMBAT_DAMAGE") * 2) / 5)) + 100);
			iOurDefense /= 100;
		}

		if (immuneToFirstStrikes())
		{
			iOurDefense *= ((((pAttacker->firstStrikes() * 2) + pAttacker->chanceFirstStrikes()) * ((GC.getDefineINT("COMBAT_DAMAGE") * 2) / 5)) + 100);
			iOurDefense /= 100;
		}
	}

	int iAssetValue = std::max(1, getUnitInfo().getAssetValue());
	int iCargoAssetValue = 0;
	std::vector<CvUnit*> aCargoUnits;
	getCargoUnits(aCargoUnits);
	for (uint i = 0; i < aCargoUnits.size(); ++i)
	{
		iCargoAssetValue += aCargoUnits[i]->getUnitInfo().getAssetValue();
	}
	iOurDefense = iOurDefense * iAssetValue / std::max(1, iAssetValue + iCargoAssetValue);

	iTheirDefense = pDefender->currCombatStr(plot(), pAttacker);
	if (::isWorldUnitClass(pDefender->getUnitClassType()))
	{
		iTheirDefense /= 2;
	}

	if (NULL == pAttacker)
	{
		if (collateralDamage() > 0)
		{
			iTheirDefense *= (100 + collateralDamage());
			iTheirDefense /= 100;
		}

		if (currInterceptionProbability() > 0)
		{
			iTheirDefense *= (100 + currInterceptionProbability());
			iTheirDefense /= 100;
		}
	}
	else
	{
		if (!(pAttacker->immuneToFirstStrikes()))
		{
			iTheirDefense *= ((((pDefender->firstStrikes() * 2) + pDefender->chanceFirstStrikes()) * ((GC.getDefineINT("COMBAT_DAMAGE") * 2) / 5)) + 100);
			iTheirDefense /= 100;
		}

		if (pDefender->immuneToFirstStrikes())
		{
			iTheirDefense *= ((((pAttacker->firstStrikes() * 2) + pAttacker->chanceFirstStrikes()) * ((GC.getDefineINT("COMBAT_DAMAGE") * 2) / 5)) + 100);
			iTheirDefense /= 100;
		}
	}

	iAssetValue = std::max(1, pDefender->getUnitInfo().getAssetValue());
	iCargoAssetValue = 0;
	pDefender->getCargoUnits(aCargoUnits);
	for (uint i = 0; i < aCargoUnits.size(); ++i)
	{
		iCargoAssetValue += aCargoUnits[i]->getUnitInfo().getAssetValue();
	}
	iTheirDefense = iTheirDefense * iAssetValue / std::max(1, iAssetValue + iCargoAssetValue);

	if (iOurDefense == iTheirDefense)
	{
		if (NO_UNIT == getLeaderUnitType() && NO_UNIT != pDefender->getLeaderUnitType())
		{
			++iOurDefense;
		}
		else if (NO_UNIT != getLeaderUnitType() && NO_UNIT == pDefender->getLeaderUnitType())
		{
			++iTheirDefense;
		}
		else if (isBeforeUnitCycle(this, pDefender))
		{
			++iOurDefense;
		}
	}

	return (iOurDefense > iTheirDefense);
}
 
Oops! My post should have read that I wasn't aware that loaded ships WOULD act as defenders in some situations (my erroneous inference from previous posts). Apparently they will not unless their "cargo" is considered to have lower value than another loaded ship. Thank you guys for explaining. :)

While I'm somewhat familiar from code from studying programming years ago, I don't think I'm seeing all the implications at a glance. I do think Pikkis' galley vs. galleon question is an interesting one, though I haven't had that situation in-game so far.
 
You're right, the normal algorithm to calculate the odds of a unit winning shouldn't be too taxing for a modern computer even if it had to do it thousands of times in the interturn. Maybe it has to do with the fact that the odds calculator wasn't a part of the game from the start. It was added in a patch and I vaguely recall that the algorithm itself was created by someone outside Firaxis.
I didn't know this. It does say the function was created by Deep0, whoever that is. When you say it was added in a patch, which patch? Was it while the game was in beta or after release? I remember the vanilla unpatched game had severe problems with the odds (particularly for first strikes which are easily the most complicating part of the odds calculation).

In my opionion, Firaxis doesn't have employees who know enough about mathematics. There are various weird formulas in the game and the approximations that they use are sometimes also quite weird. If a game designer wants some game element to have certain effects and results but can't design a formula that has these effects nor can find someone to help him create such a formula then that's an issue for such a company.

I agree they should have a minimum of one employee who can handle this sort of thing in the game, as it is important in the long run. But maybe we are biased, insisting on employment opportunities for mathematicians! :D
 
Oops! My post should have read that I wasn't aware that loaded ships WOULD act as defenders in some situations (my erroneous inference from previous posts). Apparently they will not unless their "cargo" is considered to have lower value than another loaded ship. Thank you guys for explaining. :)

While I'm somewhat familiar from code from studying programming years ago, I don't think I'm seeing all the implications at a glance. I do think Pikkis' galley vs. galleon question is an interesting one, though I haven't had that situation in-game so far.

I've really no experience reading code, but as far as I can see in the code posted by PiecOfMind, the game calculates a defence value for every defender and when that defender is a loaded transport ship, it multiplies the defence value with:

asset value transport/(asset value transport + asset value cargo).

The basic defence value would be twice as high for the galleon as for the galley because it has a strength rating of 4 instead of 2, making it a more likely defender in basis.

The cargo multiplier depends on the asset value of the ships and the cargo.
The asset value of a galley is 1, a galleon 2 and a pikeman 3. So this quotient will be 1/7 for the galley holding 2 pikemen and 2/11 for the galleon holding 3 pikemen (and 1/7 < 2/11). So the cargo multiplier also makes the galleon a more likely defender because the galleon itself is relatively more valuable compared to its cargo(the loss of the galleon is higher relative to its cargo than the galley relative to its cargo).

So the galleon would defend, due to its higher strength and due to its higher value relative to its cargo.

However, as I have no experience reading code, I could be making mistakes interpreting the code.

I didn't know this. It does say the function was created by Deep0, whoever that is. When you say it was added in a patch, which patch? Was it while the game was in beta or after release? I remember the vanilla unpatched game had severe problems with the odds (particularly for first strikes which are easily the most complicating part of the odds calculation).

I had to look up old patch changes for that (google is your friend). It was added in vanilla Civ4 patch 1.52. The game didn't have an odds calculator before that, just the strength A vs strength B indication plus maybe some first strikes and hit points.

I agree they should have a minimum of one employee who can handle this sort of thing in the game, as it is important in the long run. But maybe we are biased, insisting on employment opportunities for mathematicians! :D

Nah, I'm never biased. I'm a mathematician. I can calculate whether a die is biased and so I'd also know when I would be biased myself! I'm not biased.
Quod erat demonstrandum.
 
Top Bottom