Sakktábla

 

Készítsünk programot, mely egy sakktáblát jelenít meg. Ügyeljünk arra, hogy a tábla szabályos legyen (az a1 mezőnek sötétnek kell lenni). Vegyük figyelembe azt is, hogy a táblán később figurákat kell elhelyezni, azaz a sötét ne fekete és a világos mező ne fehér legyen. A fehér és fekete maradjon meg a figurák színének. Ha a formot átméretezzük, áthelyezzük, akkor rajzolja újra a táblát, ne legyen a sakktábla töredezett.

 

         A program futási képe:

 

 

         A program listája:

 

unit USakkTabla;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes,

  Graphics, Controls, Forms, Dialogs, StdCtrls;

type
  TfmSakkTabla = class(TForm)
    btKilepes: TButton;
    procedure FormPaint(Sender: TObject);
    procedure btKilepesClick(Sender: TObject);
    procedure FormCanResize(Sender: TObject; var NewWidth,
      NewHeight: Integer; var Resize: Boolean);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  fmSakkTabla: TfmSakkTabla;

implementation

{$R *.dfm}

procedure TfmSakkTabla.btKilepesClick(Sender: TObject);
begin
  Close;
end;

procedure TfmSakkTabla.FormPaint(Sender: TObject);
Var I, J: Word;
    Xk,Yk: Integer;
Const D=60;
begin
  Xk:= ClientWidth Div 2;
  Yk:= ClientHeight Div 2;
  With Canvas Do
  Begin
    Brush.Color:= clBtnFace;
    Pen.Color:= clBtnFace;
    Rectangle(0,0,2*Xk,2*Yk);
    Brush.Color:= clWhite;
    Pen.Color:= clWhite;
    Rectangle(Xk-9*(D Div 2),Yk-9*(D Div 2),
              Xk+9*(D Div 2),Yk+9*(D Div 2));
    Pen.Color:= RGB(144,144,0);
    Rectangle(Xk-4*D,Yk-4*D, Xk+4*D,Yk+4*D);
    For I:= 1 To 8 Do For J:= 1 To 8 Do
    Begin
      If Odd(I+J) Then
      Begin
        Brush.Color:= RGB(144,144,0);
        Pen.Color:= RGB(144,144,0);
      End
      Else
      Begin
        Brush.Color:= RGB(224,224,224);
        Pen.Color:= RGB(224,224,224);
      End;
      Rectangle(Xk-(5-I)*D,Yk-(5-J)*D,
                Xk-(4-I)*D,Yk-(4-J)*D);
    End;
    Brush.Color:= clWhite;
    Pen.Color:= clBlack;
    For I:= 1 To 8 Do
    Begin
      Font.Size:= 12;
      TextOut(Xk+I*D-73*D Div 16,Yk+65*D Div 16, Chr(96+I));
      TextOut(Xk+33*D Div 8,Yk-I*D+71*D Div 16, IntToStr(I));
    End;
  End;
end;

procedure TfmSakkTabla.FormCanResize(Sender: TObject; var NewWidth,
  NewHeight: Integer; var Resize: Boolean);
begin
  FormPaint(Sender);
end;

end.

 

 

Vezérek elhelyezése a sakktáblán véletlen mutációval

 

Írjunk programot, mely véletlen mutáció segítségével ütésmentesen elhelyez 8 vezért a sakktáblán. Nem kell az összes megoldást megkeresnie, ha talál jó megoldást, a program álljon le. Az algoritmus megírásakor a következőket tartsuk be:

 

- az állapot leírására az 1-8 számok egy permutációját használjuk;

- a vezérek elhelyezkedését a következőképpen értelmezzük: a permutáció első helyén álló szám azt mutatja, hogy az ’a’ oszlopban melyik sorban van a vezér, a második helyen álló a ’b’, harmadik helyen a ’c’, … végül nyolcadik helyen lévő szám a ’h’ oszlopban lévő vezér sorának számát jelentse;

- a kezdőállapot az ’12345678’ permutáció legyen. Ez azt jelenti, hogy a vezérek az ’a1’-’h8’ átlón helyezkednek el. Minden sorban és oszlopban pontosan egy vezér. Így csak azért nem jó az elrendezés, mert a vezér átlós irányban is üt (nem úgy, mint a bástya), tehát ekkor minden vezér a többivel ütésben van;

- az elrendezéshez rendeljünk hibaszámot, mely legyen az összes bábu összesített ütési száma;

- ha az ütési számok összege (hibaszám) nulla, akkor a vezérek nem ütik egymást, a feladatot a program megoldotta;

- a kezdeti állapotból kiindulva cseréjük fel véletlen választással a permutáció két elemét (ez a csere nem hoz létre soron vagy oszlopon belüli ütközést, tehát továbbra is csak átlós ütközéseket kell számolni);

- nézzük meg, hogy a cserével létrejött permutációhoz tartozó felállás kisebb hibaszámú-e mint a csere előtti;

- ha igen, akkor a cserét tartsuk meg, ha nem, akkor figyelmen kívül hagyjuk;

- folytassuk addig a véletlen cserélgetés, ameddig jó megoldást nem kapunk.

 

A program jelenítse meg a feladat megoldását jelentő felállást, illetve minden a megoldást jelentő előtti állapotot is. Lehessen újra indítani a keresést.

 

A program futási képei. Az alapállapot:

 

 

Egy megtalált helyes felállás:

 

 

 

 

A program listája:

 

unit URndVezer;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes,

  Graphics, Controls, Forms, Dialogs, StdCtrls, Grids;

Const Max=8;

type
  TfmRndVezer = class(TForm)
    lbRndVezer: TLabel;
    btKilepes: TButton;
    sgRndVezer: TStringGrid;
    sgTabla: TStringGrid;
    btStart: TButton;
    btAlap: TButton;
    edN: TEdit;
    Procedure Kepernyore;
    Procedure Tablara;
    Function HibaT: Byte;
    Function HibaP: Byte;
    Procedure Mutacio;
    procedure btKilepesClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure sgTablaDrawCell(Sender: TObject; Col, Row: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure btStartClick(Sender: TObject);
    procedure btAlapClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  fmRndVezer: TfmRndVezer;
  ACol, ARow: Integer;
  N: Word;
  T, P: Array[1..Max] Of Byte;

implementation

{$R *.dfm}

procedure TfmRndVezer.btKilepesClick(Sender: TObject);
begin
  Close;
end;

procedure TfmRndVezer.FormCreate(Sender: TObject);
Var I: Word;
    Ch: Char;
begin
  With sgRndVezer Do
  Begin
    For I:= 1 To Max Do Cells[I,0]:= Chr(96+I);
  End;

  With sgTabla Do
  Begin
    ColWidths[9]:= 0;
    RowHeights[9]:= 0;
    For I:= 1 To 8 Do Cells[0,I]:= IntToStr(9-I);
    For Ch:= 'a' To 'h' Do Cells[Ord(Ch)-96,0]:= Ch;
    Col:= 9; Row:= 9;
  End;

  Randomize;
  N:= 1; For I:= 1 To Max Do T[I]:= I;
  Kepernyore;
  Tablara;
end;

procedure TfmRndVezer.sgTablaDrawCell(Sender: TObject; Col, Row: Integer;
  Rect: TRect; State: TGridDrawState);
begin
  //a sakktáblát és felállást megjelenítő StringGrid beállításai
  With sgTabla.Canvas.Brush Do
  Begin
    {rögzített cellák}
    If gdFixed In State Then Color:=clWhite;

    {kiválasztott cella}
    If gdSelected In State Then Color:= clSilver;

    {a táblázat belseje}
    If Not((gdSelected In State) Or (gdFixed In State)) Then
    Begin
      Case Odd(Col) XOr Odd(Row) Of
        False: Color:= clWindow;
        True: Color:= clSilver;
      End;
    End;
    sgTabla.Canvas.Font.Size:= 17;
  End;
  sgTabla.Canvas.TextRect(Rect,Rect.Left+16,
                          Rect.Top+4,sgTabla.Cells[Col,Row]);
  If gdFocused In State Then sgTabla.Canvas.DrawFocusRect(Rect);
end;

procedure TfmRndVezer.btAlapClick(Sender: TObject);
Var I,J: Word;
begin
  N:= 1; For I:= 1 To Max Do T[I]:= I;
  With sgRndVezer Do
  Begin
    For I:= 1 To ColCount-1 Do For J:= 1 To RowCount-1 Do Cells[I,J]:= '';
    RowCount:= 5;
  End;
  Kepernyore;
  Tablara;
end;

Procedure TfmRndVezer.Kepernyore;
Var I: Word;
Begin
  With sgRndVezer Do
  Begin
    If RowCount-1<N Then RowCount:= N+1;
    Cells[0,N]:= IntToStr(N)+'.';
    For I:= 1 To Max Do Cells[I,N]:= IntToStr(T[I]);
  End;
  EdN.Text:= IntToStr(N); edN.Repaint;
End;

Procedure TfmRndVezer.Tablara;
Var I, J: Word;
Begin
  With sgTabla Do
  Begin
    For I:= 1 To ColCount-1 Do For J:= 1 To RowCount-1 Do Cells[I,J]:= '';
    For I:= 1 To Max Do
    Begin
      Cells[I,Max-T[I]+1]:= 'V';
    End;
  End;
  sgTabla.Repaint;
End;

Function TfmRndVezer.HibaT: Byte;
Var I, J, H: Byte;
Begin
  HibaT:= 0; H:= 0;
  For I:= 1 To Max-1 Do For J:= I+1 To Max Do
  If Abs(T[I]-T[J])=J-I Then Inc(H);
  HibaT:= H;
End;

Function TfmRndVezer.HibaP: Byte;
Var I, J, H: Byte;
Begin
  HibaP:= 0; H:= 0;
  For I:= 1 To Max-1 Do For J:= I+1 To Max Do
  If Abs(P[I]-P[J])=J-I Then Inc(H);
  HibaP:= H;
End;

Procedure TfmRndVezer.Mutacio;
Var I, J, Puf: Byte;
Begin
  Inc(N);
  P:= T;
  I:= Random(Max)+1;
  J:= Random(Max)+1;
  Puf:= P[I]; P[I]:= P[J]; P[J]:= Puf;
  Case N Mod 10 Of
    0..8: If HibaP<HibaT Then T:= P;
       9: If HibaP>0 Then T:= P;
  End;
End;

procedure TfmRndVezer.btStartClick(Sender: TObject);
begin
  While HibaT>0 Do
  Begin
    Mutacio;
    Kepernyore;
    Tablara;
  End;
end;

end.

 

Vezérek elhelyezése a sakktáblán Backtrack algoritmussal

 

Írjunk programot, mely a Backtrack algoritmus segítségével ütésmentesen elhelyez 8 vezért a sakktáblán. Nem kell az összes megoldást megkeresnie, ellenben minden ’a’ oszlopban elhelyezett vezérhez keressen egy-egy megoldást (azaz nyolcat).

 

A program indulási képe:

 

A megtalált nyolc lehetséges elrendezés (a sakktáblán az utolsóként megtalált felállás látható):

 

 

A program listája:

 

unit UBTrVezer;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes,

  Graphics, Controls, Forms, Dialogs, StdCtrls, Grids;

Const Max=8;

type
  TfmBTrVezer = class(TForm)
    lbBTrVezer: TLabel;
    btKilepes: TButton;
    sgBTrVezer: TStringGrid;
    sgTabla: TStringGrid;
    btStart: TButton;
    btAlap: TButton;
    lbKesz: TLabel;
    Function Rossz(B,C: Byte): Boolean;
    Function Jo(A: Byte): Boolean;
    Procedure Keres;
    procedure btKilepesClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure sgTablaDrawCell(Sender: TObject; Col, Row: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure btStartClick(Sender: TObject);
    procedure btAlapClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  fmBTrVezer: TfmBTrVezer;
  ACol, ARow: Integer;
  N: Word;
  T: Array[1..Max] Of Byte;
  I: Word;

implementation

{$R *.dfm}

procedure TfmBTrVezer.btKilepesClick(Sender: TObject);
begin
  Close;
end;

procedure TfmBTrVezer.sgTablaDrawCell(Sender: TObject; Col, Row: Integer;
  Rect: TRect; State: TGridDrawState);
begin
  With sgTabla.Canvas.Brush Do
  Begin
    {rögzített cellák}
    If gdFixed In State Then Color:=clWhite;

    {kiválasztott cella}
    If gdSelected In State Then Color:= clSilver;

    {a táblázat belseje}
    If Not((gdSelected In State) Or (gdFixed In State)) Then
    Case Odd(Col) XOr Odd(Row) Of
      False: Color:= clWindow;
      True: Color:= clSilver;
    End;
    sgTabla.Canvas.Font.Size:= 17;
  End;
  {szöveg beállítása rácson belül: +6 +4}
  {kövér betüket akkor tud, ha DefaultDrawing=True}
  sgTabla.Canvas.TextRect(Rect,Rect.Left+16,Rect.Top+4,sgTabla.Cells[Col,Row]);
  If gdFocused In State Then sgTabla.Canvas.DrawFocusRect(Rect);
end;

procedure TfmBTrVezer.FormCreate(Sender: TObject);
Var I: Word;
    Ch: Char;
begin
  With sgBTrVezer Do
  For I:= 1 To Max Do
  Begin
    Cells[I,0]:= IntToStr(I)+'.';
    Cells[0,I]:= IntToStr(I)+'.';
  End;

  With sgTabla Do
  Begin
    ColWidths[9]:= 0;
    RowHeights[9]:= 0;
    For I:= 1 To 8 Do Cells[0,I]:= IntToStr(9-I);
    For Ch:= 'a' To 'h' Do Cells[Ord(Ch)-96,0]:= Ch;
    Col:= 9; Row:= 9;
  End;
  N:= 0;
  lbKesz.Caption:= '';
end;

procedure TfmBTrVezer.btAlapClick(Sender: TObject);
Var I, J: Word;
begin
  For I:= 1 To Max Do T[I]:= 0;
  For I:= 1 To Max Do For J:= 1 To Max Do
  Begin
    sgBTrVezer.Cells[I,J]:= '';
    sgTabla.Cells[I,J]:= '';
  End;
  N:= 0;
  lbKesz.Caption:= '';
end;

Function TfmBTrVezer.Rossz(B,C: Byte): Boolean;
Var J: Word;
Begin
  J:= 1; While (J<B) And (C<>T[J]) And (Abs(C-T[J])<>Abs(B-J)) Do Inc(J);
  Rossz:= Not(J<B);
End;

Function TfmBTrVezer.Jo(A: Byte): Boolean;
Label 1;
Begin
  Repeat
    Inc(T[I]);
    If T[I]>8 Then GoTo 1;
  Until (T[I]<=8) And Rossz(A,T[I]);
  1: Jo:= T[I]<=8;
End;

Procedure TfmBTrVezer.Keres;
Begin
  I:= 1;
  With sgTabla Do While I In [1..8] Do If Jo(I) Then
  Begin
    Cells[I,Max-T[I]+1]:= 'V'; Inc(I); T[I]:= 0;
    RePaint;
    Sleep(50);
  End
  Else
  Begin
    Dec(I); Cells[I,Max-T[I]+1]:= '';
    RePaint;
    Sleep(50);
  End;
End;

procedure TfmBTrVezer.btStartClick(Sender: TObject);
Var K, J, U, V: Word;
begin
  For K:= 0 To 7 Do
  Begin
    For J:= 1 To 8 Do T[J]:= K;
    For U:= 1 To Max Do For V:= 1 To Max Do sgTabla.Cells[U,V]:= '';
    Keres;
    Inc(N); For U:= 1 To Max Do sgBTrVezer.Cells[U,N]:= IntToStr(T[U]);
    sgBTrVezer.Repaint;
    Sleep(500);
  End;
  lbKesz.Caption:= 'Kész';
end;

end.

 

 

Nyolc vezér a sakktáblán (minden lehetséges eset)

 

Feladat: írjunk programot, mely nyolc vezérnek egy sakktáblán való ütésmentes elhelyezését oldja meg. A programnak az összes lehetséges felállítást meg kell keresnie. (Ha valaki nem tudná: a vezér minden irányba, akárhányat léphet, az irány lehet oldallal párhuzamos és átlós is.)

 

A megoldásnál egy olyan alapfelállásból indulunk, amikor soronként és oszloponként nincs ütközés. Ha nyolc különböző számot (1..8) permutálunk, és azt mondjuk, hogy az egyes oszlopokon a vezér abban a sorban legyen, amit a permutáció megfelelő helyén álló szám mutat, akkor egy ilyen felállításban biztosan nincs két vagy több vezér egy sorban vagy oszlopban. Mivel az ilyen alapesetek száma 8! = 40320, először egy elegáns rekurzióval ezeket állítjuk elő, tároljuk egy táblázatban, majd ezek közül kiválogatjuk azokat, amelyek ütközésmentesek. 92 ilyen, átlós ütközésmentes permutációt találunk. Ezeket a képernyőn megjelenő sakktáblán el is lehet helyezni, ellenőrizhetjük, hogy valóban ütközésmentes a felállás. Ezen 92 között találhatók olyanok, melyek egymásnak elemi geometriai transzformációi (eltolás, tükrözés). Utolsó lépésben ezeket is kiszórjuk, vagyis meghatározzuk azt a 12-t, amelyből az összes többi geometriai transzformációval származtatható. A szűrést a következőkre hajtottam végre: 8 vízszintes eltolás, 8 függőleges eltolás, 4 szimmetriatengelyre való tükrözés, középpontos tükrözés, 90 fokos elforgatás jobbra és végül 90 fokos elforgatás balra. Az alapesetek táblán való kattintás is megmutatja a vezérek elhelyezkedését a sakktáblán.

 

A program futási képe:

 

 

         A program listája:

 

unit UVezer;

interface

uses
  Windows, Messages, SysUtils, Classes,

  Graphics, Controls, Forms, Dialogs, Grids, StdCtrls;

type
  St8= String[8];
  TfmVezer = class(TForm)
    sgMind: TStringGrid;
    lbOsszes: TLabel;
    sgJo: TStringGrid;
    lbJo: TLabel;
    sgTabla: TStringGrid;
    lbTabla: TLabel;
    sgAlap: TStringGrid;
    lbAlap: TLabel;
    Function Ugyanaz(A,B: St8): Boolean;
    procedure FormCreate(Sender: TObject);
    procedure sgTablaDrawCell(Sender: TObject; Col, Row: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure sgJoClick(Sender: TObject);
    procedure sgAlapClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

Const M=1*2*3*4*5*6*7*8;

var
  fmVezer: TfmVezer;
  S: St8;
  PT: Array[1..M] Of St8;
  Ind: Word;


implementation

{$R *.DFM}

Procedure Permut(I: Word);
Var J: Word;
    Ch: Char;
Begin
  If I=1 Then Begin Inc(Ind); PT[Ind]:= S End Else
  Begin
    Permut(I-1);
    For J:= 1 To I-1 Do
    Begin
      Ch:= S[J]; S[J]:= S[I]; S[I]:= Ch; Permut(I-1);
      Ch:= S[J]; S[J]:= S[I]; S[I]:= Ch;
    End;
  End;
End;

Function TfmVezer.Ugyanaz(A,B: St8): Boolean;
Var I: Word;
    Ws: St8;

  Function EltolasVB(C: St8): St8; //vizszintesen balra
  Begin
    C:= Copy(C+C[1],2,8);
    EltolasVB:= C;
  End;

  Function EltolasFF(C: St8): St8; //függőlegesen felfelé
  Var J, X: Word;
  Begin
    For J:= 1 To 8 Do
    Begin
      X:= Ord(C[J]); Inc(X); If X=57 Then X:= 49; C[J]:= Chr(X);
      EltolasFF:= C;
    End;
  End;

  Function TukrozesVT(C: St8): St8;  //vízsintes tengelyre
  Var J: Word;
  Begin
    For J:= 1 To 8 Do C[J]:= Chr(105-Ord(C[J]));
    TukrozesVT:= C;
  End;

  Function TukrozesFT(C: St8): St8;  //függőleges tengelyre
  Var J: Word;
      X: St8;
  Begin
    X:= '12345678';
    For J:= 1 To 8 Do X[J]:= C[9-J];
    TukrozesFT:= X;
  End;

  Function TukrozesLA(C: St8): St8;  //lefutó átlóra
  Var I: Word;
      X: St8;
      S: String;
  Begin
    X:= '12345678';
    For I:= 1 To 8 Do
    Begin Str(9-I,S); X[9-StrToInt(C[I])]:= S[1] End;
    TukrozesLA:= X;
  End;

  Function TukrozesFA(C: St8): St8;  //felfutó átlóra
  Var I: Word;
      X: St8;
      S: String;
  Begin
    X:= '12345678';
    For I:= 1 To 8 Do
    Begin Str(I,S); X[StrToInt(C[I])]:= S[1] End;
    TukrozesFA:= X;
  End;

  Function ForgatasJ(C: St8): St8; //forgatás jobbra
  Var I: Word;
      X: St8;
      S: String;
  Begin
    X:= '12345678';
    For I:= 1 To 8 Do
    Begin Str(9-I,S); X[StrToInt(C[I])]:= S[1] End;
    ForgatasJ:= X;
  End;

  Function ForgatasB(C: St8): St8; //forgatás balra
  Var I: Word;
      X: St8;
      S: String;
  Begin
    X:= '12345678';
    For I:= 1 To 8 Do
    Begin Str(I,S); X[9-StrToInt(C[I])]:= S[1] End;
    ForgatasB:= X;
  End;

  Function KozeppontosT(C: St8): St8; //középpontos tükrözés
  Begin
    KozeppontosT:= TukrozesVT(TukrozesFT(C));
  End;

Begin
  Ugyanaz:= False;
  //eltolás víszsintesen balra
  Ws:= B; For I:= 1 To 7 Do
  Begin Ws:= EltolasVB(Ws); If A=Ws Then Ugyanaz:= True End;
  //eltolás függőlegesen felfelé
  Ws:= B; For I:= 1 To 7 Do
  Begin Ws:= EltolasFF(Ws); If A=Ws Then Ugyanaz:= True End;
  //vízszintes tengelyre való tükrözés
  If A=TukrozesVT(B) Then Ugyanaz:= True;
  //függőleges tengelyre való tükrözés
  If A=TukrozesFT(B) Then Ugyanaz:= True;
  //lefutó átlóra való tükrözés
  If A=TukrozesLA(B) Then Ugyanaz:= True;
  //felfutó átlóra való tükrözés
  If A=TukrozesFA(B) Then Ugyanaz:= True;
  //forgatas jobbra
  If A=ForgatasJ(B) Then Ugyanaz:= True;
  //forgatás balra
  If A=ForgatasB(B) Then Ugyanaz:= True;
  //középpontos tükrözes
  If A=KozeppontosT(B) Then Ugyanaz:= True;
End;

procedure TfmVezer.FormCreate(Sender: TObject);
Var I, J, K, N: Word;
    Jo: Boolean;
    Ch: Char;
    SI,SJ: St8;
begin
  With sgAlap Do
  Begin
    For I:= 1 To 8 Do Cells[I,0]:= IntToStr(I)+'.';
  End;
  With sgJo Do
  Begin
    ColWidths[0]:= 42;
    For I:= 1 To 8 Do Cells[I,0]:= IntToStr(I)+'.';
  End;
  With sgTabla Do
  Begin
    For I:= 1 To 8 Do Cells[0,I]:= IntToStr(9-I);
    For Ch:= 'a' To 'h' Do Cells[Ord(Ch)-96,0]:= Ch;
    Col:= 1; Row:= 8;
  End;
  With sgMind Do
  Begin
    ColWidths[0]:= 42;
    RowCount:= M+1;
    For I:= 1 To M Do Cells[0,I]:= IntToStr(I)+'.';
    For I:= 1 To 8 Do Cells[I,0]:= IntToStr(I)+'.';
    Ind:= 0; S:= '12345678'; Permut(8);
    For J:= 1 To M Do For I:= 1 To 8 Do Cells[I,J]:= PT[J,I];
    N:= 1;
    For J:= 1 To M Do
    Begin
      Jo:= True; For I:= 1 To 7 Do For K:= I+1 To 8 Do
      If Abs(StrToInt(Cells[I,J])-StrToInt(Cells[K,J]))= K-I Then
      Jo:= False;
      If Jo Then
      Begin
        For I:= 1 To 8 Do sgJo.Cells[I,N]:= Cells[I,J];
        sgJo.Cells[0,N]:= IntToStr(N)+'.'; Inc(N);
        If sgJo.RowCount<N Then sgJo.RowCount:= sgJo.RowCount+1;
      End;
    End;
  End;
  With sgJo Do
  Begin
    N:= RowCount-1;
    For I:= 1 To N-1 Do If Cells[0,I]<>'' Then
    For J:= I+1 To N Do If Cells[0,J]<>'' Then
    Begin
      SI:= ''; SJ:= '';
      For K:= 1 To 8 Do SI:= SI+Cells[K,I];
      For K:= 1 To 8 Do SJ:= SJ+Cells[K,J];
      If Ugyanaz(SI,SJ) Then Cells[0,J]:= '';
    End;
    K:= 0;
    For I:= 1 To RowCount-1 Do If Cells[0,I]<>'' Then
    Begin
      Inc(K);
      sgAlap.Cells[0,K]:= IntToStr(K)+'.';
      For J:= 1 To 8 Do sgAlap.Cells[J,K]:= Cells[J,I];
    End;
  End;
end;

procedure TfmVezer.sgTablaDrawCell(Sender: TObject; Col, Row: Integer;
  Rect: TRect; State: TGridDrawState);
begin
  With sgTabla.Canvas.Brush Do
  Begin
    {rögzített cellák}
    If gdFixed In State Then Color:=clWhite;

    {kiválasztott cella}
    If gdSelected In State Then Color:= clSilver;

    {a táblázat belseje}
    If Not((gdSelected In State) Or (gdFixed In State)) Then
    Case Odd(Col) XOr Odd(Row) Of
      False: Color:= clWindow;
      True: Color:= clSilver;
    End;
    sgTabla.Canvas.Font.Size:= 17;
  End;
  {szöveg beállítása rácson belül: +6 +4}
  {kövér betüket akkor tud, ha DefaultDrawing=True}
  sgTabla.Canvas.TextRect(Rect,Rect.Left+16,Rect.Top+4,sgTabla.Cells[Col,Row]);
  If gdFocused In State Then sgTabla.Canvas.DrawFocusRect(Rect);
end;

procedure TfmVezer.sgJoClick(Sender: TObject);
Var I, J: Word;
begin
  With sgJo Do
  Begin
    For I:= 1 To 8 Do For J:= 1 To 8 Do sgTabla.Cells[I,J]:= '';
    For I:= 1 To 8 Do sgTabla.Cells[I,9-StrToInt(Cells[I,Row])]:= 'V';
  End;
end;

procedure TfmVezer.sgAlapClick(Sender: TObject);
Var I, J: Word;
begin
  With sgAlap Do
  Begin
    For I:= 1 To 8 Do For J:= 1 To 8 Do sgTabla.Cells[I,J]:= '';
    For I:= 1 To 8 Do sgTabla.Cells[I,9-StrToInt(Cells[I,Row])]:= 'V';
  End;
end;

end.

 

Vezérek elhelyezése a sakktáblán Back Track algoritmussal (teljes)

 

Írjunk programot, mely a Backtrack algoritmus segítségével megkeresi az összes lehetséges ütésmentes vezérelhelyezést a sakktáblán. A sakktábla méretét beviteli mező segítségével lehessen megadni (1-20 értékhatárok között). A keresés eredményét egy StrigGridben helyezzük el, melyre kattintva a sakktáblán az elhelyezés szerint a vezérek (V betűk) megjelennek. A keresés végén a program írja ki az elhelyezési lehetőségek számát.

 

A program néhány futási képe. Méret = 5:

 

 

Méret = 8:

 

Méret = 12:

 

 

A program listája:

 

unit UBTrVezer;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, 

  Graphics, Controls, Forms, Dialogs, StdCtrls, Grids;

Const Max=20;

type
  TfmBTrVezer = class(TForm)
    lbBTrVezer: TLabel;
    btKilepes: TButton;
    sgBTrVezer: TStringGrid;
    sgTabla: TStringGrid;
    btStart: TButton;
    btAlap: TButton;
    lbKesz: TLabel;
    lbMeret: TLabel;
    edMeret: TEdit;
    lbN: TLabel;
    Function Rossz(B,C: Word): Boolean;
    Function Jo(A: Word): Boolean;
    Procedure Keres;
    Procedure Tablara;
    procedure btKilepesClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure sgTablaDrawCell(Sender: TObject; Col, Row: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure btAlapClick(Sender: TObject);
    procedure btStartClick(Sender: TObject);
    procedure sgBTrVezerClick(Sender: TObject);
    procedure edMeretChange(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  fmBTrVezer: TfmBTrVezer;
  ACol, ARow: Integer;
  T: Array[1..Max] Of Word;
  Meret: Word;
  N: Word;

implementation

{$R *.dfm}

procedure TfmBTrVezer.btKilepesClick(Sender: TObject);
begin
  Close;
end;

procedure TfmBTrVezer.sgTablaDrawCell(Sender: TObject; Col, Row: Integer;
  Rect: TRect; State: TGridDrawState);
begin
  With sgTabla.Canvas.Brush Do
  Begin
    If gdFixed In State Then Color:=clWhite;

    If gdSelected In State Then Color:= clSilver;

    If Not((gdSelected In State) Or (gdFixed In State)) Then
    Case Odd(Col) XOr Odd(Row) Of
      False: Color:= clWindow;
      True: Color:= clSilver;
    End;
    sgTabla.Canvas.Font.Size:= 17;
  End;
  sgTabla.Canvas.TextRect(Rect,Rect.Left+10,Rect.Top+4,sgTabla.Cells[Col,Row]);
  If gdFocused In State Then sgTabla.Canvas.DrawFocusRect(Rect);
end;

procedure TfmBTrVezer.FormCreate(Sender: TObject);
begin
  Meret:= 8;
  btAlapClick(Sender);
end;

procedure TfmBTrVezer.btAlapClick(Sender: TObject);
Var I, J: Word;
begin
  With sgBTrVezer Do
  Begin
    ColCount:= Meret+1;
    ColWidths[0]:= 52;
    For I:= 1 To Meret Do Cells[I,0]:= Chr(96+I);
    For I:= 1 To 92 Do Cells[0,I]:= IntToStr(I)+'.';
  End;

  With sgTabla Do
  Begin
    ColCount:= Meret+2;
    RowCount:= Meret+2;
    For I:= 1 To ColCount-2 Do ColWidths[I]:= 40;
    For I:= 1 To RowCount-1 Do RowHeights[I]:= 32;
    ColWidths[ColCount-1]:= 0;
    RowHeights[RowCount-1]:= 0;
    For I:= 1 To Meret Do Cells[0,I]:= IntToStr(Meret+1-I);
    For I:= 1 To Meret Do Cells[I,0]:= Chr(96+I);
    Col:= ColCount-1; Row:= RowCount-1;
  End;
  With sgBTrVezer Do
  For I:= 1 To ColCount-1 Do For J:= 1 To RowCount-1 Do Cells[I,J]:= '';
  With sgTabla Do
  For I:= 1 To ColCount-1 Do For J:= 1 To RowCount-1 Do Cells[I,J]:= '';
  lbKesz.Caption:= '';
  N:= 0; lbN.Caption:= IntToStr(N);
end;

Function TfmBTrVezer.Rossz(B,C: Word): Boolean;
Begin
  Rossz:= (T[B]=T[C]) Or (Abs(T[B]-T[C])=Abs(B-C));
End;

Function TfmBTrVezer.Jo(A: Word): Boolean;
Var J: Word;
Begin
  J:= 1; While Not Rossz(A,J) And (J<A) Do Inc(J); Jo:= A=J;
End;

Procedure TfmBTrVezer.Keres;
Var I, J: Word;
    Vege: Boolean;
Begin
  Vege:= False; For I:= 1 To Meret Do T[I]:= 0; I:= 1;
  Repeat
    While I In [1..Meret] Do
    Begin
      Inc(T[I]);
      If T[I]>Meret Then Begin T[I]:= 0; Dec(I); End Else If Jo(I) Then Inc(I);
    End;
    If I>Meret Then
    Begin
      Tablara; Inc(N);
      With sgBTrVezer Do
      Begin
        If RowCount<N+1 Then
        Begin
          Cells[0,RowCount-1]:= IntToStr(RowCount-1)+'.';
          RowCount:= N+1;
        End;
        For J:= 1 To Meret Do Begin Cells[J,N]:= IntToStr(T[J]) End;
      End;
    End;
    If I>1 Then Begin Dec(I); Inc(T[I]) End Else Vege:= True;
  Until Vege;
  With sgBTrVezer Do If RowCount>94 Then
  Begin
    RowCount:= RowCount+1;
    Cells[0,RowCount-2]:= IntToStr(RowCount-2)+'.';
  End;
End;

Procedure TfmBTrVezer.Tablara;
Var I, J: Word;
Begin
  With sgTabla Do
  Begin
    For I:= 1 To Meret Do For J:= 1 To Meret Do Cells[I,J]:= '';
    For I:= 1 To Meret Do If T[I]<>0 Then Cells[I,Meret+1-T[I]]:= 'V';
  End;
End;

procedure TfmBTrVezer.btStartClick(Sender: TObject);
begin
  sgBTrVezer.RowCount:= 94; N:= 0;
  Keres; lbKesz.Caption:= 'Kész:'; lbN.Caption:= IntToStr(N);
end;

procedure TfmBTrVezer.sgBTrVezerClick(Sender: TObject);
Var I, J: Word;
begin
  With sgTabla Do
  For I:= 1 To ColCount-1 Do For J:= 1 To RowCount-1 Do Cells[I,J]:= '';
  With sgBTrVezer Do If Cells[Col,Row]<>'' Then
  For I:= 1 To ColCount-1 Do
  sgTabla.Cells[I,Meret+1-StrToInt(Cells[I,Row])]:= 'V';
end;

procedure TfmBTrVezer.edMeretChange(Sender: TObject);
Var Kod: Integer;
begin
  Val(edMeret.Text,Meret,Kod);
  btAlapClick(Sender);
end;

end.

 

 

Vezérek elhelyezése sakktáblán Genetikus algoritmussal

 

A genetikus algoritmusoknak ott nagy a létjogosultsága, ahol a feladatok megoldását nagyon magas elemszámú állapottérből kell megkeresni. Ekkor a fentebb (előző vezér-elhelyezési programokban) is használt keresési eljárások a gépek korlátozott sebessége miatt nem használható.

 

Mint láttuk, vannak olyan reprezentációi a kitűzött feladatnak, melyek egész hamar megoldásra vezetnek. Ezek a reprezentációk már önmagukban hordozzák a feladat specifikus tulajdonságait, így az állapottér elemszáma értelmes méretekre csökkenthető volt.

 

Ebben a szakaszban mintegy elfelejtve az imént említett reprezentációkat, úgy tekintünk a feladatra, mintha az elemi tulajdonságait nem ismernénk, azt csak az algoritmus közben, az egyedek jóságának vizsgálatakor érvényesítjük. Így az egyedek a populációk során válnak külön-külön a jó tulajdonságok hordozóivá.

 

         A Genetikus algoritmus lényege az, hogy kezdetben véletlenül megválasztott elemekből létrehozunk egy populációt (genetikus kódot, elrendezést, az elemszámot a feladat maga, illetve a rendelkezésre álló erőforrás erősen befolyásolja). Majd a következő populációt (generációt) az előzőből például keresztezéssel és/vagy mutációval létrehozzuk. A keresztezés azt jelenti, hogy két egyed genetikus kódját részben kicseréljük, így új egyedeket hozunk létre. A mutációnál az egyes egyed genetikus kódját véletlen módon megváltoztatjuk.

 

A keresztezésnél az a cél, hogy azon egyedek kódja öröklődjenek, amelyek jók. Tehát két jónak minősített egyedet keresztezünk, és két rossznak (gyengének) mutatkozó egyed helyett ezek fognak szerepelni a következő populációban. Így elvileg a populáció egyre jobb tulajdonságú elemekből fog állni. Azt várjuk, hogy keresztezés révén a populációban elő fog fordulni legalább egy, a lehető legjobb tulajdonságokkal rendelkező egyed, ami a feladat megoldását jelenti. Ez persze általában nem így van. Ha az egyedek összességében nem hordozzák a legjobb megoldás kódját, akkor nem kapjuk meg a feladat megoldását. Ekkor az egyedek jósága egy bizonyos szint fölé nem fog emelkedni és szükség lesz a mutációra.

 

         Mutációt akkor kell alkalmazni, amikor a populáció jósága egy szinten (de nem a tökéletes megoldást jelentőn) megakad, azaz keresztezéssel már nem képes tovább fejlődni. Ekkor az egyedek genetikus kódját egy adott százalékos valószínűséggel, véletlen értékre változtatjuk, azaz a kódot frissítjük. Ettől azt várjuk, hogy a holtponti helyzetből a populáció kimozdul, lesznek újra rossz és jó tulajdonságú egyedek, és reményeink szerint a véletlen választás folytán előáll a legjobb tulajdonságú egyed előállítására alkalmas genetikai kód is. Általában igaz, hogy a mutációt nem túl magas százalékban kell alkalmazni, különben a már felhalmozódott jó tulajdonságok eltűnnek az egyedekből.

 

Az itt leírtak szerint készült a címben megfogalmazott feladatra a program. A programnak nem az a célja, hogy az előző feladatokban látható megoldások felett győzedelmeskedjen. Az összes lehetséges elhelyezést megadó programon egyébként már nincs mit javítani, az pillanatok alatt mindent elmond a problémáról. A cél tehát a genetikus algoritmus bemutatása egy viszonylag egyszerű, más eszközökkel is megoldott problémára. A program listája szerintem megfelelően kommentezett, így magyarázatra nem szorul.

 

A program futási képei. Induláskor:

 

 

A keresés végén:

 

 

 

A program listája.

 

unit UGenVezer;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes,

  Graphics, Controls, Forms, Dialogs, StdCtrls, Grids;

Const EgyedSz=40;
      Max=8;
type
  TfmGenVezer = class(TForm)
    lbHenVezer: TLabel;
    btKilepes: TButton;
    sgGenVezer: TStringGrid;
    btUjPop: TButton;
    sgTabla: TStringGrid;
    lbJosag: TLabel;
    edJosag: TEdit;
    lbEgyedSz: TLabel;
    edEgyedSz: TEdit;
    lbJokSz: TLabel;
    edJokSz: TEdit;
    btStart: TButton;
    lbPopSz: TLabel;
    edPSz: TEdit;
    lbKesz: TLabel;
    edKesz: TEdit;
    lbIndex: TLabel;
    edIndex: TEdit;
    lbMutacio: TLabel;
    edMutacio: TEdit;
    lbSzazalek: TLabel;
    lbKereszt: TLabel;
    edKereszt: TEdit;
    Procedure PopInit;
    Procedure Vizsgal;
    Procedure PopKepre;
    Procedure Tablara(Ind: Word);
    Procedure Keresztez;
    Procedure Mutacio;
    procedure FormCreate(Sender: TObject);
    procedure btKilepesClick(Sender: TObject);
    procedure sgGenVezerDrawCell(Sender: TObject; Col, Row: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure sgGenVezerClick(Sender: TObject);
    procedure btUjPopClick(Sender: TObject);
    procedure sgTablaDrawCell(Sender: TObject; Col, Row: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure btStartClick(Sender: TObject);
    procedure edMutacioChange(Sender: TObject);
    procedure edKeresztChange(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  THely=Record
    X, Y: Byte;
    Jo: Boolean;      //true, ha a vezér nincs ütésben
  End;

  TEgyed=Record
    EXY: Array[1..Max] Of THely;
    EOK: Byte;        //az ütésben nem álló vezérek száma
    JoEgyed: Boolean; //true, ha az ütésben nem álló vezérek szám átlag feletti
  End;

var
  fmGenVezer: TfmGenVezer;
  ACol, ARow: Integer;
  Colors: Array[1..Max,1..Max] Of Boolean;
  EgyedT: Array[1..EgyedSz] Of TEgyed;
  JokSz: Word;        //az átlag feletti egyedek száma
  Josag: Real;        //a populáció ütésben nem álló vezéreinek átlaga
  Kereszt: Byte;      //a keresztezési index
  Uj1, Uj2: TEgyed;   //új egyedek
  IR1, IR2, IJ1, IJ2: Word;  //régi és új egyedek tömbindexei
  PSz: Word;                 //populációk száma
  OKMax, IMax, OldMax, //segédváltozók a populációk generálásánál
  MutSz: Word;         //mutáció erősségét mutató százalékérték

implementation

{$R *.dfm}

procedure TfmGenVezer.btKilepesClick(Sender: TObject);
begin
  //kilépés a programból
  Close;
end;

procedure TfmGenVezer.sgGenVezerClick(Sender: TObject);
begin
  //kattintás után az egyed megjelenítése a képernyőn lévő sakktáblán
  PopKepre;
  With sgGenVezer Do Begin ACol:= Col; ARow:= Row; RePaint End;
  Tablara(ARow);
end;

procedure TfmGenVezer.sgGenVezerDrawCell(Sender: TObject; Col,
  Row: Integer; Rect: TRect; State: TGridDrawState);
begin
  //a populációt megjelenítő StringGrid beállításai
  With sgGenVezer.Canvas.Brush Do
  Begin
    {rögzített cellák}
    If (gdFixed In State) And ((Col=ACol) Or (Row=ARow)) Then
    Color:= clYellow Else Color:=clBtnFace;

    {kiválasztott cella}
    If gdSelected In State Then Color:= clRed;

    {a táblázat belseje}
    If Not((gdSelected In State) Or (gdFixed In State)) Then
    If Odd(Col) Then Color:= clAqua Else Color:= clWindow;
  End;
  sgGenVezer.Canvas.TextRect(Rect,Rect.Left+3,Rect.Top+1,
                             sgGenVezer.Cells[Col,Row]);
  If gdFocused In State Then sgGenVezer.Canvas.DrawFocusRect(Rect);
end;

procedure TfmGenVezer.sgTablaDrawCell(Sender: TObject; Col, Row: Integer;
  Rect: TRect; State: TGridDrawState);
begin
  //a sakktáblát és felállást megjelenítő StringGrid beállításai
  With sgTabla.Canvas.Brush Do
  Begin
    {rögzített cellák}
    If gdFixed In State Then Color:=clWhite;

    {kiválasztott cella}
    If gdSelected In State Then Color:= clSilver;

    {a táblázat belseje}
    If Not((gdSelected In State) Or (gdFixed In State)) Then
    Begin
      Case Odd(Col) XOr Odd(Row) Of
        False: Color:= clWindow;
        True: Color:= clSilver;
      End;
      If Colors[Col,Row] Then Color:= clGreen;
    End;
    sgTabla.Canvas.Font.Size:= 17;
  End;
  sgTabla.Canvas.TextRect(Rect,Rect.Left+16,
                          Rect.Top+4,sgTabla.Cells[Col,Row]);
  If gdFocused In State Then sgTabla.Canvas.DrawFocusRect(Rect);
end;

procedure TfmGenVezer.edKeresztChange(Sender: TObject);
Var Kod: Integer;
begin
  Val(edKereszt.Text, Kereszt, Kod);
end;

procedure TfmGenVezer.edMutacioChange(Sender: TObject);
Var Kod: Integer;
begin
  Val(edMutacio.Text, MutSz, Kod);
end;

Procedure TfmGenVezer.PopInit;
Var I, J: Word;
Begin
  //egy teljes populáció létrehozása
  For I:= 1 To EgyedSz Do With EgyedT[I] Do
  Begin
    For J:= 1 To Max Do With EXY[J] Do
    Begin
      X:= Random(Max)+1;
      Y:= Random(Max)+1;
      Jo:= True;
    End;
    EOK:= 0;
    JoEgyed:= False;
  End;
End;

Procedure TfmGenVezer.Vizsgal;
Var I, J, K, Sz: Word;
    Utesben: Boolean;
Begin
  //a populáció vizsgálata
  //megállapítja minden vezérről, hogy ütésben van-e (-> Utesben)
  //megállapítja minden egyedről, hogy hány vezér elhelyezkedése jó (-> Jo)
  JokSz:= 0; OKMax:= 0;
  For I:= 1 To EgyedSz Do With EgyedT[I] Do
  Begin
    Sz:= 0;
    For J:= 1 To Max Do
    Begin
      Utesben:= False; For K:= 1 To Max Do If J<>K Then
      If EXY[J].X=EXY[K].X Then Begin Utesben:= True; Break End;
      If Not Utesben Then For K:= 1 To Max Do If J<>K Then
      If EXY[J].Y=EXY[K].Y Then Begin Utesben:= True; Break End;
      If Not Utesben Then For K:= 1 To Max Do If J<>K Then
      If Abs(EXY[J].X-EXY[K].X)=Abs(EXY[J].Y-EXY[K].Y) Then
      Begin Utesben:= True; Break End;
      EXY[J].Jo:= Not Utesben;
      If Not Utesben Then Inc(Sz);
    End;
    EOK:= Sz; If EOK>OKMax Then Begin OKMax:= EOK; IMax:= I End;
    Inc(JokSz,EOK);
  End;
  //megállapítja a populáció jóságát:
  //jó helyezetű vezérek számának átlaga-> Josag
  Josag:= JokSz/EgyedSz;
  edJosag.Text:= FloatToStr(Josag);
  //minden egyedről megállapítja, hogy jó-e:
  //átlag feletti a jó helyzetű vezérek száma -> JoEgyed:= True
  JokSz:= 0;
  For I:= 1 To EgyedSz Do With EgyedT[I] Do If EOK>Josag Then
  Begin
    Inc(JokSz);
    JoEgyed:= True;
  End Else JoEgyed:= False;
  edJokSz.Text:= IntToStr(JokSz);
End;

Procedure TfmGenVezer.Keresztez;
Var I, V, R: Word;
Begin
  Inc(PSz);
  //a két legrosszabb egyed keresése
  V:= Random(EgyedSz)+1; R:= Max; IR1:= 0;
  For I:= V+1 To EgyedSz Do With EgyedT[I] Do
  If Not JoEgyed And (EOK<R) Then Begin R:= EOK; IR1:= I End;
  For I:= 1 To V  Do With EgyedT[I] Do
  If Not JoEgyed And (EOK<R) Then Begin R:= EOK; IR1:= I End;

  V:= Random(EgyedSz)+1; R:= Max; IR2:= 0;
  For I:= V+1 To EgyedSz Do With EgyedT[I] Do If I<>IR1 Then
  If Not JoEgyed And (EOK<R)Then Begin R:= EOK; IR2:= I End;
  For I:= 1 To V  Do With EgyedT[I] Do If I<>IR1 Then
  If Not JoEgyed And (EOK<R) Then Begin R:= EOK; IR2:= I End;

  //két jó egyed keresése:
  //nem a két legjobbat, mert akkor nem lenne eléggé nagy a változatosság
  V:= Random(EgyedSz)+1; IJ1:= 0;
  For I:= V+1 To EgyedSz Do With EgyedT[I] Do If JoEgyed Then IJ1:= I;
  For I:= 1 To V  Do With EgyedT[I] Do If JoEgyed Then IJ1:= I;

  V:= Random(EgyedSz)+1; IJ2:= 0;
  For I:= V+1 To EgyedSz Do With EgyedT[I] Do If I<>IJ1 Then
  If JoEgyed Then IJ2:= I;
  For I:= 1 To V  Do With EgyedT[I] Do If I<>IJ1 Then
  If JoEgyed Then IJ2:= I;

  //két jó egyed keresztezése -> Uj1, Uj2: TEgyed
  If IJ1*IJ2<>0 Then
  Begin
    For I:= 1 To Kereszt Do Uj1.EXY[I]:= EgyedT[IJ1].EXY[I];
    For I:= Kereszt+1 To Max Do Uj1.EXY[I]:= EgyedT[IJ2].EXY[I];
    Uj1.JoEgyed:= False;
    For I:= 1 To Kereszt Do Uj2.EXY[I]:= EgyedT[IJ2].EXY[I];
    For I:= Kereszt+1 To Max Do Uj2.EXY[I]:= EgyedT[IJ1].EXY[I];
    Uj2.JoEgyed:= False;
  End;
End;

Procedure TfmGenVezer.Mutacio;
Var I, J: Word;
Begin
  //a populáció minden egyedének mindkét koordinátáját MutSz valószínűséggel
  //módosítjuk egy véletlen értékr
  For I:= 1 To EgyedSz Do With EgyedT[I] Do
  For J:= 1 To Max Do With EXY[J] Do
  Begin
    If Random(100)<MutSz Then X:= Random(Max)+1;
    If Random(100)<MutSz Then Y:= Random(Max)+1;
  End;
End;

procedure TfmGenVezer.btStartClick(Sender: TObject);
begin
  //populációk generálása és vizsgálata
  OKMax:= 0; IMax:=
 0; PSz:= 0;
  Repeat
    OldMax:= OKMax;
    Keresztez;
    If JokSz In [2,3,4] Then Mutacio;
    If (IR1*IR2<>0) And (IJ1*IJ2<>0) Then
    Begin
      EgyedT[IR1]:= Uj1;
      EgyedT[IR2]:= Uj2;
    End
    Else Mutacio;
    Vizsgal;
    PopKepre;
    edPSz.Repaint;
    If OKMax>OldMax Then
    Begin
      sgGenVezer.Repaint;
      edKesz.Text:= IntToStr(OKMax); edKesz.Repaint;
      edIndex.Text:= IntToStr(IMax); edIndex.Repaint;
      Tablara(IMax); sgTabla.Repaint;
    End;
  Until (OKMax>=Max) Or (PSz>20000);
  //max értékig, vagy maximum 20000 permutációig keresünk

end;

Procedure TfmGenVezer.PopKepre;
Var I, J: Word;
Begin
  //a populáció minden egyedét, a jó elhelyezkedésü vezérek számával együtt
  //megjeleníti egy StringGrid-ben
  With sgGenVezer Do
  Begin
    For I:= 1 To EgyedSz Do With EgyedT[I] Do
    Begin
      For J:= 1 To Max Do With EXY[J] Do
      Begin
        Cells[2*J-1,I]:= Char(96+X);
        Cells[2*J  ,I]:= IntToStr(Y);
      End;
      Cells[ColCount-1,I]:= IntToStr(EOK);
    End;
  End;
  edPSz.Text:= IntToStr(PSz);
End;

Procedure TfmGenVezer.Tablara(Ind: Word);
Var I, J: Word;
Begin
  //egy egyed megjelenítés a sakktáblán
  With sgTabla Do
  Begin
    For I:= 1 To ColCount-1 Do For J:= 1 To RowCount-1 Do Cells[I,J]:= '';
    For I:=1 To Max Do For J:= 1 To Max Do Colors[I,J]:= False;
    With EgyedT[Ind] Do For I:= 1 To Max Do With EXY[I] Do
    Begin
      Cells[X,Max-Y+1]:= 'V';
      Colors[X,Max-Y+1]:= Jo;
    End;
  End;
  sgTabla.Repaint;
End;

procedure TfmGenVezer.FormCreate(Sender: TObject);
Var I: Word;
    Ch: Char;
begin
  //a program vízuális elemeinek megjelenítése, a kezdeti populáció generálása
  ACol:= 1; ARow:= 1;
  With sgGenVezer Do
  Begin
    RowCount:= EgyedSz+1;
    ColWidths[0]:= 35;
    For I:= 1 To RowCount-1 Do Cells[0,I]:= IntToStr(I)+'.';
    For I:= 1 To Max Do
    Begin
      Cells[2*I-1,0]:= IntToStr(I)+'.X';
      Cells[2*I  ,0]:= IntToStr(I)+'.Y';
    End;
    Cells[ColCount-1,0]:= 'EOK';
  End;

  With sgTabla Do
  Begin
    ColWidths[9]:= 0;
    RowHeights[9]:= 0;
    For I:= 1 To 8 Do Cells[0,I]:= IntToStr(9-I);
    For Ch:= 'a' To 'h' Do Cells[Ord(Ch)-96,0]:= Ch;
    Col:= 9; Row:= 9;
  End;

  Randomize;
  PopInit;
  Vizsgal;
  PopKepre;

  //kezdő és alapértelmezett értékek:
  edEgyedSz.Text:= IntToStr(EgyedSz);
  PSz:= 1; edPSz.Text:= IntToStr(PSz);
  MutSz:= 25; edMutacio.Text:= IntToStr(MutSz);
  Kereszt:= 4; edKereszt.Text:= IntToStr(Kereszt);

end;

procedure TfmGenVezer.btUjPopClick(Sender: TObject);
Var I, J: Word;
begin
  //új populáció generálása
  For I:= 1 To Max Do For J:= 1 To Max Do Colors[I,J]:= False;
  With sgTabla Do
  For I:= 1 To ColCount-1 Do For J:= 1 To RowCount-1 Do Cells[I,J]:= '';
  PopInit;
  Vizsgal;
  PopKepre;
  PSz:= 1; edPSz.Text:= IntToStr(PSz);
end;

end.

 

 

Vezérek elhelyezése a sakktáblán ütközésmentesítő algoritmussal

 

Írjunk programot, mely az ütközésmentesítő algoritmus segítségével ütésmentesen elhelyez 8 vezért a sakktáblán. Nem kell az összes megoldást megkeresnie, ha talál egy jó megoldást, a program álljon le.

 

A program tesztelése közben kiderült, hogy a kettős cserét alkalmazó algoritmus gyakran nem tudja befejezni eredményesen a keresést, ezért a hármas cserét használót alkalmaztam. A biztonság kedvéért a maximális próbálgatási lehetőséget 1000-re állítottam be. Tesztelés közben 772 volt a maximális menetszám. Az alaphelyzet, amiből a keresés indul, a vezérek egy véletlen elhelyezése a táblán. A futtatási környezet a véletlen mutációt alkalmazó programhoz hasonló. A keresés a Start gombra indul, Alap gombbal újra kereshetünk. A program kiírja a lépések számát és az ütközésszámot.

 

A program futási képe a keresés előtt:

 

 

Majd a keresés befejeztével (futási idő 1 másodpercnél kisebb úgy, hogy a képernyő minden lépésben frissül):

 

 

A program listája:

 

unit UUtkVez;


interface

uses
  Windows, Messages, SysUtils, Variants, Classes, 

  Graphics, Controls, Forms, Dialogs, StdCtrls, Grids;

Const Max=8;

type
  TfmUtkVez = class(TForm)
    lbUtkVez: TLabel;
    btKilepes: TButton;
    sgTabla: TStringGrid;
    sgUtkVez: TStringGrid;
    btStart: TButton;
    edN: TEdit;
    btAlap: TButton;
    edUtOSz: TEdit;
    Procedure Kepernyore;
    Procedure Tablara;
    Function UTSz(O: Word): Word;
    Procedure Utkozesek;
    procedure btKilepesClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure sgTablaDrawCell(Sender: TObject; Col, Row: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure btStartClick(Sender: TObject);
    procedure btAlapClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  fmUtkVez: TfmUtkVez;
  ACol, ARow: Integer;
  MaxMenet, Menet, UtOSz: Word;
  T, UTT: Array[1..Max] Of Word;

implementation

{$R *.dfm}

procedure TfmUtkVez.btKilepesClick(Sender: TObject);
begin
  Close;
end;

procedure TfmUtkVez.sgTablaDrawCell(Sender: TObject; Col, Row: Integer;
  Rect: TRect; State: TGridDrawState);
begin
  With sgTabla.Canvas.Brush Do
  Begin
    {rögzített cellák}
    If gdFixed In State Then Color:=clWhite;

    {kiválasztott cella}
    If gdSelected In State Then Color:= clSilver;

    {a táblázat belseje}
    If Not((gdSelected In State) Or (gdFixed In State)) Then
    Begin
      Case Odd(Col) XOr Odd(Row) Of
        False: Color:= clWindow;
        True: Color:= clSilver;
      End;
    End;
    sgTabla.Canvas.Font.Size:= 17;
  End;
  sgTabla.Canvas.TextRect(Rect,Rect.Left+12,
                          Rect.Top+1,sgTabla.Cells[Col,Row]);
  If gdFocused In State Then sgTabla.Canvas.DrawFocusRect(Rect);
end;

procedure TfmUtkVez.FormCreate(Sender: TObject);
Var I: Word;
    Ch: Char;
begin
  With sgUtkVez Do
  Begin
    For I:= 1 To Max Do Cells[I,0]:= Chr(96+I);
  End;

  With sgTabla Do
  Begin
    ColWidths[9]:= 0;
    RowHeights[9]:= 0;
    For I:= 1 To 8 Do Cells[0,I]:= IntToStr(9-I);
    For Ch:= 'a' To 'h' Do Cells[Ord(Ch)-96,0]:= Ch;
    Col:= 9; Row:= 9;
  End;

  Randomize;
  btAlapClick(Sender);
  MaxMenet:= 1000;
end;

procedure TfmUtkVez.btAlapClick(Sender: TObject);
Var I, J, A, B, P: Word;
begin
  For I:= 1 To Max Do T[I]:= I;
  For I:= 1 To 1000 Do
  Begin
    A:= Random(Max)+1; B:= Random(Max)+1;
    P:= T[A]; T[A]:= T[B]; T[B]:= P;
  End;
  With sgUtkVez Do
  Begin
    For I:= 1 To ColCount-1 Do For J:= 1 To RowCount-1 Do Cells[I,J]:= '';
    RowCount:= 5;
  End;
  Menet:= 1;
  Kepernyore;
  Tablara;
  Utkozesek;
  edUtOSz.Text:= IntToStr(UTOSz);
end;

Procedure TfmUtkVez.Kepernyore;
Var I: Word;
Begin
  With sgUtkVez Do
  Begin
    If RowCount-1<Menet Then RowCount:= Menet+1;
    Cells[0,Menet]:= IntToStr(Menet)+'.';
    For I:= 1 To Max Do Cells[I,Menet]:= IntToStr(T[I]);
  End;
End;

Procedure TfmUtkVez.Tablara;
Var I, J: Word;
Begin
  With sgTabla Do
  Begin
    For I:= 1 To ColCount-1 Do For J:= 1 To RowCount-1 Do Cells[I,J]:= '';
    For I:= 1 To Max Do Cells[I,Max-T[I]+1]:= 'V';
  End;
End;

Function TfmUtkVez.UTSz(O: Word): Word;
Var I, U: Word;
Begin
  U:= 0;
  For I:= 1 To Max Do If I<>O Then
  If Abs(T[O]-T[I])=Abs(O-I) Then Inc(U);
  UTSz:= U;
End;

Procedure TfmUtkVez.Utkozesek;
Var I: Word;
Begin
  UTOSz:= 0; For I:= 1 To Max Do
  Begin UTT[I]:= UTSz(I); Inc(UTOSz,UTT[I]) End;
End;

procedure TfmUtkVez.btStartClick(Sender: TObject);
Var X1, X2, X3, P, A, B: Word;
begin
  Menet:= 1;
  While (UTOSz>0) And (Menet<MaxMenet) Do
  Begin
    Inc(Menet); Utkozesek; A:= UTOSz;
    X1:= 1; While UTT[X1]=0 Do X1:= Random(Max)+1;
    X2:= Random(Max)+1; X3:= Random(Max)+1;
    P:= T[X1]; T[X1]:= T[X2]; T[X2]:= T[X3]; T[X3]:= P;
    Utkozesek; B:= UTOSz;
    If B>A Then
    Begin P:= T[X3]; T[X3]:= T[X2]; T[X2]:= T[X1]; T[X1]:= P End;
    Utkozesek;
    edN.Text:= IntToStr(Menet);
    edUtOSz.Text:= IntToStr(UTOSz);
    Tablara;
    Kepernyore;
    RePaint;
  End;
end;

end.