Not sure of the best way to go about this?
I want to create a tournament bracket of 2,4,8,16,32, etc teams.
The winner of the first two will play winner of the next 2 etc.
All the way until there is a winner.
Like this
Can anyone help me?
OK so more information.
Initially I want to come up with a way to create the tournament with the 2,4,8,16,etc.
Then when I have all the users in place, if they are 16 players, there are 8 fixtures.
At this point I will send the fixture to the database.
When all the players that won are through to the next round, i would want another sql query again for the 2 winners that meet.
Can you understand what i mean?
I did something like this a few years ago. This was quite a while ago and I'm not sure I'd do it the same way (it doesn't really scale to double-elimintation or the like) How you output it might be a different question. I resorted to tables as it was in 2002-2003. There are certainly better techniques today.
The amount of rounds in the tournament is log2(players) + 1, as long as players is one of the numbers you specified above. Using this information you can calculate how many rounds there are. The last round contains the final winner.
I stored the player information something like this (tweek this for best practices)
Tournament
Name
Size
Players
Tournament
Name
Position (0 to tournament.size - 1)
Rounds
Tournament
Round
Position (max halves for each round)
Winner (player position)
Note in all my queries below, I don't include the "Tournament = [tournament]" to identify the tournament. They all need it.
It's rather simple to query this with one query and to split it out as needed for the different rounds. You could do something like this to get the next opponent (assuming there is one). For round 1, you'd simply need to get the next/previous player based on if it was even or odd:
SELECT * FROM Players WHERE Position = PlayerPosition + 1
SELECT * FROM Players WHERE Position = PlayerPosition - 1
For the next round, if the user's last Round.Position was even, you'll need to make suer that the next position up has a winner:
SELECT Player FROM Rounds WHERE Position = [playerRoundPosition] - 1
If not, the next player isn't decided, or there's a gap (don't allow gaps!)
If the users last Round.Position was odd, you'll need make sure there's a user below them AND that there's a winner below them, otherwise they should automatically be promoted to the next round (as there is no one to play)
SELECT COUNT(*) FROM Players WHERE Position > [Player.Position]
SELECT Player FROM Rounds WHERE Position = [playerRoundPosition] + 1
On a final note, I'm pretty sure you could use something like the following to reduce the queries you write by using something like:
SELECT Player FROM Rounds WHERE Position + Position % 2 = [playerRoundPosition]
SELECT Player FROM Rounds WHERE Position - Position % 2 = [playerRoundPosition]
Update:
Looking over my original post, I find that the Rounds table was a little ambigous. In reality, it should be named matches. A match is a competition between two players with a winner. The final table should look more like this (only the name changed):
Matches
Tournament
Round
Position (max halves for each round)
Winner (player position)
Hopefully that makes it a bit more clear. When the two players go up against each other (in a match), you store that information in this Matches table. This particular implementation depends on the position of the Match to know which players participated.
I started numbering the rounds at 1 because that was more clear in my implementation. You may choose 0 (or even do something completely different like go backwords), if you choose.
In the first round, match 1 means players 1 and 2 participated. In match 2, the players 3-4 participated. Essentially the first round is simply players position and position + 1 participated. You could also store this information in the rounds table if you need more access to it. Every time I used this data in the program, I needed all the round and player information anyways.
After the first round, you look at the last round of matches. In round 2, match 1, the winners from matches 1 and 2 participate. Round 2, match 2, the winners from match 3 and 4 participate. It should look pretty familiar, except that it uses the match table after round 1. I'm sure there's a more efficent way to do this repetitive task, I just never got enough time to refactor that code (it was refactored, just not that much).
Use arrays and remove the losing teams from the main array. (But keep 'em on a separate array, for reference and reuse purposes).
Related
Consider I am writing a program to objectively select a winner in a competition. There are 'n' human judges secretly assigning a 1st, 2nd, 3rd position ranking to the top three candidates from a pool of 'm' candidates.
The program must then go through the judges decisions, and based on weights assigned to 1st place, 2nd place and 3rd place, each candidate will be rated based on the number of 1st, 2nd, and 3rd place votes they received, multiplied by the appropriate rating for each finishing position.
However, at the start, the program has no idea of what weights are appropriate, so I have created an automated "program" that is intended to "discover" the proper weights based on how the judges would pick the winner from a hypothetical situation.
I present a table where the horizontal axis contains the finishing position, and the judges' codes (e.g. Judge W, Judge X, Judge Y, Judge Z). The vertical axis has three rows (1st place, 2nd place, 3rd place), and at the intersection of each Judge/Row, I have randomly generated a candidate ID (from the set A through F).
After rendering the table, I then ask the judge who THEY would have chosen as the winner (the judge has the option to PASS if there is not sufficient information to choose).
After the judges run through an appropriate number of scenarios, I wish to now take the results of the various runs and use that information to determine the "best fit" for the weighting of 1st, 2nd, and 3rd positions.
Let's say one of the hypothetical grids looks like this:
<table border="1"><tbody><tr><th>Position</th><th>Judge 'W'</th><th>Judge 'X'</th><th>Judge 'Y'</th><th>Judge 'Z'</th></tr><tr><td>1st</td><td><center>A</center></td><td><center>F</center></td><td><center>C</center></td><td><center>B</center></td></tr><tr><td>2nd</td><td><center>D</center></td><td><center>B</center></td><td><center>E</center></td><td><center>D</center></td></tr><tr><td>3rd</td><td><center>C</center></td><td><center>E</center></td><td><center>B</center></td><td><center>C</center></td></tr></tbody></table>
and the human judge picks candidate "B" as the winner. My program should react by calculating the (w1 + w2 + w3) > (w1 + 2w3) (i.e. B better than C) and (w1 + w2 + w3) > (2 w2) (i.e. B better than D), etc.
From these various algebraic comparisons, over a number of "hypothetical scenarios", I want to be able to calculate the optimum values for w1, w2 and w3. And then, at some point when there is enough "good" data, I want to be able to use these "discovered" weights to go back over the training data an identify areas where perhaps the human judges were mistaken.
I am using PHP as the programming language and don't know which functions or possible existing libraries are appropriate to solve this kind of "fuzzy" equation.
I'm looking for some direction to help me tackle this problem.
Thank you for your assistance.
For the winning candidate count how many times he appears in each position, then do the same for all the other candidates. Then write the following formula for each candidate:
GoodForJ=w1*nw1+w2*nw2+w3*nw3>w1*nj1+w2*nj2+w3*nj3
Where nw1-3 are the times the winner appears in each position and nj1-3 are the times the j candidate appears in each position.
If goodForJ is true for all the candidates this means that the tuple of weights is good. Now you just have to try a bounch of weights combinations and find out which one fits. Trying all combinations of weights between 1 and 10 requires 1000 iterations.
To make things a bit fuzzier, for each try you could count how many timrs goodForJ is true and choose the weights that produces the highest score.
I've been trying for several hours to make a random walk (a path) like this one.
From top to down.
x 1 x
x 2 3
x x 4
7 6 5
8 x x
9 10 x
My greatest difficulty is to calculate the displacement from right to left because the cycles (for, while..) go from left to right.
I am not proficient in math, so I'm using a simple approach.
I have two arrays. One with the position of the previous row.
$previousRow=array(1=>"x",2=>"1",3=>"x");
One with the current row I have to fill.
$currentRow=array(1=>"",2=>"",3=>"");
$p //Is the current position. 1, 2 or 3. Example $currentRow[$p]
$last //the last number that increases each time the path has a new step.
I'm using some cycles and conditions to set the displacement.
Is this approach wrong?
EDIT: further specifications as requested from comments:
Start point is located in the middle point of the first row
End point is located in the last row
End point can be located in any column of the last row
per each field you have three possibilities: left, right, forward.
some cases reduce this, e.g. there is no field to the left or right or that field was visited already.
so find out about possible moves, pick one at random and go on.
I'm trying to perform some basic analysis on Lotto results :)
I have a database that looks something like:
id|no|day|dd|mmm|yyyy|n1|n2|n3|n4|n5|n6|bb|jackpot|wins|machine|set
--------------------------------------------------------------------
1 |22|mon|22|aug|1999|01|05|11|29|38|39|04|2003202| 1 | Topaz | 3
2 |23|tue|24|aug|1999|01|06|16|21|25|39|03|2003202| 2 | Pearl | 1
That's just an example. So, n1 to n6 are standard balls in the lottery and bb stands for the bonus ball.
I want to write a PHP/SQL code that will display just one random sequence of numbers that have yet to come out. However, If the numbers 01, 04, 05, 11, 29, 38 and 39 have come out, I don't want the code to print out them numbers but just in a different order, as in theory them set of numbers are already winning numbers.
I just can't get my head around the logic of this. I'd appreciate any help.
Thanks in advance
Assuming that the balls are stored in ascending order in your database like the examples you've given, you could just generate a random sequence of 6 numbers, sort them and then generate 1 random bonus number. Once you've done that it would just be a matter of doing a simple SQL query into your database and seeing if it comes back with a result:
$nums=...//generate your 6 numbers plus bonus number here
sort($nums);
$mysqli=new mysqli('...','...','...','...');
$stmt=$mysqli->prepare("SELECT * FROM table
WHERE n1=? AND n2=? AND n3=? AND n4=? AND n5=? AND n6=? AND bb=?");
$stmt->bind_param('iiiiiii', $nums[0], $nums[1], $nums[2], $nums[3], $nums[4], $nums[5], $nums[6]);
$stmt->execute();
$stmt->store_result();
if($stmt->num_rows==0)
//your numbers have not been drawn before - return them
else
//otherwise loop round and try again
As long as both list of numbers (but not the bonus ball) are sorted you won't have any problems with a different ordering of an already drawn set of numbers.
This will become less efficient as your database of previous draws gets fuller, but I don't think you'll have to worry about that for a few decades. :-)
What about sorting each already drawn result (each row) in some order, ascending maybe, then sort the set of already drawn results (all rows)? Then you will have a easy to look up in list in which you can see what is left to be drawn.
Say for example you want a never drawn set before? You would just have to loop through the list until you spot a "hole", which would be a never before drawn set. If you would like to optimise further you could store at what index you last found a "hole" as well. Then you would never need to loop through the same part of the list twice, and you could even abandon "completed" parts of the list to save disk space, or if you would like the new number you come up with to seam random you could start at a random offset in the list.
To do this effectively you should make an extra column to store the pre-sorted set. For example if you have (5, 3, 6, 4, 1, 2) that column could contain 010203040506. Add in enough zeros so that the numbers occur on a fixed offset basis.
There are a few hundred of book records in the database and each record has a publish time. In the homepage of the website, I am required to write some codes to randomly pick 10 books and put them there. The requirement is that newer books need to have higher chances of getting displayed.
Since the time is an integer, I am thinking like this to calculate the probability for each book:
Probability of a book to be drawn = (current time - publish time of the book) / ((current time - publish time of the book1) + (current time - publish time of the book1) + ... (current time - publish time of the bookn))
After a book is drawn, the next round of the loop will minus the (current time - publish time of the book) from the denominator and recalculate the probability for each of the remaining books, the loop continues until 10 books have been drawn.
Is this algorithm a correct one?
By the way, the website is written in PHP.
Feel free to suggest some PHP codes if you have a better algorithm in your mind.
Many thanks to you all.
Here's a very similar question that may help: Random weighted choice The solution is in C# but the code is very readable and close to PHP syntax so it should be easy to adapt.
For example, here's how one could do this in MySQL:
First calculate the total age of all books and store it in a MySQL user variable:
SELECT SUM(TO_DAYS(CURDATE())-TO_DAYS(publish_date)) FROM books INTO #total;
Then choose books randomly, weighted by their age:
SELECT book_id FROM (
SELECT book_id, TO_DAYS(CURDATE())-TO_DAYS(publish_date) AS age FROM books
) b
WHERE book_id NOT IN (...list of book_ids chosen so far...)
AND RAND()*#total < b.age AND (#total:=#total-b.age)
ORDER BY b.publish_date DESC
LIMIT 10;
Note that the #total decreases only if a book has passed the random-selection test, because of short-circuiting of AND expressions.
This is not guaranteed to choose 10 books in one pass -- it's not even guaranteed to choose any books on a given pass. So you have to re-run the second step until you've found 10 books. The #total variable retains its decreased value so you don't have to recalculate it.
First off I think your formula will guarantee that earlier books get picked. Try to set your initial probabilities based on:
Age - days since publication
Max(Age) - oldest book in the sample
Book Age(i) - age of book i
... Prob (i) = [Max (age) + e - Book Age (i)] / sum over all i [ Max (age) + e - Book age(i) ]
The value e ensures that the oldest book has some probability of being selected. Now that that is done, you can always recalc the prob of any sample.
Now you have to find an UNBIASED way of picking books. Probably the best way would be to calculate the cumulative distribution using the above then pick a uniform (0,1) r.v. Find where that r.v. is in the cumulative distribution and pick the book nearest to it.
Can't help you on the coding. Make sense?
What I am hoping to achieve is the ability to generate 'teams' of users. I will have x amount of men, weighted (decimal skill weight, like 75.23) and y amount of women (also with a skill weight value).
Given that list of users, I would then take for input the number of teams to make (let us say, 6 teams). Then, I go through the list of x's and y's and organize them so that the best average possible weighted teams are created. I would like to keep the teams balanced (women and men ratio)
I don't want 'stacked' teams, (best skilled in one team). I would like an even distribution of weight.
Curious how I could achieve this in PHP? I'd be using a MySQL database to fetch users with weight values. I would know ahead of time how many users I would have, also how many teams I would want to generate.
I would appreciate any suggestions, or links to a solution if anyone has found something similar like this. I'm just not a math wiz, so I don't know what formula would apply here.
Thanks. I appreciate any input!
EDIT
After reviewing the answers, maybe I was not clear enough, so hopefully this helps a little more.
I want the teams to be roughly equally-sized
I want the average (mean) skill score for each team to be roughly equal
I want the ratio of men to women in each team to be roughly equal (that is to say, if by division, we get a distribution, of 5 men and 3 women per team, I would like to keep that roughly the same). Not really an issue if I sort men first, and women second (or vise-versa).
I don't want a linear approach (team 1 gets highest, team 2, sec highest, team 3.. so on). Tim's method of taking (if 6 teams) 6 people and randomizing and then distributing via linear fashion seems to work out fine.
I'm not entirely clear what you're after here, so I'll recap on what I understand you to be asking. If this is not right, you can clarify your requirements by editing your question:
You have a list of a certain number of men and a certain number of women. Each person has a known skill score. You want to divide these into a certain number of teams, with the following aims:
you want the teams to be roughly equally-sized
you want the average (mean) skill score for each team to be roughly equal
you want the ratio of men to women in each team to be roughly equal
I would have thought that a simple method to achieve this would be:
Create a list of all the men in decreasing order of skill score.
Create a list of all the women in decreasing order of skill score.
Add the list of women to the end of the list of men.
Start at the beginning of the combined list, and allocated each person in turn to a team in a round-robin fashion. (That is to say, allocate the first person to team number one, the second to team number two, and so on until you have allocated one person to each of the teams you wish to create. Then start again with team one, allocating people to each team in order, and so on.)
With this approach, you will be guaranteed the following outcomes:
If possible (i.e. if the number of teams divides the total number of people), the teams will all have the same number of people.
If the teams are not all the same size, the largest team will have exactly one more person than the smallest team.
If possible the teams will all have the same number of men.
If the teams do not have the same number of men, the team with the most men exactly one more man than the team with the least men.
If possible the teams will all have the same number of women.
If the teams do not have the same number of women, the team with the most women exactly one more man than the team with the least women.
Each team will have men with a range of skill scores, from near the top of the range to near the bottom of the range.
Each team will have women with a range of skill scores, from near the top of the range to near the bottom of the range.
With sensible data, the mean skill score for each team will be roughly equal (although team one will have a slightly higher mean score than team two, and so on - there are ways of correcting this).
If this simple approach doesn't meet your requirements, please let us know what else you had in mind.
This is similar to "maximum/minimum weight perfect matching", just that the matching is for more than two elements (note that this is a different weight from what you have (the skill weight), namely, you would assign a weight to a matching (a matching would be a proposed 'team')).
The known algorithms for the perfect matching above (e.g., Edmond's algorithm) might not be adaptable to the group case. I would perhaps look into some simulated annealing technique or a simple genetic algorithm.
If the number of people in each group (x,y) is relatively even, and the total number of people is relatively high random sampling should work quite well. See here on how to select random rows from a MySQL database:
http://dev.mysql.com/doc/refman/5.0/en/mathematical-functions.html#function_rand
Slight edit, to ensure fairness personally I'd do something like this. Say you know you want n members per team. Then create a local variable which is n*mean where mean is the average skill level per person. Then when your randomly selecting your team members do so within that limit.
E.g.
while(new random record){
if(team_skill+random person skill > n*mean){
next;
}
if(team_skill+random person skill < n*mean && selected team members =n){
team + random person;
break;
}
}