Показать сообщение отдельно
  #4  
Старый 09.02.2015, 20:59
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,100
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Делал подобную задачу - перемешивание колоды карт.
Собственно, проблема данной задачи в том, что при прямой генерации для исключения повторения сгенерированного значения необходимо заного его генерировать. Такой алгоритм приводит к практически бесконечной генерации в конце списка.
Примененное решение заключалось в том, что производится не генерация самих значений (их список известен и конечен), а генерация их места в итоговом списке. Если позиция уже занята, то происходит просто поиск следующей свободной позиции (сдвиг).

Вот пример генерации:
Код:
procedure GetNumbers(var A : Array of Integer);
var
  I, Idx : Integer;
  B : Array [0..8] Of Integer;
begin
  If (Length(A) > 9) Or (Length(A) < 1)
    Then Raise Exception.Create('Input array should have length 1 to 9. ');

  // Init temp arrray
  For I := 0 to 8 Do B[i] := 0;

  // Generate list
  For I := 1 to 9 Do
    Begin
      Idx := Random(9);
      While B[Idx] <> 0 Do
        If Idx = 8 Then Idx := 0 Else Inc(Idx);
      B[Idx] := I;
    End;

  // Copy result to output array
  For I := Low(A) To High(A) Do A[i] := B[i];
end;

Пример использования. Пусть будут римские цифры:
Код:
// Return rome 1..9
function IntToRome(Value : Integer) : String;
const
  Romes : Array [1..9] Of String =
    ('I','II','III','IV','V','VI','VII','VIII','IX');
begin
  If Not (Value In [1..9]) 
    Then Raise Exception.Create('Value should be in range 1..9.');
  Result := Romes[Value];
end;

procedure Form1.Button1Click(Sender : TObject);
var
  N, I : Integer;
  A : Array Of Integer;
  S : String;
begin
  Randomize;
  N := Random(9)+1; // Random number of digits 1..9
  SetLength(A,N); // prepare the array
  GetNumbers(A); // Get values

  // Prepare and show result
  S := '';
  For I := Low(A) To High(A) Do
    Begin
      S := S + IntToRome(A[i]);
      If I < High(A) Then S := S + ', ';
    End;
  ShowMessage(S);
end;
Ответить с цитированием