I am creating a script for a game in a browser that will generate a random animal for the player to fight anywhere from 0-5 markup. The markings on this animal are randomly generated and fed into the imagick user-defined function, which adds them in order as they appear in the array.
While the marking is randomly determined, there are many rules for how they should appear on the animal, for example, marking in the "full body" area shows the marks above in the "stomach" area. To better explain, I will show a tester image:

Thus, in order to break 5 tags into this randomly generated animal, the eyeshadow marking belongs to the eye area, undertail belongs to the tail, streaks belongs to the fullbody, appaloosa belongs to the back and okapi belongs to the legs. Now the order is simply added when the script is looped over the database and randomly selected labels, so okapi (stripes on the legs) is on top, since it was the last in the array and the last one was added. But following the rules of the order, the last one in the array should have been stripes (horizontal stripes all over the body), since the pop-up inscriptions come from above.
Here is the code that selects the marking, this is done using the Laravel engine:
// Determine number of markings $num = mt_rand(1,10); if ($num == 1) { $markingNum = 0; } elseif ($num > 1 && $num < 4) { $markingNum = 1; } elseif ($num > 4 && $num < 6) { $markingNum = 2; } elseif ($num > 6 && $num < 8) { $markingNum = 3; } elseif ($num > 8 && $num < 10) { $markingNum = 4; } else { $markingNum = 5; } // Calculate Marking type and color $markings = array(); if ($markingNum > 0) { for ($m = 0 ; $m < $markingNum; $m++) { // Set color values (pulls from the "pallet" selected earlier in the code, which will determine the range of color that marking can be) if ($m == 1) { $pal = $pallet->marking1; } elseif ($m == 2) { $pal = $pallet->marking2; } elseif ($m == 3) { $pal = $pallet->marking3; } elseif ($m == 4) { $pal = $pallet->marking4; } else { $pal = $pallet->marking5; } // Pull previous marking info if (count($markings) != 0) { $previous = DataMarking::whereIn('name', array_keys($markings))->get(); // This pulls the regions of the current markings in the array so it won't select a region that already has a marking. foreach ($previous as $p) { $regions[$p->region] = $p->name; } // Uncommon marking (10% chance) $r = mt_rand(1, 10); if ($r == 10) { $marking = DataMarking::where('rarity', 1) ->where('public', 1) ->whereNotIn('name', array_keys($markings)) ->whereNotIn('region', array_keys($regions)) ->orderByRaw("RAND()") ->first(); // Common markings } else { $marking = DataMarking::where('rarity', 0) ->where('public', 1) ->whereNotIn('name', array_keys($markings)) ->whereNotIn('region', array_keys($regions)) ->orderByRaw("RAND()") ->first(); } // Colors marking if ($pal == 0) { $markingColor = rand_color(); } else { $range = ColorRange::where('id', $pal)->firstOrFail(); $markingColor = "#" . mixRange(substr($range->start_hex, 1), substr($range->end_hex, 1)); } $markings[$marking->name] = $markingColor; } else { // Uncommon marking (10% chance) $r = mt_rand(1, 10); if ($r == 10) { $marking = DataMarking::where('rarity', 1) ->where('public', 1) ->orderByRaw("RAND()")->first(); // Common marking } else { $marking = DataMarking::where('rarity', 0) ->where('public', 1) ->orderByRaw("RAND()")->first(); } // Colors marking if ($pal == 0) { $markingColor = rand_color(); } else { $range = ColorRange::where('id', $pal)->firstOrFail(); $markingColor = "#" . mixRange(substr($range->start_hex, 1), substr($range->end_hex, 1)); } $markings[$marking->name] = $markingColor; } } }
I suppose I can accomplish this with many complex if statements, but that just doesn't seem like an elegant solution for me. In addition, there is an exception: “Gradient”, a full label, falls under everything, even if it is a full body label. So far this is the only marking with a similar exception.
I tried using the various sort functions offered by PHP, but I was not very lucky. uksort seems to be the most promising, but since the value that we sort exists in the database, and not in the array that we sort (the imagick function must be supplied in the marking format => color matrix), which is difficult to work with.
Tl; dr: I need to reorder an array in which an indefinite amount of data is based on the values existing in the database for keys (area for marking). What is the most elegant way to achieve this?