2016-07-20 31 views
0

Dies ist eher eine Diskussion als eine Frage per se, da ich dies mit Code lösen könnte, aber ich denke, es sollte bessere Möglichkeiten geben, dies zu tun.Elemente in einer Matrix beliebiger Größe anordnen

Ich muss Elemente in einer Matrix so verteilen, dass jeder Quadrant der Matrix (welche Dimensionen nicht unbedingt durch 4 teilbar sind) eine gleiche (oder so nahe wie möglich) Anzahl der Elemente enthält, aber zufällig angeordnet ist innerhalb dieses Quadranten. Der Rest der Matrix muss zufällige Elemente eines anderen Typs enthalten.

Zum Beispiel der Verteilung von 10 Elementen (A) in einer 9x6-Matrix könnte wie folgt aussehen:

enter image description here

Welche das Problem, was mit den Mittellinien zu tun, zeigt, wenn eine Dimension ungerade ist. Es könnte auf dem einen oder dem anderen Quadranten enthalten sein (die Tatsache, dass es keine As in den 3 mittleren Spalten gibt, ist Zufall)

Ich dachte zuerst daran, dies mit einer rekursiven Funktion zu behandeln, die sich in Quadranten und zufällige Orte aufteilt jedes Element.

Ich bin auf halbem Weg durch Codierung dies in C#, die Idee ist, so etwas wie diese (es funktioniert nicht als die noch und einige Dinge sind ineffizient, um zu versuchen den Code besser lesbar zu machen):

private void PopulateQuadrants(ref Test5Target[,] matrix, 
     int xBeginQuadrant, int xEndQuadrant, int yBeginQuadrant, int yEndQuadrant, int targets) 
    { 
     if (targets == 0) 
     { 
      return; 
     } 
     else if (targets == 1) 
     { 
      Random rand = new Random(); 
      matrix[rand.Next(xBeginQuadrant, xEndQuadrant), rand.Next(yBeginQuadrant, yEndQuadrant)] 
       = new Test5Target(ChosenTarget, UseAdvancedTargets); 
      for (int x = xBeginQuadrant; x < xEndQuadrant; x++) 
      { 
       for (int y = xBeginQuadrant; y < xEndQuadrant; y++) 
       { 
        if (matrix[x, y] == null) 
        { 
         int type = rand.Next(TargetCount); 
         while(type == ChosenTarget){ 
          type = rand.Next(TargetCount); 
         } 

         matrix[x, y] = new Test5Target(rand.Next(TargetCount), UseAdvancedTargets); 
        } 
       } 
      } 

      return; 
     } 
     else 
     { 
      int[] TargetsPerQuadrant = { targets/4, targets/4, targets/4, targets/4 }; 
      int RemaindingTargets = targets % 4; 
      Random rand = new Random(); 
      while (RemaindingTargets > 0) 
      { // Randomly select quadrants to allocate the Remainding targets (one may end up with 3 extra as it is now) 
       TargetsPerQuadrant[rand.Next(4)]++; 
       RemaindingTargets--; 
      } 
      PopulateQuadrants(ref matrix, xBeginQuadrant, xEndQuadrant/2, yBeginQuadrant, yEndQuadrant/2, TargetsPerQuadrant[0]); 
      PopulateQuadrants(ref matrix, xEndQuadrant/2, xEndQuadrant, yBeginQuadrant, yEndQuadrant/2, TargetsPerQuadrant[1]); 
      PopulateQuadrants(ref matrix, xBeginQuadrant, xEndQuadrant/2, yBeginQuadrant, yEndQuadrant/2, TargetsPerQuadrant[2]); 
      PopulateQuadrants(ref matrix, xEndQuadrant/2, xEndQuadrant, yBeginQuadrant/2, yEndQuadrant, TargetsPerQuadrant[3]); 
     } 
    } 

Gibt es mathematisch korrekte oder einfache oder etwas, um dies zu erreichen oder sollte ich auf diese Weise weitermachen?

Antwort

0

Ich entschied mich schließlich, nur ein Viertel aller Elemente zufällig in jede Ecke zu legen, und der Rest ignorierte zufällig auch ungerade Längen oder ließ es einfach nach der einen oder anderen Seite laufen.

private Element[,] GetCancellationTestMatrix(int rows, int columns, int targets, int types) 
    { 
     // Supposing the different types of elements are just ints and we want a concrete type 
     // for our targets which is contained in the variable "TargetType" 
     Element[,] Matrix = new int[rows, columns]; 

     Random rand = new Random(); 
     int currQuadRowBegin = 0; 
     int currQuadRowEnd = rows/2; 

     int currQuadColBegin; 
     int currQuadColEnd; 

     int rowIndex; 
     int colIndex; 
     for (int i = 0; i < 2; i++) 
     { 
      currQuadColBegin = 0; 
      currQuadColEnd = columns/2; 
      for (int j = 0; j < 2; j++) 
      { 
       for (int t = 0; t < targets/4; t++) 
       { 
        rowIndex = rand.Next(currQuadRowBegin, currQuadRowEnd); 
        colIndex = rand.Next(currQuadColBegin, currQuadColEnd); 
        while (Matrix[rowIndex, colIndex] != null) 
        { 
         rowIndex = rand.Next(currQuadRowBegin, currQuadRowEnd); 
         colIndex = rand.Next(currQuadColBegin, currQuadColEnd); 
        } 
        Matrix[rowIndex, colIndex] = new Element(TargetType); 
       } 
       currQuadColBegin = currQuadColEnd++; 
       currQuadColEnd = columns - 1; 
      } 
      currQuadRowBegin = currQuadRowEnd++; 
      currQuadRowEnd = rows - 1; 
     } 

     // Some targets may be unarranged yet (up to three) 
     int remainding = targets % 4; 
     while (remainding > 0) 
     { 
      rowIndex = rand.Next(0, rows); 
      colIndex = rand.Next(0, columns); 
      while (Matrix[rowIndex, colIndex] != null) 
      { 
       rowIndex = rand.Next(0, rows); 
       colIndex = rand.Next(0, columns); 
      } 
      Matrix[rowIndex, colIndex] = new Element(TargetType); 
      remainding--; 
     } 

     // Fill the remainding elements of the target matrix with other targets 
     List<int> fakeTargets = new List<int>(rows * columns - targets); 
     // If we are placing 10 targets in a 9x6 matrix then we need to place an extra 
     // 9 * 6 - 10 = 34 targets and if we have, say, 4 types then we can divide that 
     // between 4-1 (for the target type) 
     int targetsOfEachType = (rows * columns - targets)/types-1; 
     for (int i = 0; i < types; i++) 
     { 
      if (i == TargetType) continue; 
      for (int j = 0; j < targetsOfEachType; j++) 
      { 
       fakeTargets.Add(i); 
      } 
     } 
     int tmp; 
     while (fakeTargets.Count < rows * columns - targets) 
     { 
      tmp = rand.Next(types); 
      while (tmp == TargetType) 
      { 
       tmp = rand.Next(types); 
      } 
      fakeTargets.Add(tmp); 
     } 
     Shuffle(fakeTargets); // Assume this method shuffles the list of fakeTargets 
     tmp = 0; 
     for (int i = 0; i < rows; i++) 
     { 
      for (int j = 0; j < columns; j++) 
      { 
       if (Matrix[i, j] != null) continue; 
       Matrix[i, j] = new Element(fakeTargets[tmp++]); 
      } 
     } 
     return Matrix; 
    } 

Natürlich, ich bin nicht behaupten, ist eine gute Lösung, nur eine, die zumindest für jetzt für mich arbeitet. Ich werde etwas Zeit lassen, damit jemand eine bessere Antwort oder einige Korrekturen über meine geben kann, bevor ich das als Antwort ansehe.