Zawieszenie programu podczas próby odpalenia programu "szyfrującego"

0

Witam wszystkich.

Próbowałem napisać w Delphi program na zajęcia, który zajmowałby się szyfrowaniem.
Szyfrowanie miałoby polegać na wydzieleniu przez program paczek po 2 znaki w całym wprowadzonym ciągu i wymieszaniu ich wg poniższego wzoru:

aabbccddeeffgghhiijj => bbaaddccffeehhggjjii [zamiana pierwszej i drugiej paczki, zamiana trzeciej z czwartą itd]

Niestety podczas ciężkiej pracy z kodem doszedłem do pewnych rezultatów, lecz wszystko działało gdy pracowałem na wcześniej określonych tablicach, które przechowywały paczki. Gdy przerobiłem program na wersję o dowolnej ilości znaków powstał problem, że program się odpala, ale po kliknięciu na przycisk następuje zawieszenie programu.

Oto kod jaki udało mi się stworzyć:

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    Label5: TLabel;
    zdanie: TEdit;
    Edit2: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    procedure Edit1Change(Sender: TObject);
    procedure zdanieChange(Sender: TObject);
    procedure Button1Click(Sender: TObject);

  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
var

   tekst:String;
   tekst_po:String;            {tekst po ustaleniu parzystosci}
   liczba_znakow:Integer;
   liczba_znakow_po:Integer;   {tekst po ustaleniu parzystosci}
   liczba_paczek:Integer;
   tablica:array of String;
   tablica1:array of String;
   parzysta:boolean;
   petla:Integer;
   x:Integer;
   y:Integer;
   z:Integer;
   wynik:String;
   wynik1:String;



begin

 {liczenie ilosci znakow}
  tekst:=zdanie.Text;
  liczba_znakow:=length(zdanie.Text);
  Label1.Caption:=IntToStr(liczba_znakow);

  {sprawdzanie, czy liczba zakow jest parzysta jesli nie to dodajemy znak spacji, zeby bylo parzyscie}
  begin
  parzysta:=(liczba_znakow mod 2 = 0);
  if parzysta then tekst_po:=tekst
  else tekst_po:=tekst+#32;
  end;


  {ustawienia parametrow tablicy}
  SetLength(tablica, liczba_znakow);

  {liczenie ilosci znakow}
  liczba_znakow_po:=length(tekst_po);
  liczba_paczek:=liczba_znakow_po div 2;
  Label4.Caption:=IntToStr(liczba_paczek);



  {petla zapisywania paczek znakow do tablicy}
  x:=1;
  petla:=0;
  while petla<liczba_paczek do
  begin
  tablica[petla]:=Copy(tekst_po,x,2);
  inc(petla);
  inc(x,2);
end;

  {ustawienia parametrow tablicy1}
  SetLength(tablica1, liczba_znakow);

  {zamiana paczek miejscami=> tablica na tablica1}
  y:=0;
   while y<liczba_paczek+1 do
   begin
   tablica1[y]:=tablica[y+1];
   tablica1[y+1]:=tablica[y];
   Inc(y,2);
   end;

   {Sklejanie paczek}
   z:=0;
   wynik1:=tablica1[0];
   while z<liczba_paczek do
    begin
   wynik:=wynik1+tablica1[z+1];
   end;

  {wyswietlenie wyniku}
   Edit2.Caption:=wynik;
  end;

end.
 

Bardzo prosiłbym o pomoc i wsparcie. Chciałbym napisać kod w miarę najprostszy, ponieważ dopiero zaczynam programować i chciałbym wszystko zrozumieć - nawet jeśli trzeba będzie rozpisać kod na kilka linijek, aby obejść problem okrężną drogą. Proszę wybaczyć za chaos panujący w kodzie.

Z góry dziękuję za pomoc

3
var str:String;
var ch:Char;
var i,k,len:Integer;
begin
  str:=zdanie.Text;
  len:=Length(str);
  i:=1;
  while i<len do
  begin
    for k:=i to i+1 do
    begin
      if k+2<=len then
      begin
        ch:=str[k];
        str[k]:=str[k+2];
        str[k+2]:=ch;
      end;
    end;
    inc(i,4);
  end;
  Edit2.Caption:=str;
end;
0

Dzięki wielkie. Chyba trochę za bardzo chciałem wszystko rozbudować.
U mnie to 2 dni roboty, a u kolegi chwilę - szacun!

0
procedure CodeOrDecode(const AInput: AnsiString; var AOutput: AnsiString);
var
  intLoop: Integer;
begin
  SetLength(AOutput, Length(AInput));
  intLoop := 1;

  while intLoop < Length(AInput) - 1 do
  begin
    Move(AInput[intLoop], AOutput[intLoop + 2], 2);
    Move(AInput[intLoop + 2], AOutput[intLoop], 2);
    Inc(intLoop, 4);
  end;
end;

W przypadku, gdy wejściowa "paczka" ma długość niepodzielną przez 4, taką paczkę podczas jej tworzenia trzeba dopełnić; A sam algorytm szyfrowania i tym samym deszyfrowania jest tak prosty, jak pokazałem wyżej.

1

@furious programming Jeżeli zagwarantowana podzielność to można jeszcze prościej:

function CodeOrDecode(const Str:AnsiString):String;
var I:Integer;
begin
  SetLength(Result,Length(Str));
  for I:=1 to Length(Result) do Result[I]:=Str[((I-1)xor(2))+1];
end;
0

@_13th_Dragon - podzielność musi być zagwarantowana, bo inaczej algorytm będzie zupełnie nieoptymalny - dla każdej paczki trzeba będzie wykonywać zbędne czynności, zamiast działać z minimalnym kosztem; A tak to można śmiało swapować na sztywno, a na koniec jedynie usunąć dopełnienie już z całego bufora;

Moje rozwiązanie miało być czytelne i zrozumiałe dla pytacza, ale pomysł z **Xor**owaniem ciekawy - obadam.

0

Właśnie jeśli chodzi o mnie to zależało mi na poprawie mojego jakże skomplikowanego kodu na początku, albo czytelnego innego sposobu. Niestety robię ten program na zajęcia, a mój "nauczyciel" przeprowadził z nami łącznie 3h kursu. Szybko doszedł do pętli i na tym skończył. Trochę poczytałem na temat tablic i sposób na tablicach wydawał mi się w miarę klarowny, ale pomysł @_13th_Dragon również przypadł mi do gustu, bo jest czytelny i szybko go pojąłem. W sumie oparty na pętlach, więc nie będę się musiał tłumaczyć skąd umiem inne komendy itd. Oczywiście nie mam zamiaru skopiować kodu, tylko napisać podobny program jeszcze raz w celu nauki :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1