Ordering Combinations for Maximum Effectiveness - php

So recently I was given a problem, which I have been mulling over and am still unable to solve; I was wondering if anyone here could point me in the right direction by providing me with the psuedo code (or at least a rough outline of the pseudo code) for this problem. PS I'll be building in PHP if that makes a difference...
Specs
There are ~50 people (for this example I'll just call them a,b,c... ) and the user is going to group them into groups of three (people in the groups may overlap), and in the end there will be 50-100 groups (ie {a,b,c}; {d,e,f}; {a,d,f}; {b,c,l}...). *
So far it is easy, it is a matter of building an html form and processing it into a multidimensional array
There are ~15 time slots during the day (eg 9:00AM, 9:20AM, 9:40AM...). Each of these groups needs to meet once during the day. And during one time slot the person cannot be double booked (ie 'a' cannot be in 2 different groups at 9:40AM).
It gets tricky here, but not impossible, my best guess at how to do this would be to brute force it (pick out sets of groups that have no overlap (eg {a,b,c}; {l,f,g}; {q,n,d}...) and then just put each into a time slot
Finally, the schedule which I output needs to be 'optimized', by that I mean that 'a' should have minimal time between meetings (so if his first meeting is at 9:20AM, his second meeting shouldn't be at 2:00PM).
Here's where I am lost, my only guess would be to build many, many schedules and then rank them based on the average waiting time a person has from one meeting to the next
However My 'solutions' (I hesitate to call them that) require too much brute force and would take too long to create. Are there simpler, more elegant solutions?

These are the table laid out, modified for your scenerio
+----User_Details------+ //You may or may not need this
| UID | Particulars... |
+----------------------+
+----User_Timeslots---------+ //Time slots per collumn
| UID | SlotNumber(bool)... | //true/false if the user is avaliable
+---------------------------+ //SlotNumber is replaced by s1, s2, etc
+----User_Arrangements--------+ //Time slots per collumn
| UID | SlotNumber(string)... | //Group session string
+-----------------------------+
Note: That the string in the Arrangement table, was in the following format : JSON
'[12,15,32]' //From SMALLEST to BIGGEST!
So what happens in the arrangement table, was that a script [Or an EXCEL column formula] would go through each slot per session, and randomly create a possible session. Checking all previous sessions for conflicts.
/**
* Randomise a session, in which data is not yet set
**/
function randomizeSession( sesionID ) {
for( var id = [lowest UID], id < [highest UID], id++ ) {
if( id exists ) {
randomizeSingleSession( id, sessionID );
} //else skips
}
}
/**
* Randomizes a single user in a session, without conflicts in previous sessions
**/
function randomizeSingleSession( id, sessionID ) {
convert sessionID to its collumns name =)
get the collumns name of all ther previous session
if( there is data, false, or JSON ) {
Does nothing (Already has data)
}
if( ID is avaliable in time slot table (for this session) ) {
Get all IDs who are avaliable, and contains no data this session
Get all the UID previous session
while( first time || not yet resolved ) {
Randomly chose 2
if( there was conflict in UID previous session ) {
try again (while) : not yet resolved
} else {
resolved
}
}
Registers all 3 users as a group in the session
} else {
Set session result to false (no attendance)
}
}
You will realize the main part of the assignment of groups is via randomization. However, as the amount of sessions increases. There will be more and more data to check against for conflicts. Resulting to a much slower performance. However large being, ridiculously large, to an almost perfect permutation/combination formulation.
EDIT:
This setup will also help ensure, that as long as the user is available, they will be in a group. Though you may have pockets of users, having no user group (a small number). These are usually remedied by recalculating (for small session numbers). Or just manually group them together, even if it is a repeat. (having a few here and there does not hurt). Or alternatively in your case, along with the remainders, join several groups of 3's to form groups of 4. =)
And if this can work for EXCEL with about 100+ ppl, and about 10 sessions. I do not see how this would not work in SQL + PHP. Just that the calculations may actually take some considerable time both ways.

Okay, for those who just join in on this post, please read through all the comments to the question before considering the contents of this answer, as this will very likely fly over your head.
Here is some pseudo code in PHP'ish style:
/* Array with profs (this is one dimensional here for the show, but I assume
it will be multi-dimensional, filled with availability and what not;
For the sake of this example, let me say that the multi-dimensional array
contains the following keys: [id]{[avail_from],[avail_to],[last_ses],[name]}*/
$profs = array_fill(0, $prof_num, "assoc_ids");
// Array with time slots, let's say UNIX stamps of begin time
$times = array_fill(0, $slot_num, "time");
// First, we need to loop through all the time slots
foreach ($times as $slot) {
// See when session ends
$slot_end = $slot + $session_time;
// Now, run through the profs to see who's available
$avail_profs = array(); // Empty
foreach ($profs as $prof_id => $data) {
if (($data['avail_from'] >= $slot) && ($data['avail_to'] >= $slot_end)) {
$avail_prof[$prof_id] = $data['last_ses'];
}
}
/* Reverse sort the array so that the highest numbers (profs who have been
waiting the longest) will be up top */
arsort($avail_profs);
$profs_session = array_slice($avail_profs, 0, 3);
$profs_session_names = array(); // Empty
// Reset the last_ses counters on those profs
foreach ($profs_session as $prof_id => $last_ses) {
$profs[$prof_id]['last_ses'] = 0;
$profs_session_names[0] = $profs[$prof_id]['name'];
}
// Now, loop through all profs to add one to their waiting time
foreach ($profs as $prof_id = > $data) {
$profs[$prof_id]['last_ses']++;
}
print(sprintf('The %s session will be held by: %s, $s, and %s<br />', $slot,
$profs_session_names[0], $profs_session_names[1],
$profs_session_names[2]);
unset ($profs_session, $profs_session_names, $avail_prof);
}
That should print something like:
The 9:40am session will be held by: C. Hicks, A. Hole, and B.E.N. Dover

I see an object model consisting of:
Panelists: a fixed repository of of your the panelists (Tom, Dick, Harry, etc)
Panel: consists of X Panelists (X=3 in your case)
Timeslots: a fixed repository of your time slots. Assuming fixed duration and only occurring on a single day, then all you need is track is start time.
Meeting: consists of a Panel and Timeslot
Schedule: consists of many Meetings
Now, as you have observed, the optimization is the key. To me the question is: "Optimized with respect to what criteria?". Optimal for Tom might means that the Panels on which he is a member lay out without big gaps. But Harry's Panels may be all over the board. So, perhaps for a given Schedule, we compute something like totalMemberDeadTime (= sum of all dead time member gaps in the Schedule). An optimal Schedule is the one that is minimal with respect to this sum
If we are interested in computing a technically optimal schedule among the universe of all schedules, I don't really see an alternative to brute force .
Perhaps that universe of Schedules does not need to be as big as might first appear. It sounds like the panels are constituted first and then the issue is to assign them to Meetings which them constitute a schedule. So, we removed the variability in the panel composition; the full scope of variability is in the Meetings and the Schedule. Still, sure seems like a lot of variability there.
But perhaps optimal with respect to all possible Schedules is more than we really need.
Might we define a Schedule as acceptable if no panelist has total dead time more than X? Or failing that, if no more than X panelists have dead time more than X (can't satisfy everyone, but keep the screwing down to a minimum)? Then the user could assign meeting for panels containing the the more "important" panelists first, and less-important guys simply have to take what they get. Then all we have to do is fine a single acceptable Schedule
Might it be sufficient for your purposes to compare any two Schedules? Combined with an interface (I'm seeing a drag-and-drop interface, but that's clearly beyond the point) that allows the user to constitute a schedule, clone it into a second schedule, and tweak the second one, looking to reduce aggregate dead time until we can find one that is acceptable.
Anyway, not a complete answer. Just thinking out loud. Hope it helps.

Related

Event entries scheduling algorithm PHP

we have an entry portal system in which we accept entries for events.
For example Championship Event 2017 will be held on 30th Nov.
Event got about 150 entries in different classes. Junior Class, Senior Class, Pro Class etc.
Now event venue only has certain numbers of ground on which the competition can be held. For example Ground 1, Ground 2 and Ground 3. Its a solo performance event.
Now our system needs to generate a schedule in such a way that competitors who entered multiple classes or same classes multiple times should get maximum break between their performances.
The input data we have are registration under each class.
Starting time of each Ground. For example Ground A will start at 8:00 AM, Ground 2 at 8:00 and Ground 3 at 9:00.
We also know that which class will be held in which arena. For example Junior and senior Class will be held in Ground 1 and Pro Class will be held in Ground 2.
We know the performance time as well. Senior Class 1 performance is 5 minutes. Junior class performance is 7 minutes and Pro Performance is 9 minutes.
Now I have written following code to get the schedule so that competitors competing multiple times in one class or in multiple class get maximum break between their performance but it still puts same competitor performance one after another.
Let me know what is my mistake.
foreach ($totalPerformanceTimeSlot as $time => $performance) {
# $totalPerformanceTimeSlot is array of timeslots starting from 8:00 am
foreach ($performance as $classId) {
#there could be 2 performance at the same time in different arena for different class.
$totalPerformanceLeftThisClass = count($this->lassRegistrationLinks[$classId]); //Get the total performance for this class from array;
# $accountRidesLeftArray has value of how many times each account is performing in this class
arsort($accountRidesLeftArray);
# for each person, estimate what their start time threshold should be based on how many times they're performing
$accountPerformanceTimeThreshold = array();
foreach ($accountPerformanceLeftArray as $accountId => $accountPerformancesLeft) {
$tempPerformanceThreshold = 20 * 60;
# reduce this person's performance threshold by a performance at a time until the minimum performance threshold has been met
while ((($totalPerformanceLeftThisClass * $this->classes[$classId]['performanceTime']) / $accountPerformanceLeft < $tempPerformanceThreshold) && ($tempPerformanceThreshold > $this->minRideThreshold))
$tempPerformanceThreshold -= $this->classes[$classId]['performanceTime'];
$accountPerformanceTimeThreshold[$accountId] = $tempPerformanceThreshold;
}
$performanceLeft = $totalPerformanceLeftThisClass - $count;
# given the number of performance left in the class,
# calculate how important it is per account that they get placed in the next slot
$accountToPerformNextImportanceArray = array();
$timeLeft = $performanceLeft * $this->classes[$classId]['performanceTime'];
foreach ($accountPerformanceLeftArray as $accountId => $accountPerformancesLeft) {
# work out the maximum number that can be used as entropy
$entropyMax = (20 * 60 / ($timeLeft / 1)) * 0.5;
$entropy = ((mt_rand (0, $entropyMax * 1000)) / 1000);
# the absolute minimum amount of time required for this user to perform
$minTimeRequiredForComfortableSpacing = ($accountRidesLeft - 1) * 20* 60;
# add a bit of time around the absolute minimum amount of time required for this person to perform so that it doesn't instantly snap in when this person suddenly has the minimum amount of time left to perform
$generalTimeRequiredForComfortableSpacing = $minTimeRequiredForComfortableSpacing * 1.7;
$nearestPerformancePrior = $this->nearest_performance_prior($classDetails['date'], $currentTime, $accountId);
$nearestRideAfter = $this->nearest_performance_after($classDetails['date'], $currentTime, $accountId);
# work out how important it is for this rider to ride next based on how many rides they have left
$importanceRating = 20 * 60 / ($timeLeft / $accountPerformanceLeft);
# if there's more than enough time left then don't worry about giving this person any importance rating, ie. it's not really important that they perform straight away
if ($timeLeft > $generalTimeRequiredForComfortableSpacing)
$importanceRating = 0;
# add a little bit of random entropy to their importance rating
$importanceRating += $entropy;
# if this account has performed too recently to place them here in this slot, then make them very undesirable for this slot
if ((!is_null($nearestPerformancePrior)) && ($nearestPerformancePrior > $currentTime - $accountPerformanceTimeThreshold[$accountId]))
$importanceRating = -1;
# work out if this account will perform too soon afterwards to place them here in this slot, then make them very undesirable for this slot
if ((!is_null($nearestRideAfter)) && ($nearestRideAfter < $currentTime + $accountRideTimeThreshold[$accountId]))
$importanceRating = -1;
$accountToPerformNextImportanceArray[$accountId] = $importanceRating;
}
arsort($accountToPerformNextImportanceArray);
//Then I take the first one from this array and allocate the time for that user.
$this->set_performance_time($classDetails['date'], $accountId, $currentTime);
$currentTime += $this->classes[$classId]['performanceTime'];
}
}
Here is some explanation of the variables
$accountPerformancessLeft is total number of performance for each user.
For e.g. if user has entered into 2 classes that means $accountPerformancessLeft is 6 for that user.
threshold is something like break.
Rider and account is conceptually the same.
I know it is hard to think the output without the actual data but any help would be appreciated.
Thank you
Well, first let's see what we have and simplify the problem:
There are different competitions(events) but since they are independent to each other we can consider only one
We have C different classes (senior, junior, ...)
We have G different grounds that each ground may hold some of C classes.
There are some persons(competitor) lets say P who registers to C classes.
Persons need to have maximum possible break.
So putting them all together the problem is:
The are some grounds G = {g1, g2, ..., gm} that each of them contains some persons P = {p1, p2, ..., pn}. We want to maximize the break time of each person in all of its competitions.
The trivial case:
First, let's assume that there is only one ground g1, and a group of person P = {p1, p2, ..., pn} who wants to compete on this ground. let's define a boolean method isItPossible(breaktime) showing that whether it is possible to schedule the competition that each person has at least breaktime to rest or not. we can simply prove that this method is monotonic i.e. if there exist a breaktime that isItPossible(breaktime) became true then:
isItPossible(t) = true for every t <= breaktime
So we can use binary search to find the maximum value for breaktime. Here is the pseudo code (C++ syntax like):
double low = 0 , high = INF;
while(low < high){
mid = (low + high) / 2;
if(isItPossible(mid))
low = mid;
else
high = mid;
}
breakTime = low;
Now the only thing remains is implementing isItPossible(breaktime) method. There are a lot of ways to implement it but I use greedy algorithm and a heap priority queue to solve it. We need a priority queue for maintaining some tuples. Each tuple contains a person, the number of time that person should compete and the earliest time we can schedule a competition for that person. We start from time t0 (the opening time of the ground e.g. it could be 8.00 a.m.) and each time we pick a person from the priority queue with the minimum earliest time. Here is the C++ like pseudo code:
bool isItPossible(double breaktime){
//Tuple(personId, numberOfCompete, earliestTime)
priority_queue<Tuple> pq;
for p in Person_list
pq.push(Tuple(p,countCompetition(p),t0));
for(time = t0;time<end_of_ground_time;){
person = pq.pop();
add_person_to_scedule_list(person.personId, max(time, person.earliestTime));
time = max(time, person.earliestTime) + competition_time;
if(person.numberOfCompete > 1)
pq.push(Tuple(person.Id,person.numberOfCompete - 1,time + breaktime)));
}
return pq.isEmpty();
}
The main problem:
After solving the trivial case we are ready to solve the original problem. In this case there are G = {g1, g2, ..., gm} grounds and we want to schedule P = {p1, p2, ..., pn} competitors. Like the trivial case we define a isItPossible(breaktime) function. Again we can prove that this function in monotonic, so we use binary search for finding the maximum value (like the above code). After that we only need to implement the isItPossible(breaktime) method. In this case implementing this method is little tricky.
For this method you can do some heuristic algorithms or some creative greedy ones (for example distribute each person start time base on breakTime over all grounds and check whether it is possible to do it for all persons or not). But again I suggest you to use Greedy algorithm and priority queue like the trivial case. Your tuple should also contains number of times that person compete in each ground, and when you want to increase time and sweep it, you should iterate over all grounds and schedule them simultaneously.
Hope it can help you. Of course there are some evolutionary algorithms like genetic or PSO to solve it (I can also explain them if you want) But using the above method is much simpler to implement and debug.
What an interesting problem!
Here is how I'd tackle it:
Set up a random schedule which works (but doesn't fit the criteria).
Write a function that can swap 2 performances
Write a shuffler which uses swap() many times in order to get a new timetable
Write a function to calculate a score(), how good is this particular schedule? does it have a lot of breaks between performances?
A score should sum all the performance gaps together, this is the function we want to maximise.
Write an algorithm that takes a "search" approach and backtracking to the problem, and let it run for a couple hours, the backtracking should:
Swap stuff
See if the swapped stuff has a better score
if so, continue from swapped
otherwise, backtrack
It can take a while, but the program can generate a better timetable.
Let us know if this approach helps.

Managing old elements by timestamp in Redis sorted set

You have a sorted set A in redis, every now and then you add new elements to it, they get sorted by rank e.g. You also have a sorted set B.
Is there a way to check if there are elements in set A that have been there for more then say 20 seconds, and move them to sorted set B
because this checking operation is done very frequently, and list can be very big, iterating through every element in set is a not a good solution. Need fastest one.
Thanks.
UPDATE:
Here is what I was trying to do:
Basically the idea was, imagine you have some kind of game server that matches opponents when they put a fight request. The current design was that every request get's to the set, and the rank/score is the player rank. so that way every 2 players that are near each other in the list are perfect matches. every 5 seconds or so a script get's called that pulls 50 rows from top of set, and matches them 2 by 2 (and removes them). This was working fine, and I think that was a very fast working solution. But then the idea of creating a Bot (AI) players came. so that when player is waiting too long in que, he get's matched with a bot (AI) player. And I cannot figure out a way to see "who is waiting too long" Basically maybe the entire idea was wrong.. so any better ideas are welcome :) Thanks a lot.
If the score in your sorted set is a unix timestamp, you can use zrange to grab the oldest NN items from set A. You can then do your checks, add qualifying entries to set B, then remove them from set A.
If your scoring in set A is not based on timestamp, then you will have to iterate over your set A entirely, or rethink your design. Redis keys do not have an inherent available timestamp of when they are added (which holds doubly true for items in a key such as a sorted set), so it has to be something you specifically create and track. Perhaps if you share more about what you are doing and why we can help with more detail.
Edit:
based on the additions to your questions, I would recommend trying a solution similar to what #akonsu is proposing.
Specifically:
Sorted-Set-A: players by rank just as they are now.
Sorted-Set-B:
uses timestamp as the time the person went into the queue, stores their userid. In other words, when you zadd to SetA with their rank & ID, you zadd to SetB with the timestamp and ID.
When you match players you remove them from both sets. If you pull your set of users to match from SetB using a zrange command to grab the X oldest entries, you will have the time they queued up, in order of their entry (like a FIFO). You then use a zrange command on SetA with their rank +/- whatever rank range you need. If you get a match you proceed with the match by removing them from both sets and moving on.
If there is no suitable opponent in SetA and their timestamp is old enough you match with an AI, then remove them from both sets and move on.
Essentially it is an index queue of users->timestamp. Doing it this way mean shorter queue times for all users as you are now matching them in order of queue length. You still use SetA for matching based on players' rank, but now you are indexing and prioritizing based on time.
The specific implementation may be a bit more interesting than this, but as an overall stratagem I think this fits what you need.

Item rankings, order by confidence using Reddit Ranking Algorithms

I am interested to use this ranking class, based off of an article by Evan Miller to rank a table I have that has upvotes and downvotes. I have a system very similar to Stack Overflow's up/down voting system for an events site I am working on, and by using this ranking class I feel as though results will be more accurate. My question is how do I order by the function 'hotness'?
private function _hotness($upvotes = 0, $downvotes = 0, $posted = 0) {
$s = $this->_score($upvotes, $downvotes);
$order = log(max(abs($s), 1), 10);
if($s > 0) {
$sign = 1;
} elseif($s < 0) {
$sign = -1;
} else {
$sign = 0;
}
$seconds = $posted - 1134028003;
return round($order + (($sign * $seconds)/45000), 7);
}
I suppose each time a user votes I could have a column in my table that has the hotness data recalculated for the new vote, and order by that column on the main page. But I am interested to do this more on-the-fly incorporating the function above, and I am not sure if that is possible.
From Evan Miller, he uses:
SELECT widget_id, ((positive + 1.9208) / (positive + negative) -
1.96 * SQRT((positive * negative) / (positive + negative) + 0.9604) /
(positive + negative)) / (1 + 3.8416 / (positive + negative))
AS ci_lower_bound FROM widgets WHERE positive + negative > 0
ORDER BY ci_lower_bound DESC;
But I rather not do this calculation in the sql as I feel this is messy and difficult to change down the line if I utilize this code on multiple pages .etc.
Accessing the corresponding "Posts" table for anything (reading, writing, sorting, comparing, etc.) is extremely quick and thus relying on the database is the "most on-the-fly" alternative you have for non-temporary data storage (memory/sessions are still quicker but, logically, cannot be used to store this information).
You should be more worried about building a good ranking algorithm delivering the results you want (you are proposing two different systems, delivering different results) and working on making the whole code and the code-database communication as efficient as possible.
In principle, small codes with iterative simple orders offer the quickest and most reliable solution for this kind of situations. Example:
Ranking function (like the first one you propose or any
other one built on the ranking rules you want) called every time a
vote is given. It writes to the corresponding column(s) in the
"Posts" table (the simpler the query, the better: you can create a
ranking system as complex as you wish, but try to rely on PHP
rather than on queries).
Every time a comparison between posts is required, the "Posts" table is read with a simple SELECT ordering the records by ranking
(you can have various "assessing columns" (e.g., up-votes,
down-votes, further considerations); but better having one with the
definitive ranking).
You are right, query like this is rather messy and expensive as well.
Mixed PHP/MySQL on the fly is a bad idea well as you will have to select values for all posts and calculate hotness and then select a list of hotest ones. Extremely expensive.
You should consider saving at least part of your calculation to the database. Definitely order should go to the database. It's always better to calculate something and save just once on every save/update, instead of calculating each time it will be displayed. Try to do a benchmark on how much time you will save by calculating order on save/update instead of every time you calculate the hotness. Good thing is that order never changes unless someone upvotes/downvotes which you save to the db anyway, same for the sign.
Even if you save the sign to the db you are stil not able to avoid calculating on the fly due to the posted timestamp parameter.
I would see what difference does it make and where it makes a difference and calculate hotness with a CLI script every x amount of time only for those scripts where this is crucial, every y amount of time where it's making less of a difference.
Taking this approach you will be recalculating hotness only when necessary. This will make your application much more efficient.
I am not sure if it is possible with your DB and Schema however have you consider writing a UDF for custom sorting?
A post from stackoverflow talks about how to do this here.

Possible ways to create a turn based system using PHP/MySQL [closed]

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 11 years ago.
Improve this question
Right, I'm trying to create a system where by the user can do something, but then must wait until all the other users in the mysql table have made their move, i.e
User1 makes move, user2 and 3 must wait
user2 makes move, user 1 and 3 must wait
user3 makes move, user 1 and 2 must wait
user1 makes move...
One way I thought of was to give each of the users an number (ranging from 1 to the total number of players, say 6) and then when a player makes a move, set their number to the max number (6) and decrease everyone else's number by one, so the one with the minimum number is the only one who can play.
That's my only idea, is there an easier or alternative way?
My suggestion would be just store the last move date as a datetime. When you need to check if a user can move, simply just select out of the table all of the other players where the last move date is less than or equal to the current player's last move date. If the number of rows is not 0, then the player cannot move yet.
The benefits of this approach is the simplicity- every time you allow a player to make a move, just update the column with the current date and time.
Your proposed solution seems a little circuitous:
You're updating+reading every player every move, when the minimum information you need to maintain is whose move it is.
You're losing information about player order as you encode next turn information.
A high-level solution:
Create a games table, one row per game, with a column like INT currentTurn
Create a gameUsers table on a per-game basis, linked to its game in games
Do assign each of the n users in gameUsers an INT playerOrder ranging [1-n]
Only accept a move from playerN if playerN == "SELECT playerID FROM gameUsers WHERE playerOrder = currentTurn"
After a successful move: "UPDATE games SET currentTurn = currentTurn + 1 WHERE game = thisGame"
I believe above table structure is a good object oriented representation of an actual game model. You can stash other per-game things into games like winner, length, date, etc. Pardon the pseudoSQL.
You could have a table with column hasMoved tinyint(1) required default 0, and query for where hasMoved == 0; if the query returns null, then all players have moved.
(Note: this is based on "must wait for all other users", NOT for a strict move order - i.e. 'A' must move before 'B' must move before 'C', etc.)
Additionally, queries using this method is somewhat slow and (to me) seems somewhat unnecessarily resource-intensive - perhaps think about using Ajax instead?
Have a game sequence number that starts at zero. Have a "last moved" number for each player. When a player moves, set their "last moved" number equal to the game sequence number. Once every player has moved, increment the game sequence number.
You may want to use a timeout though, otherwise a player who doesn't move can delay the other players indefinitely.
I would first determine $sequence by calculating speed. Then comparing speeds to determine order. Then use the order to send out notices for their move. Use a timestamp to ensure the user doesn't take over a day or however long, you will need a cron job just for this.
Have a variable or array hold the first n last sequence so u can easily move the last moved player to the back without mixing uP orders.
Have the page check the players order sequence and not allow action unless it's at 1 or 0. Be sure to sanitize inputs so no manipulation exists. Then insert your form and graphics and game equations.
You can save date-time of the last move of the each user. So when you DESC sort this table by this date-time column, you will have to fetch only the first row of the result, that will contain the ID of the allowed to make move player.

Algorithm for Room Allocation Using PHP

I need help with an algorithm to allocate rooms to people. I need to shuffle through a list of rooms to assign a room to a person and after the fourth person is assigned to the room, it should be out of the list(should be unavailable). I have not had any luck with PHP shuffling and sorting functions yet.
Any help (pointers, references, etc.) will greatly be appreciated.
This sounds like both a homework assignment and a problem with thousands of solutions.
As Jack already said, try to develop your algorithm before you try to implement it in code. If you're having trouble understanding this, then just imagine the scenario and try to write simple rules for solving it in real life
Let's say I have a hallway with 10 rooms. Each room can support up to 4 people. Then 35 people show up and want to be assigned to rooms. How would I do this?
I would probably start at the beginning of the hallway and fill up the first room, then fill up the next room, and continue until I ran out of people or rooms (whichever came first). This solution has the advantage of not having to walk very far down the hallway, but the disadvantage of crowding 4 people into one room instead of spreading them evenly.
If you chose to spread them evenly then you'd want to put one in the first room, then one in the second room, etc. Do this until you run out of rooms, then go back through every room putting a second person.
Since you have two methods of doing this, the next step is determining how to represent your basic components in code. You need a way to represent a room and a way to represent a person. The most important feature of a room is that it can hold up to four people, but it always has to know how many people it's holding. Therefore it might be good to think of each room as it's own number, the number telling you how many people are already in that room.
In PHP, if you want several numbers which are related and ordered (as the rooms in a hallway would be) you use an array. This is true when you have several of ANY variable that need to be related to one another and maintain their respective order.
$rooms = array(0, 0, 0, 0, 0); // 5 rooms, all with 0 people in them
If your room needs to know who is staying in the room (if they need to differentiate between different guests) then you might consider each individual room as a 4-element array, each element of which represents a person and is able to identify that person.
$rooms = array(
array(null, null, null, null),
array(null, null, null, null),
array(null, null, null, null),
array(null, null, null, null),
array(null, null, null, null)
);
After you've created your rooms, you have a certain number of people who are waiting to enter a room. Since each person only counts as 1, unless you need to remember extra information about each person (such as their name, age, etc.) then you should be able to see a very convenient way of representing people.
$peopleNotInARoomYet = 10;
If you do need to remember extra information about these people (suppose after assigning rooms you are asked the question "In which room is Bob?") then you would need something much more intelligent. Perhaps an array of classes, each class representing a person. Unless, of course, the person need only be represented by a single variable. Then you could boil them doing to just an array.
$peopleNotInARoomYet = array("Bob", "Sally", "Bill", "Mary");
//or
$peopleNotInARoomYet = array(new Person('Bob'), new Person('Sally'), new Person('Bill'), new Person('Mary'));
Note that the second method required the Person class already be defined, and it can get very convoluted if you aren't careful.
Once you have a way of representing the people, you want to loop through every person to find them a room. If people are represented by a single number, this would look like:
while($peopleNotInARoomYet > 0){
// Assign a room
$peopleNotInARoomYet--;
}
If the people are represented as an array, you might want to consider the PHP array_pop() function.
PHP.net array_pop manual
$nextPerson = array_pop($peopleNotInARoomYet){
while($nextPerson != NULL){
// Assign a room
$nextPerson = array_pop($peopleNotInARoomYet);
}
Having a way to represent rooms and people now, your new task is to take our definition of assignment from above and turn it into code. So let's look at our first (and probably simpler) method. We put people into a room until it's full, then go to the next room.
This actually poses a few algorithmic challenges. First, how do you "put someone into a room"?
The answer to this actually depends on which definition of a room we used. If we simply had an array of integers (the case when we care how many people are in a room but do not care who is in the room) then we need to add one to this integer.
If we had an array of 4-element arrays, then we need to find the first empty element and place the person in that element. Putting a person into a non-empty element will replace the person who was there before.
Since it's obvious from this first attempt to convert our rule set to code that the method will differ depending on the implementation chosen, for the rest of the example I will assume that rooms need only know how many people are in them, and not who is in them in specific. If you do need this further information, that's a lesson left up to the reader to figure out on their own.
So here's our definition of a room, a person, and the beginning of our loop:
<?php
$rooms = array(0, 0, 0, 0, 0); // 5 empty rooms
$peopleNotInRoomsYet = 14; // We'll choose a number that won't divide evenly
while($peopleNotInRoomsYet > 0){
// Assign a room
$peopleNotInRoomsYet --;
}
?>
And we know that once we've chosen which room to put someone in, actually putting them there involves the following:
$rooms[$roomNumber]++;
So now let's go back to our original problem definition and see where we left off. We want to fill up the first room, then the second, then the third, etc.
So first we needed a way to define filling up a room. Well filling a room involves putting people in it (done) until it's full (not done). So now we need a way to check and see if a room is full.
if($rooms[$roomNumber] == 4)
should do nicely. So now we have a way of "filling a room until it's full"... But after this we need to start on the next room. This means we need to always know which room we are currently filling. If there's something new that we need to know, we need a new variable for it. Let's call this variable $roomNumber. We'll start with $roomNumber = 0; (the first room in the array) and continue until it's 5. Since there is no sixth room (element 5) then if $roomNumber ever becomes 5, we have too many people.
<?php
$rooms = array(0, 0, 0, 0, 0); // 5 empty rooms
$peopleNotInRoomsYet = 14; // We'll choose a number that won't divide evenly
$roomNumber = 0;
while($peopleNotInRoomsYet > 0){ // If there are people waiting...
if($rooms[$roomNumber] == 4){ // If the room is full...
$roomNumber ++; // Go to the next room
}
if($roomNumber == 5){ // If we are out of rooms...
die("Too many people!!!"); // die
}
$rooms[$roomNumber] ++; // Otherwise, add someone to the room
$peopleNotInRoomsYet --; // And remove them from the waiting list
}
?>
I know this was extremely length for the tiny amount of code we ended with, but I was attempting to explain the process of going from concept to code. Recognize the simple rules that you need to follow, then recognize the items you need to keep track of. Also remember that the solution I posted works only in the simplest situation, that being you don't need to know who is in the room, just how many people. It also assumes that no room starts with anyone in it. If room two started out full then this algorithm would fall apart since I didn't check for that. There are plenty of modifications left to be done by the reader, but this should get you pointed in the right direction.
This is not directly a PHP question, you should first describe the algorithm and then try to implement it.
From what I understand the best solution would be to keep a list of rooms sorted by actual empty spaces (so at the beginning you will have empty rooms, then rooms with 1 people, then rooms with 2, etcetera).
Then whenever a new user comes you have to choose a policy to assign it to a room, for example you could choose to always add the newcomer to a most empty room (so you will choose a random one between the empty ones, or between the rooms with just 1 people if no empty one is available and so on).. or you could decide to assign it to one random room which is not full. It depends on what you really need to do.
In anycase you could keep 2 lists of rooms, one for the not-full and one for the full rooms. When a room becomes full because a newcomer fills it you just swap it to the other list. When, instead, an user leaves a full room you switch it back to original list.
Of course keeping the not-full room list ordered by empty spaces is useful just when you policy needs to perform a choice that depends on how many empty spaces there are in any room, otherwise you could just keep all of them together and choose one randomly.

Categories