dongshao8125 2017-02-26 05:53
浏览 25
已采纳

PHP数组随机化但不复制名册

I'm trying to make a randomizing roster. I am having trouble with it.

I need to take 1 C 2 P SS CF 3 LF RF

And create 9 random orders where they do not repeat in order, nor does one value take the same spot twice. Like a grid where each position is used once 9 times up and 9 times across. But I want to be able to randomize it. So its not always the same. I mean I guess I could just randomize the names, but the names would typically be in a specific order, whereas the positions would need not be, but not duped.

123456789    
234567891    
345678912    
456789123    
567891234    
678912345   
789123456    
891234567    
912345678 

I started with this, but it makes no sense. At first I was making sure as to not duplicate any positions, but I realized it didn't really, and I got kinda brain stuck.

shuffle($positions);
    $p1 = $positions;
    echo '<table style="width:100%;"><tr>';
    foreach($p1 as $pA){
        echo '<td>'.$pA.'</td>';
    }   
    echo '</tr>';   


    shuffle($positions);
    $p2 = $positions;
    if($p2 === $p1){    
        while($p2 === $p1){
            shuffle($positions);
            $p2 = $positions; 
            $a++; 
            echo '<br>=a=<br>'.$a.'<br>==<br>';
            //if($p2 == $p1){continue;}else{break;}
        }       
    }
    echo '<tr>';
    foreach($p2 as $pB){
        echo '<td>'.$pB.'</td>';
    }   
    echo '</tr>';




    shuffle($positions);
    $p3 = $positions;
    if($p3 === ($p1 || $p2)){   
        while($p3 === ($p1 || $p2)){
            shuffle($positions);
            $p3 = $positions; 
            $b++; 
            echo '<br>=b=<br>'.$b.'<br>==<br>';
            //if($p2 == ($p1 || $p2)){continue;}else{break;}
        }       
    }
    echo '<tr>';
    foreach($p3 as $pC){
        echo '<td>'.$pC.'</td>';
    }   
    echo '</tr>';



    shuffle($positions);
    $p4 = $positions;
    if($p4 === ($p1 || $p2 || $p3)){    
        while($p4 === ($p1 || $p2 || $p3)){
            shuffle($positions);
            $p4 = $positions; 
            $c++; 
            echo '<br>=c=<br>'.$c.'<br>==<br>';
            //if($p2 == ($p1 || $p2)){continue;}else{break;}
        }       
    }
    echo '<tr>';
    foreach($p4 as $pD){
        echo '<td>'.$pD.'</td>';
    }   
    echo '</tr>';



    shuffle($positions);
    $p5 = $positions;
    if($p5 === ($p1 || $p2 || $p3 || $p4)){ 
        while($p5 === ($p1 || $p2 || $p3 || $p4)){
            shuffle($positions);
            $p5 = $positions; 
            $d++; 
            echo '<br>=d=<br>'.$d.'<br>==<br>';
            //if($p2 == ($p1 || $p2)){continue;}else{break;}
        }       
    }
    echo '<tr>';
    foreach($p5 as $pE){
        echo '<td>'.$pE.'</td>';
    }   
    echo '</tr>';


    shuffle($positions);
    $p6 = $positions;
    if($p6 === ($p1 || $p2 || $p3 || $p4 || $p5)){  
        while($p6 === ($p1 || $p2 || $p3 || $p4 || $p5)){
            shuffle($positions);
            $p6 = $positions; 
            $e++; 
            echo '<br>=d=<br>'.$e.'<br>==<br>';
            //if($p2 == ($p1 || $p2)){continue;}else{break;}
        }       
    }
    echo '<tr>';
    foreach($p6 as $pF){
        echo '<td>'.$pF.'</td>';
    }   
    echo '</tr>';



    shuffle($positions);
    $p7 = $positions;
    if($p7 === ($p1 || $p2 || $p3 || $p4 || $p5 || $p6)){   
        while($p7 === ($p1 || $p2 || $p3 || $p4 || $p5 || $p6)){
            shuffle($positions);
            $p7 = $positions; 
            $f++; 
            echo '<br>=d=<br>'.$f.'<br>==<br>';
            //if($p2 == ($p1 || $p2)){continue;}else{break;}
        }       
    }
    echo '<tr>';
    foreach($p7 as $pG){
        echo '<td>'.$pG.'</td>';
    }   
    echo '</tr>';

    shuffle($positions);
    $p8 = $positions;
    if($p8 === ($p1 || $p2 || $p3 || $p4 || $p5 || $p6 || $p7)){    
        while($p8 === ($p1 || $p2 || $p3 || $p4 || $p5 || $p6 || $p7)){
            shuffle($positions);
            $p8 = $positions; 
            $g++; 
            echo '<br>=d=<br>'.$g.'<br>==<br>';
            //if($p2 == ($p1 || $p2)){continue;}else{break;}
        }       
    }
    echo '<tr>';
    foreach($p8 as $pH){
        echo '<td>'.$pH.'</td>';
    }   
    echo '</tr>';



    shuffle($positions);
    $p9 = $positions;
    if($p9 === ($p1 || $p2 || $p3 || $p4 || $p5 || $p6 || $p7 || $p8)){ 
        while($p9 === ($p1 || $p2 || $p3 || $p4 || $p5 || $p6 || $p7 || $p8)){
            shuffle($positions);
            $p9 = $positions; 
            $h++; 
            echo '<br>=d=<br>'.$h.'<br>==<br>';
            //if($p2 == ($p1 || $p2)){continue;}else{break;}
        }       
    }
    echo '<tr>';
    foreach($p9 as $pI){
        echo '<td>'.$pI.'</td>';
    }   
    echo '</tr>';



    shuffle($positions);
    $p10 = $positions;
    if($p10 === ($p1 || $p2 || $p3 || $p4 || $p5 || $p6 || $p7 || $p8 || $p9)){ 
        while($p10 === ($p1 || $p2 || $p3 || $p4 || $p5 || $p6 || $p7 || $p8 || $p9)){
            shuffle($positions);
            $p10 = $positions; 
            $i++; 
            echo '<br>=d=<br>'.$i.'<br>==<br>';
            //if($p2 == ($p1 || $p2)){continue;}else{break;}
        }       
    }
    echo '<tr>';
    foreach($p10 as $pJ){
        echo '<td>'.$pJ.'</td>';
    }   
    echo '</tr>';


    echo '</table>';


?>
  • 写回答

1条回答 默认 最新

  • dongwei7048 2017-02-26 12:44
    关注

    James, I know it can be hard when you have a bunch of allstars and you want to be a fair coach who gives everyone an equal shot. Randomizing code to the rescue. The only thing this table doesn't account for is roster fluctuations -- if you have a sick/injured player, you will have to make an adjustment.

    This code will output the grid that you are looking for. While it is not optimized for speed, it only takes ~.25 seconds to complete -- so performance is not going to be an issue for your case. Performance Test

    <?php
    $players=array(
        "Mickey Mantle",
        "Babe Ruth",
        "Yogi Berra",
        "Lou Gehrig",
        "Joe DiMaggio",
        "Derek Jeter",
        "Whitey Ford",
        "Roger Maris",
        "Reggie Jackson"
    );
    $positions=array("P","C","1","2","SS","3","LF","CF","RF");
    $batch=array();
    
    echo "<table border=1>";
    echo "<tr><th>#</th><th>",implode("</th><th>",$players),"</th></tr>";
        for($week=1; $week<11; ++$week){
            if($week==9){
                // see what's missing (use remaining value versus needless looping)
                foreach($players as $i=>$v){
                    $batch[$week][$i]=current(array_diff($positions,array_column($batch,$i)));
                }
            }elseif($week==10){
                // purely random, as every player has played every position by now.
                shuffle($positions);
                $batch[$week]=$positions;           
            }else{    // weeks 1 - 8
                while(!isset($batch[$week])){
                    shuffle($positions);
                    $batch[$week]=$positions;
                    //echo "<tr><td>",implode("</td><td>",$batch[$week]),"</td></tr>";
                    if($week>1){     // check for no duplicate positions for any player
                        foreach($batch[$week] as $i=>$v){
                            //echo "<tr><td colspan=9>",implode(', ',array_column($batch,$i)),"</td></tr>";
                            if(sizeof(array_unique(array_column($batch,$i)))<$week){  // if vertical duplicates
                                unset($batch[$week]);   // trash the week, trigger rerun of loop
                                break;  // don't bother to assign positions for remaining players
                            }
                        }
                    }
                }
            }
            echo "<tr><th>$week</th><td>",implode("</td><td>",$batch[$week]),"</td></tr>";
        }
    echo "</table>";
    ?>
    

    Output:

    PositionSchedule

    If my code doesn't earn your green tick of approval, please clarify your question with an edit. I am happy to explain any of the lines if you have questions. Truth is, I loved this challenge; I'd like one of these per week!


    Answer Extension -- a function with improved flexibility and efficiency

    To be honest, I never did actually quit working on this -- I'm just not very good at letting things go unresolved. Your invoice is in the mail ;)

    THIS IS BY NO MEANS PERFECT -- don't go and try to sell it! I have tested the following function/code using 9 innings/periods, 9 positions, and (9, 13, and 18) players and I wasn't able to break it.

    When I set the periods to 4 while the roster and positions are much higher, it did break. This may be a matter of logic that a mathematician could explain in detail -- I'm not going to go down that rabbit hole.

    I am leaving all of my comments and debugging echos in place, in case anyone needs to understand/modify/improve it in the future.

    Please read the fineprint just before the function call.

    function fairRotation($roster=[],$positions=[],$rotations=9,$off="X"){
        $roster_count=sizeof($roster);
        $positions_count=sizeof($positions);
        echo "<div>roster_count=$roster_count, positions_count=$positions_count</div>";
        $ons_avg=$positions_count/$roster_count;
        $ons_max=ceil($ons_avg);
        $ons_min=floor($ons_avg);
        echo "<div>ons_avg=$ons_avg, ons_max=$ons_max, ons_min=$ons_min</div>";
        $off_avg=($roster_count-$positions_count)*$rotations/$roster_count;
        $off_max=ceil($off_avg);
        $off_min=floor($off_avg);
        echo "<div>off_avg=$off_avg, off_max=$off_max, off_min=$off_min</div><br>";
        $positions=array_pad($positions,$roster_count,$off);  // sync positions with roster using sub identifier    
        $positions_count=sizeof($positions);    // overwrite with updated count
        for($r=0; $r<$rotations; ++$r){
            shuffle($positions);
            $result[$r]=$positions;
        }
        //$color_result=$result;
        // unfiltered result:
        /*echo "<table border=1>";
            echo "<tr><th>#</th><th>",implode("</th><th>",$roster),"</th></tr>";
            foreach($result as $key=>$row){
                echo "<tr><th>",($key+1),"</th><td>",implode("</td><td>",$row),"</td></tr>";
            }
        echo "</table>";    */
    
        // Assess result and address conflicts...
        $iterations=0;
        $fair="?";
        $must_drop_count=0;
        $must_gain_count=0;
        while($fair!="true" && $iterations<500){
            $must_gain=$must_drop=$may_gain=$may_drop=[];  // reset
            for($c=0; $c<$roster_count; ++$c){  // triage each column
                $col=array_column($result,$c);
                $val_counts[$c]=array_merge(array_fill_keys($positions,0),array_count_values($col));
                foreach($val_counts[$c] as $pos=>$cnt){
                    if(($pos!=$off && $cnt<$ons_min) || ($pos==$off && $cnt<$off_min)){
                        $must_gain[$c][$pos]=array_keys($col,$pos);  // column/player must gain this position, but not where row = value(s)
                    }elseif(($pos!=$off && $cnt>$ons_max) || ($pos==$off && $cnt>$off_max)){
                        $must_drop[$c][$pos]=array_keys($col,$pos);  // column/player must drop this position, but only where row = value(s)
                    }elseif(($pos!=$off && $cnt<$ons_max) || ($pos==$off && $cnt<$off_max)){
                        $may_gain[$c][$pos]=array_keys($col,$pos);  // column/player may gain this position, but not where row = value(s)
                    }elseif(($pos!=$off && $cnt>$ons_min) || ($pos==$off && $cnt>$off_min)){
                        $may_drop[$c][$pos]=array_keys($col,$pos);  // column/player may drop this position, but only where row = value(s)
                    }
                }
            }
    
            if(sizeof($must_gain)==0 && sizeof($must_drop)==0){
                $fair="true";
            }elseif(sizeof($must_drop)==$must_drop_count && sizeof($must_gain)==$must_gain_count){
                //var_export($must_drop);
                //echo "<br>Program Deadlock @ $iterations Iterations.";
                //echo "<br>Desperately reshuffle one of the deadlocked rows.";
                shuffle($positions);
                if($must_drop_count>0){
                    $result[current(current(current($must_drop)))]=$positions;
                    //$color_result[current(current(current($must_drop)))]=$positions;
                }else{
                    $result[current(current(current($must_gain)))]=$positions;
                    //$color_result[current(current(current($must_gain)))]=$positions;
                }
            }else{
                $must_drop_count=sizeof($must_drop);
                $must_gain_count=sizeof($must_gain);
                //echo "<br><div>MustDrop:$must_drop_count , MustGain:$must_gain_count</div>"; 
    
                foreach($must_drop as $d1col=>$d1array){  // $must_drop1[0]["SS"]=array(3,8);
                    ++$iterations;
                    //echo "<div>({$iterations}x): {$roster[$d1col]} must drop ";
                        //var_export($d1array);
                        foreach($d1array as $d1pos=>$d1keys){
                            foreach(array_diff_key($must_drop,array($d1col=>"")) as $d2col=>$d2array){  // dual-solution swap
                                foreach($d2array as $d2pos=>$d2keys){
                                    //echo "<div>..seeking a new home for $d1pos</div>";
                                    if($d1pos!=$d2pos && (isset($must_gain[$d1col][$d2pos]) || isset($may_gain[$d1col][$d2pos]))){
                                        //echo "<div>{$roster[$d1col]} may drop $d1pos for {$roster[$d2col]}'s $d2pos</div>";
                                        foreach($d2keys as $row){
                                            //echo "<div>checking {$roster[$d2col]}'s row($row) holding $d2pos vs {$roster[$d1col]}'s $d1pos ";
                                            //var_export($d1keys);
                                            //echo "</div>";
                                            if(in_array($row,$d1keys)){
                                                //echo "<div>row match on $row between {$roster[$d1col]} & {$roster[$d2col]}</div>";
                                                if(isset($must_gain[$d1col][$d2pos])){
                                                    //echo "<div>Success: {$roster[$d1col]} must gain holds $d2pos</div>";
                                                    //$color_result[$row][$d1col]="<span style='background-color:green;'>$d2pos</span>";
                                                    //$color_result[$row][$d2col]="<span style='background-color:blue;'>$d1pos</span>";
                                                    $result[$row][$d1col]=$d2pos;
                                                    $result[$row][$d2col]=$d1pos;
                                                    //var_export($result[$row]);
                                                    //echo "<br>";
                                                    //unset($must_drop[$d1col][$d1pos],$must_gain[$d2col][$d2pos],$must_gain[$d1col][$d2pos],$must_gain[$d2col][$d1pos]);
                                                    break(5);
                                                }elseif(isset($may_gain[$d1col][$d2pos])){
                                                    //echo "<div>Success: {$roster[$d1col]} may gain holds $d2pos</div>";
                                                    //$color_result[$row][$d1col]="<span style='background-color:red;'>$d2pos</span>";
                                                    //$color_result[$row][$d2col]="<span style='background-color:orange;'>$d1pos</span>";
                                                    $result[$row][$d1col]=$d2pos;
                                                    $result[$row][$d2col]=$d1pos;
                                                    //var_export($result[$row]);
                                                    //echo "<br>";
                                                    //unset($must_drop[$d1col][$d1pos],$must_gain[$d2col][$d2pos],$may_gain[$d1col][$d2pos],$may_gain[$d2col][$d1pos]);
                                                    break(5);
                                                }else{
                                                    //echo "<div>No Eligible Swap: {$roster[$d1col]} doesn't need/want $d2pos @ row$row";
                                                    //var_export(array_merge(array(),$must_gain[$d1col],$may_gain[$d1col]));
                                                    //echo "</div>";
                                                }
                                            }
                                            //echo "<br>";
                                        }
                                    }
                                }
                            }                   
                        }
                    //echo "</div><br>";
                }
    
            }
        }
        if($fair=="true"){
            echo "<div>FAIR! after $iterations adjustments</div>";
            return $result;  // $color_result for color
        }else{
            echo "Runaway Deadlock, Call Full Rerun<br>";
            return false;
        }
    }
    
    $roster=array(
        "Mickey Mantle","Babe Ruth","Yogi Berra","Lou Gehrig","Joe DiMaggio",
        "Derek Jeter","Whitey Ford","Roger Maris","Reggie Jackson","sub1","sub2","sub3","sub4","sub5","sub6","sub7","sub8","sub9");
    $positions=array("P","C","1st","2nd","SS","3rd","LF","CF","RF");
    $rotations=9; // rotating each inning of a 9 inning baseball game
    
    // roster array must be larger than positions array
    // if roster is short, remove positions which will be vacant
    // values in the positions array MUST NOT be purely numeric, due to array_fill_keys() type-feature/glitch
    // subs/inactive assignments will be marked by an X, unless otherwise declared in the function call
    
    $result=false;
    while(!$result){
        $result=fairRotation($roster,$positions,$rotations);
    }
    
    echo "<table border=1>";
        echo "<tr><th>#</th><th>",implode("</th><th>",$roster),"</th></tr>";
        foreach($result as $key=>$row){
            echo "<tr><th>",($key+1),"</th><td>",implode("</td><td>",$row),"</td></tr>";
        }
    echo "</table>";
    

    Displays something like this:

    PosSched2

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 在不同的执行界面调用同一个页面
  • ¥20 基于51单片机的数字频率计
  • ¥50 M3T长焦相机如何标定以及正射影像拼接问题
  • ¥15 keepalived的虚拟VIP地址 ping -s 发包测试,只能通过1472字节以下的数据包(相关搜索:静态路由)
  • ¥20 关于#stm32#的问题:STM32串口发送问题,偶校验(even),发送5A 41 FB 20.烧录程序后发现串口助手读到的是5A 41 7B A0
  • ¥15 C++map释放不掉
  • ¥15 Mabatis查询数据
  • ¥15 想知道lingo目标函数中求和公式上标是变量情况如何求解
  • ¥15 关于E22-400T22S的LORA模块的通信问题
  • ¥15 求用二阶有源低通滤波将3khz方波转为正弦波的电路