Adam Anderson Adam Anderson - 15 days ago 7
PHP Question

Values not being placed in array

Im creating a revision timetable for a school project that lets the user choose subjects and how many hours they want for each one, before inputting them into a 2d-array the user can use as a table. I have written the following code that takes the array $subject through post of a previous page.

$subject is a 2d-array with the first level being the subjects the user choose and the second being how many hours the user wants for that subject.

The code should take the $subject array and use it in a number of functions to populate the array but when I run the code I just get an empty array

Here is the code

<?php
$timetable = array(

"0" => array // 0 = Monday 6 = Sunday
// 0 - 23 = horus
(
"0" => '',
"1" => '',
"2" => '',
"3" => '',
"4" => '',
"5" => '',
"6" => '',
"7" => '',
"8" => '',
"9" => '',
"10" => '',
"11" => '',
"12" => '',
"13" => '',
"14" => '',
"15" => '',
"16" => '',
"17" => '',
"18" => '',
"19" => '',
"20" => '',
"21" => '',
"22" => '',
"23" => ''
),
"1" => array
(
"0" => '',
"1" => '',
"2" => '',
"3" => '',
"4" => '',
"5" => '',
"6" => '',
"7" => '',
"8" => '',
"9" => '',
"10" => '',
"11" => '',
"12" => '',
"13" => '',
"14" => '',
"15" => '',
"16" => '',
"17" => '',
"18" => '',
"19" => '',
"20" => '',
"21" => '',
"22" => '',
"23" => ''
),
"2" => array
(
"0" => '',
"1" => '',
"2" => '',
"3" => '',
"4" => '',
"5" => '',
"6" => '',
"7" => '',
"8" => '',
"9" => '',
"10" => '',
"11" => '',
"12" => '',
"13" => '',
"14" => '',
"15" => '',
"16" => '',
"17" => '',
"18" => '',
"19" => '',
"20" => '',
"21" => '',
"22" => '',
"23" => ''
),
"3" => array
(
"0" => '',
"1" => '',
"2" => '',
"3" => '',
"4" => '',
"5" => '',
"6" => '',
"7" => '',
"8" => '',
"9" => '',
"10" => '',
"11" => '',
"12" => '',
"13" => '',
"14" => '',
"15" => '',
"16" => '',
"17" => '',
"18" => '',
"19" => '',
"20" => '',
"21" => '',
"22" => '',
"23" => ''
),
"4" => array
(
"0" => '',
"1" => '',
"2" => '',
"3" => '',
"4" => '',
"5" => '',
"6" => '',
"7" => '',
"8" => '',
"9" => '',
"10" => '',
"11" => '',
"12" => '',
"13" => '',
"14" => '',
"15" => '',
"16" => '',
"17" => '',
"18" => '',
"19" => '',
"20" => '',
"21" => '',
"22" => '',
"23" => ''
),
"5" => array
(
"0" => '',
"1" => '',
"2" => '',
"3" => '',
"4" => '',
"5" => '',
"6" => '',
"7" => '',
"8" => '',
"9" => '',
"10" => '',
"11" => '',
"12" => '',
"13" => '',
"14" => '',
"15" => '',
"16" => '',
"17" => '',
"18" => '',
"19" => '',
"20" => '',
"21" => '',
"22" => '',
"23" => ''
),
"6" => array
(
"0" => '',
"1" => '',
"2" => '',
"3" => '',
"4" => '',
"5" => '',
"6" => '',
"7" => '',
"8" => '',
"9" => '',
"10" => '',
"11" => '',
"12" => '',
"13" => '',
"14" => '',
"15" => '',
"16" => '',
"17" => '',
"18" => '',
"19" => '',
"20" => '',
"21" => '',
"22" => '',
"23" => ''
)
);

$subjects = $_POST;

function pick_random_subject($subjects, $timetable)
{
$available = FALSE;
while ($available == FALSE) {
$subject = array_rand($subjects);
if (check_subject_availability($subjects, $timetable, $subject)) {
$available = TRUE;
}
}
return $subject;
}

function check_subject_availability($subjects, $timetable,$subject)
{
$count = 0;
foreach ($timetable as $day) {
$count += array_count_values($day)[$subject];
}

if ($count < $subjects[$subject]) {
return True;
} else {
return false;
}
}

function verify_available_slot($timetable, $day, $slot)
{
if ($timetable[$day][$slot] == '') {
return true;
} else {
return false;
}
}

function pick_random_slot($timetable)
{

$available = FALSE;
while ($available == FALSE) {
$day = rand(0, 6);
$hour = rand(0, 23);

$available = verify_available_slot($timetable, $day, $hour);
}
return [$day, $hour];
}

function Check_end($subjects, $timetable)
{
$finished = FALSE;
foreach ($subjects as $subject) {
if (!check_subject_availability($subjects, $timetable, $subject)) {
$finished = TRUE;
break;
}
}
return $finished;
}
if(isset($_POST)) {
while(Check_end($subjects, $timetable )== FALSE)
{

$subject = pick_random_subject($subjects, $timetable);
$slot = pick_random_slot($subject);
$day = $slot[0];
$hour = $slot[1];
$timetable[$day][$hour] = $subject;
}
}
else {
header('http://localhost/timetable/TimetableAlgorithmn.php');
}

?>
<pre>
<?print_r($timetable) ?>
<pre>


Note: I think that the problem lies within the function "check_subject_availability" but im not sure.

Answer

I can't test it without the surrounding code but at least one problem should lie between the Check_end() and check_subject_availability calls:

function Check_end($subjects, $timetable)
{
$finished = FALSE;
foreach ($subjects as $subject) {
    if (!check_subject_availability($subjects, $timetable, $subject)) {
        $finished = TRUE;
        break;
    }
}
return $finished;
}

This code assumes the name of the subject is a value e.g. $subjects == ['subject1']

While in check_subject_availability() you use it as key into subjects e.g. $subjects == ['subject1' => 5]

function check_subject_availability($subjects, $timetable,$subject)
{
$count = 0;
foreach ($timetable as $day) {
    $count += array_count_values($day)[$subject];
}

return $count < $subjects[$subject]; // usage as key
}

Maybe changing foreach ($subjects as $subject) to foreach ($subjects as $subject => $max_count) fixes your problem.

Another bug:

while(Check_end($subjects, $timetable )== FALSE)
{
    $subject = pick_random_subject($subjects, $timetable);
    list($day, $hour) = pick_random_slot($timetable);  // $timetable not $subject
    $timetable[$day][$hour] = $subject;
}

And finally the last bug (at least to get it work for me:)

function Check_end($subjects, $timetable)
{
$finished = TRUE;
foreach ($subjects as $subject => $max_n) {
    if (check_subject_availability($subjects, $timetable, $subject)) {
        $finished = false;
    }
}
return $finished;
}

Your version stopped as soon as one subject was !check_subject_availability(). This version stops only if all subjects are not available.

One last tip: You should consider the shuffle approach I use in the code below because your version slowly becomes problems when the timetable fills up and you can't find empty slots anymore.

A little add:

$timetable = array_fill(0, 7, array_fill(0, 24, ''));

constructs exactly the same array as your long array() statement.

A bigger add: Your code could be refactored to this:

$timetable = [];
foreach ($_POST as $subject => $n)  // add in the required amount of subjects
    $timetable = array_merge($timetable, array_fill(0, $n, $subject));
$timetable = array_merge($timetable, array_fill(0, 24 * 7 - count($timetable), ''));  // fill the array with empty values
shuffle($timetable);  // shuffle the set
$timetable = array_chunk($timetable, 24);  // split it into 7 days