2015-12-30 11 views
7

私は、0-5のマーキングでどこからでも戦うためのランダムな動物を生成するブラウザゲームのスクリプトを作成しています。その動物のマーキングは無作為に生成され、配列に現れる順番にそれらを追加するカスタムimagick関数に送られます。不確実なデータで配列を並べ替える

マーキングはランダムに決定されますが、動物にどのように表示されるのかについては多くのルールがあります。たとえば、「全身」領域のマーキングは「腹」領域のマーキングの上に表示されます。良く説明するために、私はこれまで、テスターの画像を添付します:

enter image description here

だから、このランダムに生成された動物の5つのマーキングを打破するために、マーキング eyeshadowは、目領域に属し

undertailは尾に属し、streaksはfullbodyに属し、appaloosaは後ろに属し、okapiは脚に属します。今すぐ注文は、データベースをループしたスクリプトと無作為に選択されたマーキングとして追加されます。そのため、okapi(脚の縞模様)は配列の最後にあり、最後に追加されたものです。しかし、注文ルールに従って、アレイ内の最後のものは、フルボディマーキングが上に上がるため、ストリーク(身体全体の水平ストリーク)であったはずです。私はif文の複合体の多くでこれを達成することができます理解

// 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; 
      } 
     } 
    } 

それだけでエレガントなように見えるしていません。ここで

これはLaravelのエンジンを使用して行われ、コード選択マーキングです解決策さらに、フルボディマーキングである「グラディエント」は、フルボディマーキングであるにもかかわらずすべての下にあります。これまでのところ、この種の例外は唯一のマーキングです。

私は様々なsort関数をPHPで提供してみましたが、私は大したことはありません。 uksortがもっとも有望ですが、ソートしている値はデータベースに存在し、ソートしている配列ではないので(imagick関数にはマーキング=>カラー配列形式を与えなければなりません)、作業が困難です。

Tl; dr:キーのDB(マーキングの領域)に存在する値に基づいて不確実な量のデータを並べ替える必要があります。これを達成する最もエレガントな方法は何ですか?

+0

私は奇妙な見たいの犬であっても、犬のイメージが好きです。 – Phiter

+0

ハハ!それは変な犬だよね? –

+0

'DataMarking'テーブルに' z-index'(int)カラムが必要です。このプロパティは深度として機能します。たとえば、「アイシャドー」の「z-インデックス」は1とすることができ、「ストリーク」の「z-インデックス」は5とすることができる。「z-インデックス」が高いほどマーキングが引き出され、 「ストリーク」は他のすべての上に描かれています。 マーキングの配列を検索した後、昇順で 'z-index'で並べ替えます。それをループして、すべてのマーキングを描きます。 – Alexander

答えて

4

をやっていることで失われますが、あなたのコードにいくつかの最適化され、行われたかを説明するインラインコメントがあります。これは、明らかにMarcin氏が答えて指摘したことがあるほど良くなるため、終了していません。

// Determine number of markings 
    $num = mt_rand(1,10); 

    // Removed redundent $num > X as the conditions were already meet that it was > X by the previous if statement 
    if ($num == 1) { 
     $markingNum = 0; 
    } else if ($num < 4) { 
     $markingNum = 1; 
    } else if ($num < 6) { 
     $markingNum = 2; 
    } else if ($num < 8) { 
     $markingNum = 3; 
    } else if ($num < 10) { 
     $markingNum = 4; 
    } else { 
     $markingNum = 5; 
    } 

    // Calculate Marking type and color 
    $markings = array(); 

    if ($markingNum > 0) { 
     for ($m = 1 ; $m <= $markingNum; $m++) { // incrimented to 1 and <= so we can dynamically select elements 
      // Set color values (pulls from the "pallet" selected earlier in the code, which will determine the range of color that marking can be) 
      $pal = $pallet->{'marking' . $m}; // Removed if/else and replaced with a dynamic variable 


      // Uncommon marking (10% chance) 
      $r = mt_rand(1, 10); 

      // removed duplicate database selections for a simple $rarity variable that accomplishes the same task 
      if ($r == 10) { 
       $rarity = 1; 
      } else { 
       $rarity = 0; 
      } 

      $marking = DataMarking::where('rarity', $rarity) 
            ->where('public', 1) 
            ->whereNotIn('name', array_keys($markings)) 
            ->whereNotIn('region', $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] = $marking; // adds all of the marking data, this is where you could have a z-index in the database 
      $markings[$marking->name] = $markingColor; // add your color to your marking data 
      $regions[] = $marking->region; 

     } 
    } 
2

私はあなたの質問に答えませんが、あなたのコードを見ると、改善のためのスペースがたくさんあります。

この考えてみましょう:

$marking = DataMarking::where('rarity', ($r == 10) ? 1 : 0) 
         ->where('public', 1) 
         ->whereNotIn('name', array_keys($markings)) 
         ->whereNotIn('region', array_keys($regions)) 
         ->orderByRaw("RAND()") 
         ->first(); 
:に書き換えることができれば

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(); 
} 

:用

$pa1 = (in_array($m,range(1,4))) ? $pallet->marking{$m} : $pallet->marking5; 

同じ:それははるかに簡単な何かを変更することができ

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; 
} 

もちろん、上記のORDER BY RAND()は、パフォーマンス上の理由から最良の解決策ではない可能性があります。

あなたが本当にあなたのコードとの重複の量を気にしなければならないか、あなたはすぐにあなたがここ

+0

ヒントありがとうございました! –