Stat issue - comparing list against itself - c#

This one is for you CompSci or stats people. Can you please tell me, if theList contains 72,786 "things," what the value of compareCount will be at the end of the loops? I'm thinking it's 72,786^2-1 but it's been soo long since this old brain worked like that. Much obliged for your time and assistance!
List<thing> theList = new List<thing>();//list contains 73,786 "things"
private void compare()
{
int compareCount = 0;
for(int i = 0; i < theList.Count-1; i++)
{
for(int comp = i + 1; comp < theList.Count; comp++)
{
compare(theList[i], theList[comp]);
compareCount++;
}
}
}

The compareCount in your code will have the value (72786^2 - 72786) / 2 = 2648864505. I've confirmed that by running it. As it is written now, there is no need to have the call compare(theList[i], theList[comp]) in the inner loop (as it doesn't influence the count in any way).
Here's how I remember the (n^2 - n)/2 formula: a round robin tournament with n players, each of them meeting all other players exactly once.
The match plan is a square with n rows and columns (n * n = n^2 combinations). Since a player doesn't play against himself the n matches on the diagonal from upper left to lower right must be subtracted (n^2 - nmatches left now). Pairings of player A against player B in the triangle above the diagonal are the same as pairings of B against A in the triangle below (there are (n^2 - n)/2 of such pairings). Subtracting this number from n^2 - n gives the final result of (n^2 - n)/2 possible matches.

Related

Dealing Cards game: x cards per y over z Amount of Players Algorithm in C#

I've been trying to come up with an algorithm which deals, as the title states,
X amount of Cards, per Y amount of Cards, over Z amount of Players of a normal (52 piece) Deck of Cards which is sorted or unsorted. I've been walking into a wall for the past few hours to come up with a working solution, while also Googling to find similar problems. Unfortunately without success, hence this question.
An example would be: dealing 2 Cards, per 1, over 2 Players would result in
Player 1 receiving 1 card
Player 2 receiving 1 card
Player 1 receiving 1 card
Player 2 receiving 1 card
Until now I have a solution with which I'm able to run my application, although the actual dealing algorithm isn't keeping the 'per' parameter into account. It will deal the right amount of cards to the Y amount of players, although each player will receive the total amount to be dealed in 1 go..
I was wondering if anyone here had to handle a similar problem in the past? Or could guide me into the right direction? :/
public List<Card>[] Deel(int per, int players, int cards)
{
_currentCard= 0;
List<Card>[] output = new List<Card>[players];
if (_cardsDistributed < _deck.Count)
{
for (int i = 0; i < players; i++)
{
List<Card> hand = new List<Card>();
for (int j = 0; j < cards; j++)
{
_currentCard= 0;
hand.Add(_deck[_currentCard]);
_deck.Remove(_deck[_currentCard]);
_cardsDistributed++;
}
output[i] = hand;
}
return output;
}
else
return null;
}
One way to think about this is to get a deck of cards and do it yourself, by hand, and write down the steps. For example, you have three players and you want to deal each player four cards, two at a time. So what do you do?
You take the deck in hand, hold it over the first player's pile, and deal two cards. The code for that is pretty simple:
player = 1
for i = 1 to 2
deal next card to player
Then you move to the second player's pile and deal two cards, and you do the same thing for the third player. So you need a loop to go through the players:
for player = 1 to 3
for i = 1 to 2
deal next card to player
At this point you've dealt two cards to each of the three players.
If you want to deal X cards Y at a time, and Y is smaller than X, then you need to go around to each player multiple times. How many? Well, how many times does Y go into X? The answer is X/Y.
If you were doing this by hand, you would start over at player 1, deal him two cards, move on to player 2, etc. Adding that in code is simple:
numRounds = 4/2
for round = 1 to numRounds
for player = 1 to 3
for card = 1 to 2
deal next card to player
Now, replace the constant values with X, Y, and Z, and try it with some other combination by following those exact steps. Deal six cards to each player, three at a time. Did it work? Try a few other combinations to verify that the steps you wrote down always work.
Once you've determined that the algorithm you've developed works, then writing the code to implement it on the computer is easy. There are, of course, some minor details like how to deal a card, but those are easy compared to figuring out the overall approach to the problem.
I was fortunate that I discovered this approach to problem solving early in my education. Casting an algorithmic problem into physical terms lets me build a model that I can play with, and write down the steps I took to solve the problem. After that, writing the program is a simple matter of duplicating those steps in code. It doesn't work for all problems, but it's very effective for a large number of different problems that you will encounter.
If I understood your question correctly you need something like this:
public List<Card>[] Deel(int per, int players, int cards)
{
List<Card>[] output = new List<Card>[players];
// init hand for each player
for (int i = 0; i < players; i++)
{
output[i] = new List<Card>();
}
// assume the number of cards is divided by 'per' without a remainder
// otherwise you need one more round to deal rest (cards % per) cards
int rounds = cards / per;
for (int round = 0; round < rounds; round++)
{
for (int i = 0; i < players; i++)
{
for (int j = 0; j < per; j++)
{
if (_deck.Count > 0)
{
output[i].Add(_deck[0]);
_deck.Remove(_deck[0]);
_cardsDistributed++;
}
else
{
// should throw an exception because the deck contains no more cards
// or maybe you need to check it before dealing
}
}
}
}
return output;
}

c# Normalized power for Polar cycle

List<int> NPower = new List<int>();
List<double> list = new List<double>();
try
{
for (int i = 1; i < dataGridView1.Rows.Count; i++)
{
for (int n = 0; n < i + 30; n++)
{
NPower.Add(Convert.ToInt32(dataGridView1.Rows[i + n].Cells[6].Value));
}
}
average = NPower.Average();
total = Math.Pow(average, 4);
NPower.Clear();
}
catch (Exception)
{
average = NPower.Average();
NP = Convert.ToInt32(Math.Pow(average, (1.0 / 3.0)));
label19.Text = "Normalised Power: " + NP.ToString();
NPower.Clear();
}
Hi so i'm trying to calculate the normalized power for a cycling polar cycle. I know that for the normalized power you need to:
1) starting at the 30 s mark, calculate a rolling 30 s average (of the preceeding time points, obviously).
2) raise all the values obtained in step #1 to the 4th power.
3) take the average of all of the values obtained in step #2.
4) take the 4th root of the value obtained in step #3.
I think i have done that but the normalized power comes up with 16 which isnt correct. Could anyone look at my code to see if they could figure out a solution. Thankyou, sorry for my code i'm still quite new to this so my code might be in the incorrect format.
I'm not sure that I understand your requirements or code completely, but a few things I noticed:
Since you're supposed to start taking the rolling average after 30 seconds, shouldn't i be initialized to 30 instead of 1?
Since it's a rolling average, shouldn't n be initialized to the value of i instead of 0?
Why is the final result calculated inside a catch block?
Shouldn't it be Math.Pow(average, (1.0 / 4.0)) since you want the fourth root, not the third?

Setting random variables C# that equal add up to a total

I'm creating a game in which someone opens a chest and the chest will give them a random prize. The maximum I can give out is 85,000,000 in 10,000 chests which is 8,500 average however I want some to make it so some chests will be below this value and above and to be able to set a min lose of 2,500 and max win 250,000 but still get the total value of 85,000,000.
I'm really struggling to come up with an algorithm for this using my C# knowledge.
Here goes some OOP. You have Player class. Which stores some info - amount of gold he has, chests left to open, and total amount of gold in chests he will find.
public class Player
{
private int gold = 0;
private int goldLeftInChests = 85000000;
private int chestsToOpen = 10000;
private Random random = new Random();
public void OpenChest()
{
if (chestsToOpen == 0)
return; // or whatever you want after 10000 chests.
int goldInChest = CalculateGoldInNextChest();
goldLeftInChests -= goldInChest;
chestsToOpen--;
gold += goldInChest;
}
private int CalculateGoldInNextChest()
{
if (chestsToOpen == 1)
return goldLeftInChests;
var average = goldLeftInChests / chestsToOpen;
return random.Next(average);
}
}
When next chest is opened, gold in chest is calculated and player data ajusted - we add some gold to player and reduce total amount of gold in chests, and chests left to open.
Calculating gold in a chest is very simple. We get average amount left and calculate number between 1 and average. First time this value will always be below 8500. But next time average will be little bit bigger. So player will have chance to find more than 8500. If he will be unlucky again, average will grow. Or it will be reduced if palyer gets lot of gold.
UPDATE: As #Hans pointed, I didn't count min and max restrictions for gold in chests. Also there is a problem in #Hans solution - you should move gold between 10000 chests lot of time to get some chests close to 250000 value. And you have to fill and keep all 10000 values. Next problem I thought about was random numbers distribution in .NET. Values have equal probability on all interval we are using. So if we are generating value from 2500 to 250000, chance that we'll get value around 8500 (average) is like 12000 (8500±6000) vs 235500 (250000-12000-2500). That means generating default random numbers from given range will give you lot of big numbers in the begining, and then you will stick near lowest boundary (2500). So you need random numbers with different distribution - Gaussian variables. We still want to have 8500 gold with highest probablity, and 250000 with lowest probability. Something like that:
And last part - calculation. We need to update only one method :)
private int CalculateGoldInNextChest()
{
const int mean = 8500;
var goldPerChestRange = new Range(2500, 250000);
var averageRange = new Range(mean - 2500, mean + 2500);
if (chestsToOpen == 1)
return goldLeftInChests;
do
{
int goldInChest = (int)random.NextGaussian(mu: mean, sigma: 50000);
int averageLeft = (goldLeftInChests - goldInChest) / (chestsToOpen - 1);
if (goldPerChestRange.Contains(goldInChest) && averageRange.Contains(averageLeft))
return goldInChest;
}
while (true);
}
Note: I used range to make code more readable. Running tests several times produces nice top values more than 200000.
pseudocode algoritm:
use an array of chests
index of array is chest number; length of array is amount of chests
value in array is amount in chest at that index
initial value is total amount divided by number of chests
now repeat a number of times (say: 10 times the number of chests)
get two random chests
work out the maximum amount you can transfer from chest 1 to chest 2, so that 1 doesn't get below the minimum and 2 doesn't get above the maximum
get a random value below that maximum and transfer it
Now try and implement this in C#.
This should be a good starting point. Each chest gets filled randomly with the limits adapting to make sure the remaining chests can also get valid values.
Random rand = new Random();
int[] chests = new int[numOffChests];
int remaining = TotalValue;
for(int i = 0; i < numOffChests; i++)
{
int minB = Math.Max(remaining / (numOffChests - i), maxChestValue);
int maxB = Math.Min(remaining - (numOffChests - i * minChestValue), maxChestValue);
int val = rand.Next(minB, maxB);
remaining -= val;
chests[i] = val;
}
The distribution has to be heavily skewed to get that range of values with that mean. Try an exponential formula, X=exp(a*U+b)+c where U is uniform on [0,1]. Then the conditions are
-2,500 = exp(b)+c
250,000 = exp(a+b)+c
8,500 = integral(exp(a*u+b), u=0..1)
= exp(b)/a*(exp(a)-1)+c
= 252,500/a+c
which gives the two equations
250,000+2,500*exp(a) = c*(1-exp(a))
8,500 = 252,500/a+c
A bit of graphical and numerical solution gives the "magic" numbers
a = 22.954545,
b = -10.515379,
c = -2500.00002711621
Now fill 10,000 chests according to that formula, compute the sum over the chest prices and distribute the, with high probability small, excess in any pattern you like.
If you want to hit the upper and lower bounds more regularly, increase the bounds at the basis of the computation and cut the computed value if outside the original bounds.
I assume that a probabilistic function gives the chance of a win/lose value V to occur. Let's say that the probability for V is proportional to (250000-V)**2, giving fewer chances to get high prizes.
To simplify some rounding issues, let's also assume that win/lose are multiple of 100. You may then make the following (untested) computations:
int minwin = -2500 ;
int maxwin = 250000;
int chestcount = 10000;
int maxamount = 85000;
// ----------- get probabilities for each win/lose amount to occur in all chests ----------
long probtotal = 0 ;
List<long> prob = new List<long> ;
for (long i=minwin;i<=maxwin;i++) if (i%100==0)
{ long ii=(maxwin-i)*(maxwin-i) ; prob.Add((float)ii) ; probtotal+=ii ; }
for (int i=0;i<prob.Count;i++) prob[i]=prob[i]/(probtotal) ;
for (int i=0;i<prob.Count;i++)
Console.writeLine("Win/lose amount"+((i-minwin)*100).ToString()+" probability="+(proba[i]*100).ToString("0.000")) ;
// Transform "prob" so as to indicate the float count of chest corresponding to each win/lose amount
for (int i=0;i<prob.Count;i++) prob[i]=prob[i]*chestcount ;
// ---------- Set the 10000 chest values starting from the highest win -------------
int chestindex=0 ;
List<int> chestvalues = new List<int>();
float remainder = 0 ;
int totalwin=0 ;
for (int i=0;i<prob.Count;i++)
{
int n = (int)(prob[i]+remainder) ; // only the integer part of the float ;
remainder = prob[i]+remainder-n ;
// set to n chests the win/lose amount
int curwin=(i-minwin)*100 ;
for (int j=0;j<n && chestvalues.count<chestcount;j++) chestvalues.Add(curwin) ;
totalwin+=curwin ;
}
// if stvalues.count lower than chestcount, create missing chestvalues
for (int i=chestvalues.Count;i<chestcount;i++) chestvalues.Add(0) ;
// --------------- due to float computations, we perhaps want to make some adjustments --------------
// i.e. if totalwin>maxamount (not sure if it may happen), decrease some chestvalues
...
// --------------- We have now a list of 10000 chest values to be randomly sorted --------------
Random rnd = new Random();
SortedList<int,int> randomchestvalues = new SortedList<int,int>() ;
for (int i=0;i<chestcount;i++) randomchestvalues.Add(rnd.Next(0,99999999),chestvalues[i]) ;
// display the first chests amounts
for (int i=0;i<chestcount;i++) if (i<234)
{ int chestamount = randomchestvalues.GetByIndex(i) ; Console.WriteLine(i.ToString()+":"+chestamount) ; }
}

Get 3 most common Point from List<Point>

I have a quick question that I haven't found out how to do efficiently (in C#).
I have a list array of Points (X,Y). I need to find which 3 points are the tightest cluster. It's for a mapping project.
What would the best way to do this be? There's only about 6 to 9 items in the list.
Thanks in advance.
Cheers!
For such small numbers, the brute force method should work just fine. With six points, there are 20 possible combinations of three points. With 9 points, there are 84 possible combinations. I wouldn't recommend this approach for a lot of points, but with just a handful, it's going to be plenty fast enough and it's dead simple to write.
You can easily generate the combinations:
for (int i = 0; i < points.Length - 2; ++i)
{
for (j = i + 1; j < points.Length - 1; j++)
{
for (k = j + 1; k < points.Length; k++)
{
// Here, your three points are
// points[i], points[j], and points[k]
// compute "tightness" and store
}
}
}
You'll need a structure to hold your combinations:
struct PointGroup
{
public readonly int i;
public readonly int j;
public readonly int k;
public readonly double tightness;
public PointGroup(int i, int j, int k, double tight)
{
this.i = i;
this.j = j;
this.k = k;
this.tightness = tight;
}
}
If you create one of those structures for each group and store them in an array, you can simply sort the array and take the best three.
Your bigger problem is coming up with a definition of "tight group." Also, you have to decide if a point can be in more than one of those "tightest" groups. Three possible ways to define tightness are:
The sum of the distances between the points is minimized.
The average distance from each point to the center of the group is minimized.
The circumference of the triangle formed by the three points is minimized.
Undoubtedly there are more.
If the points are not identical, this becomes a form of cluster analysis.
There are various algorithms that differ in how they measure and "cluster" points, though with only a few points, a brute force approach might be the easiest... You could just measure the distance between each pair of points, and sort...
You can simplify the problem as follows:
Don't check a Point against itself; distance is zero.
Exploit symmetry: distance from Point i to Point j is the same as Point j to Point i
Those eliminate a number of combinations.
But, given those, you have to calculate the distance between each pair and sort.

Random Probability Selection

Say I have 10 prizes to give to 100 people. Each person gets a shot, one at a time. So if the first person fails to win a prize, the probability goes up, 10 in 99, and so one... Also all 10 prizes MUST go.
What would be the best way to write this in such a way that by the end if there is still a prize left, that person would have a 1 in 1 chance to get a prize...
What I was thinking like this:
int playersLeft = 100
int winners = 0
while (winners < 10)
winners += (random.Next(playersLeft--)<(10-winners)) ? 1 : 0;
I wanted to know if there was a better or more straight forward way to do it. I know it seems simple but this simple task is part of a very important aspect of the app and it must be right.
TO CLARIFY: Why I want to do something like this:
In reality there is an unlimited number of players, each with an X in Y probability to win, say 10/100 = 10%. However if I leave it to the random number generator, there is a chance that in 100 players, only 9 would win, or worst, 11. In my app, I must assure that no more and no less than 10 players for every 100 will win.
Should every person have equal chances of winning? In that case why not just select randomly 10 distinct numbers 1-100 and then pretend to do it in order?
var winners = new HashSet<int>();
while(winners.Count < 10)
{
var number = random.Next(100);
if(!winners.Contains(number)) winners.Add(number);
}
for(i = 0; i < 100; i++)
{
if(winners.Contains(i)) Console.WriteLine("{0} won!!!", i);
else Console.WriteLine("{0} didn't win, sorry...", i);
}
I have thought about this some more and have come up with the following. We can give the first guy a fair shot at winning and then if the rest of the rewards are distributed fairly among the rest of the people (no matter if he wins or loses) the whole thing will be fair. Of course that's far from formal proof, so feel free to correct me. The following should give a fair system:
int prizes = 10;
for(int i = 100; i >= 1; i++)
{
var result = random.Next(people);
if(result < prizes)
{
Console.WriteLine("{0} won", i);
prizes--;
}
}
Edit: Proof this works:
The first person trivially has n/k chance of winning (n being the number of prizes, k being the number of people.
Let's assume we distribute the remaining prizes fairly among the rest of the people. In that case they will have with probability n/k, n-1 prizes distributed between them and with probability (k-n)/k, n prizes. That adds up to (n*(n-1))/k + (n*(k-n))/k = n*(k-1)/k on average which is their fair share of the prizes.
We use the same method to either distribute n-1 or n prizes among the k-1 people. Q.E.D.
This will give you the behavior of forcing the probability of a winner to go to 1.0 as the number of people shrinks. However, as #obrok pointed out, the probability of a person winning a prize depends on their rank in the list of 100 people.
This is actually the same algorithm that is used for "N choose K" subset selection. http://mcherm.com/permalinks/1/a-random-selection-algorithm
int prizes = 10;
int people = 100;
while ( prizes > 0 ) {
double probOfWin = (double) prizes / people;
if ( random.NextDouble() <= probOfWin ) {
prizes--;
}
people--;
}
The perfectly fair way to do is to generate a random number from 1 to (100! / (90! * 10!)) (since this is the number of possible combinations of prizewinners) and use that to award the prizes.
However it's easier to use some multiple of that number, such as the number of permutations of prizewinners, which is (100! / 90!). One way of doing this is to populate an array of 100 integers but remove the winning integer from the array each time (swapping it with the last non-winning integer is the easiest way to achieve this).
Your algorithm effectively requires randomness of 100! so it is much less efficient, although I believe it is still perfectly fair.

Categories

Resources