Advertisement
Guest User

PathFinder

a guest
Jun 1st, 2011
417
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 7.25 KB | None | 0 0
  1. program PathFinder;
  2.  
  3. {$APPTYPE CONSOLE}
  4.  
  5. uses
  6.   SysUtils,
  7.   Windows,
  8.   Graphics;
  9.  
  10. type
  11.   TNode = record
  12.     E, L: integer;
  13.     X, Y: integer;
  14.     S, D: PColor;
  15.   end;
  16.  
  17.   THeap = array of TNode;
  18.  
  19. const
  20.   MinW = 200;
  21.   dx: array [0 .. 7] of integer = (-1, 1, 0, 0, -1, -1, 1, 1);
  22.   dy: array [0 .. 7] of integer = (0, 0, -1, 1, -1, 1, 1, -1);
  23.   dL: array [0 .. 7] of integer = (65536, 65536, 65536, 65536, 92682, 92682, 92682, 92682);
  24.   DirCounts: array [0 .. 1] of integer = (4, 8);
  25.  
  26. var
  27.   x1,y1,x2,y2: integer;
  28.   W,H: integer;
  29.   i: integer;
  30.   DirC: integer;
  31.   ColorShift: array [0 .. 7] of integer;       // для указателеёбства с пикселами битмапов
  32.   S: string;
  33.   bmP, bmL, bmW, bmA: TBitmap;
  34.   T: cardinal;
  35.   LW: integer;
  36.  
  37.   procedure Push(var H: THeap; const N: TNode);
  38.   var
  39.     i, ai: integer;
  40.     tmp: TNode;
  41.   begin
  42.     i := Length(H);
  43.     SetLength(H, i+1);
  44.     H[i] := N;
  45.    
  46.     if i>0 then begin
  47.       tmp := H[i];
  48.       repeat
  49.         ai := (i-1) div 2;
  50.         if H[ai].E < tmp.E then break;
  51.         H[i] := H[ai];
  52.         i := ai;
  53.       until i=0;
  54.       H[i] := tmp;
  55.     end;
  56.   end;
  57.  
  58.   procedure Pop(var H: THeap; var N: TNode);
  59.   var
  60.     E,i,ai,j1,j2: integer;
  61.     tmp: TNode;
  62.   begin
  63.  
  64.     E := Length(H);
  65.     N := H[0];
  66.     H[0] := H[E-1];
  67.     SetLength(H, E-1);
  68.  
  69.     i := 0;
  70.     ai :=0;
  71.     dec(E);
  72.  
  73.     if E>0 then begin
  74.       tmp := H[i];
  75.       repeat
  76.         j1 := i*2+1;
  77.         j2 := j1+1;
  78.  
  79.         if j1>=E then break
  80.         else if j2>=E then ai := j1
  81.         else if H[j1].E < H[j2].E then ai := j1
  82.         else ai := j2;
  83.  
  84.         if tmp.E > H[ai].E then H[i] := H[ai]
  85.         else break;
  86.         i := ai;
  87.       until false;
  88.       H[i] := tmp;
  89.     end;
  90.   end;
  91.  
  92.   procedure SetShifts;
  93.   var
  94.     i: integer;
  95.   begin
  96.     for i := Low(ColorShift) to High(ColorShift) do ColorShift[i] := (dx[i] + dy[i]*W) * SizeOf(TColor);
  97.   end;
  98.  
  99.   procedure SetWeights(S: TBitmap; var D: TBitmap);
  100.   var
  101.     i,j,k: integer;
  102.     SC, DC: PColor;
  103.   begin
  104.     if D = nil then D := TBitmap.Create;
  105.     D.PixelFormat := pf32bit;
  106.     D.Width := W;
  107.     D.Height := H;
  108.     SC := S.ScanLine[S.Height-1];
  109.     DC := D.ScanLine[D.Height-1];
  110.     for j := 0 to H-1 do for i := 0 to W-1 do begin
  111.       if SC^ = $FF then begin
  112.         x1 := i;
  113.         y1 := j;
  114.         SC^ := $FFFFFF;
  115.       end else if SC^ = $FF00 then begin
  116.         x2 := i;
  117.         y2 := j;
  118.         SC^ := $FFFFFF;
  119.       end;
  120.  
  121.       k := (SC^ shr 16 and $FF) + (SC^ shr 8 and $FF) + (SC^ and $FF);
  122.       // k : 0 .. 255*3
  123.       if k=0 then DC^ := MaxInt
  124.       else DC^ := (255*3) - k + MinW;
  125.       // max -> 10; min -> 255*3
  126.       Inc(SC);
  127.       Inc(DC);
  128.     end;
  129.   end;
  130.  
  131.   function FastDist(x1,y1,x2,y2: integer): integer;
  132.   var
  133.     dx, dy: integer;
  134.   begin
  135.     if DirC = 4 then result := (abs(x1-x2) + abs(y1-y2)) * MinW
  136.     else begin
  137.       dx := abs(x1-x2);
  138.       dy := abs(y1-y2);
  139.       if dx>dy then result := dx+dy*27146 div 65536 else result := dy+dx*27146 div 65536;
  140.       result := result * MinW;
  141.     end;
  142.   end;
  143.  
  144.   procedure Fill(S: TBitmap; var D: TBitmap; x1,y1,x2,y2: integer);
  145.   var
  146.     i: integer;
  147.     SC, DC: PColor;
  148.     tmpD: PColor;
  149.     N: TNode;
  150.     T: THeap;
  151.     newl,newe: integer;
  152.     ax,ay: integer;
  153.  
  154.     procedure PushP(x,y,L,E: integer;S,D: PColor);
  155.     var
  156.       N: TNode;
  157.     begin
  158.       N.X := x;
  159.       N.Y := y;    
  160.       N.L := L;
  161.       N.E := E;
  162.       N.S := S;
  163.       N.D := D;
  164.       Push(T, N);
  165.       D^ := L;   // dlinna
  166.     end;
  167.  
  168.   begin
  169.     if D = nil then D := TBitmap.Create;
  170.     D.PixelFormat := pf32bit;
  171.     D.Width := W;
  172.     D.Height := H;
  173.     SC := S.ScanLine[S.Height-1];
  174.     DC := D.ScanLine[D.Height-1];
  175.     tmpD := DC;
  176.     for i := 0 to S.Width*S.Height-1 do begin
  177.       tmpD^ := MaxInt;
  178.       Inc(tmpD);
  179.     end;
  180.     Inc(SC, x1+y1*W);
  181.     Inc(DC, x1+y1*W);
  182.  
  183.     PushP(x1,y1,0,FastDist(x1,y1,x2,y2),SC,DC); // evreistika
  184.  
  185.     while Length(T) > 0 do begin
  186.       Pop(T, N);
  187.       for i := 0 to DirC-1 do begin
  188.         ax := N.X + dx[i];
  189.         ay := N.Y + dy[i];
  190.         if ((ax>=0) and (ax<W)) and ((ay>=0) and (ay<H)) then begin
  191.           PChar(SC) := PChar(N.S) + ColorShift[i];
  192.           PChar(DC) := PChar(N.D) + ColorShift[i];
  193.           if SC^ < MaxInt then begin
  194.             newl := N.L + SC^ * DL[i] div 65536;
  195.             newe := newl + FastDist(ax,ay,x2,y2);      // evreistika
  196.             if newl < DC^ then PushP(ax,ay,newl,newe,SC,DC);        
  197.             if (ax=x2) and (ay=y2) then exit;
  198.           end;
  199.         end;
  200.       end;
  201.     end;
  202.   end;
  203.  
  204.   procedure DrawPath(P, S: TBitmap; var D: TBitmap; x1,y1,x2,y2: integer; var LW: integer);
  205.   var
  206.     SC, DC: PColor;
  207.     SN, DN: array [Low(ColorShift) .. High(ColorShift)] of PColor;
  208.     m: integer;
  209.     i, dir: integer;
  210.     ax, ay: integer;
  211.   begin
  212.     if D = nil then D := TBitmap.Create;
  213.     D.PixelFormat := pf32bit;
  214.     D.Width := W;
  215.     D.Height := H;
  216.     SC := P.ScanLine[P.Height-1];
  217.     DC := D.ScanLine[D.Height-1];
  218.     for i := 0 to W*H-1 do begin
  219.       DC^ := SC^;
  220.       Inc(DC);
  221.       Inc(SC);
  222.     end;
  223.  
  224.     SC := S.ScanLine[S.Height-1];
  225.     DC := D.ScanLine[D.Height-1];
  226.     Inc(SC, x2+y2*W);
  227.     Inc(DC, x2+y2*W);
  228.  
  229.     LW := 0;
  230.  
  231.     while(x2<>x1) or (y2<>y1) do begin      
  232.       DC^ := $FF0000;
  233.  
  234.       m := MaxInt;
  235.       dir := High(ColorShift)+1;
  236.  
  237.       for i := 0 to DirC-1 do begin
  238.         ax := x2 + dx[i];
  239.         ay := y2 + dy[i];
  240.         if ((ax>=0) and (ax<W)) and ((ay>=0) and (ay<H)) then begin
  241.           PChar(SN[i]) := PChar(SC) + ColorShift[i];
  242.           PChar(DN[i]) := PChar(DC) + ColorShift[i];
  243.           if SN[i]^ < m then begin
  244.             m := SN[i]^;
  245.             dir := i;
  246.           end;
  247.         end;
  248.       end;
  249.  
  250.       if dir > High(ColorShift) then break;
  251.       if LW = 0 then LW := SC^;
  252.       SC^ := MaxInt;
  253.  
  254.       Inc(x2, dx[dir]);
  255.       Inc(y2, dy[dir]);
  256.       SC := SN[dir];
  257.       DC := DN[dir];
  258.     end;
  259.     DC^ := $FF0000;
  260.   end;
  261.  
  262.   function CutDim(S: string): string;
  263.   var
  264.     i: integer;
  265.   begin
  266.     i := Length(S);
  267.     while (i>0) and (S[i] <> '.') do Dec(i);
  268.     if i=0 then i := Length(S)+1;
  269.     Result := Copy(S, 1, i-1);
  270.   end;
  271.  
  272. begin            
  273.   if ParamCount = 0 then begin
  274.     Write('Enter file name: ');
  275.     ReadLn(S);
  276.   end else S := ParamStr(1);
  277.   WriteLn('Loading...');
  278.   bmP := TBitmap.Create;
  279.   bmP.LoadFromFile(S);
  280.   bmP.PixelFormat := pf32bit;
  281.  
  282.   W := bmP.Width;
  283.   H := bmP.Height;
  284.  
  285.   x1 := 0;
  286.   y1 := 0;
  287.   x2 := W-1;
  288.   y2 := H-1;
  289.  
  290.  
  291.   SetShifts;
  292.   WriteLn('weights...');
  293.   SetWeights(bmP, bmL);
  294.  
  295.   for i := 0 to 1 do begin
  296.     DirC := DirCounts[i];
  297.     T := GetTickCount;                    // timer begin
  298.     WriteLn('finding path, ', DirC, ' directions...');
  299.     Fill(bmL, bmW, x1, y1, x2, y2);
  300.     WriteLn('drawing path...');
  301.     DrawPath(bmP, bmW, bmA, x1, y1, x2, y2, LW);
  302.     T := GetTickCount - T;                // timer end
  303.     WriteLn('saving file...');
  304.     bmW.SaveToFile(CutDim(S) + '_wave_' + IntToStr(DirC) + '.bmp');
  305.     bmA.SaveToFile(CutDim(S) + '_answer_' + IntToStr(DirC) + '.bmp');
  306.     WriteLn('complete. Total (finding+drawing) time = ', T, ' ms, length = ', LW/MinW:0:5);
  307.   end;
  308.   WriteLn('Press ENTER to exit.');
  309.   ReadLn;
  310. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement