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.