BOT w Delphi

Pedros

No to teraz Pedros wkracza do akcji :) Oto moj pierwszy art na 4programmers.net. Bedzie on dotyczyl pisania wlasnego bota w delphi. Pewnie niektorzy mieli okazje rozmawiac z Monika. Pierwowzor Moniki zostal napisany w delphi tylko ze potem zostala przepisana w php i teraz jest dostepna na mojej stronie <a href="http://www.pedros.prv.pl" TARGET=_BLANK>pedros.prv.pl</a>. No celem artykulu jest przybilzenie wam zasady jej dzialania. Do napisania bota bedzie nam potrzebne delphi i plik tekstowy z odpowiedziami. Pamietam ze niektorzy chcieli poznac jej dzialanie no to teraz je ladnie napisze :) Wydaje mi sie ze najlepiej jest napisac funkcje ktora przyjmuje zdanie i zdanie zwraca wyglada ona tak:

function bot(msg : string):string;

Najlepiej na poczatku poobcinac wszystkie ogonki z polskich znakow. Do tego tez sobie napisalem funkcje. Juz wam ja napisze zebyscie sie zabardzo nie zmeczyli :)

function wytnijpol(text : string):string;
var
  s,a : string;
begin
  result := text;
  a := text;
  s := text;
  if Pos('ą',text) <> 0 then
  begin
    s := StringReplace(a,'ą','a',[rfReplaceAll]);
    a := s;
  end;
  if Pos('ę',text) <> 0 then
  begin
    s := StringReplace(a,'ę','e',[rfReplaceAll]);
    a := s;
  end;
  ...
  Result := s;
end;

Teraz by sie przydalo sprawdzic czy w zdanie zawiera przeklenstwa i takie tam :) No do tego tez musialem sobie napisac funkcje ktora wyglada mniej wiecej tak:

function przeklenstwa(text : string):boolean;

Cala funkcja wyglada tak: (te przeklenstwa to tylko na potrzeby artykulu :))

function przeklenstwa(text : string):boolean;
begin
  result := false;
  if Pos('dupa',text) <> 0 then Result := True;
  if Pos('kurw',text) <> 0 then Result := True;
  ...
end;

Moze jeszcze wyjasnie dlaczego 'kurw' a nie np 'kurwa' no bo jak ktos napisze 'kurwy' to ta funkcja uzna to za przeklenstwo a to wina naszego wspanialego jezyka polskiego :) Ja zrobilem ze jak:

przeklenstwa(msg) = true

to zeby wczytalo odpowiednie odpowiedzi u mnie to sa takie ladne odpowiedzi z brzydkimi tekstami, natomiast jezeli:

przeklenstwa(msg) = false

to wczytuje normalne odpowiedzi. Teksty z odpowiedziami to jest zwykly plik tekstowy w ktorym jest zdanie pod zdaniem. U nas ten plik bedzie sie sam rozrastal poniewaz napiszemy to w taki sposob aby nasz bot mial mozliwosc uczenia sie tego co ktos do niego napisze. Dobrze jezeli mamy juz obciete ogonki i wczytane odpowiednie odpowiedzi to mozemy zajac sie szukaniem najwazniejszego a mianowicie podmiotu :) No to moze troszke teorii na poczatek :) Ja sobie zalozylem ze podmiot to powienien byc dluzszy niz 3 literki i nie byc jednym z wykluczonych slow jak np jest, albo bardzo. Do wyszukania podmiotu potrzebna nam bedzie jeszcze jedna proceduka ktora juz wam dam w calosci :)

procedure TForm1.rozdzielanie(text,znak : String);
var
 Lancuch : string;
 P : Integer;
begin
 rozdziel.clear;
 Lancuch := text;
 P := Pos(znak, Lancuch);
 while P > 0 do begin
 rozdziel.Add(Copy(Lancuch, 1, P - 1));
 Delete(Lancuch, 1, P);
 P := Pos(znak, Lancuch);
end;
 rozdziel.Add(Lancuch);
end;

Aby ta procedura w pelni ladnie dzialala to nalezy jeszcze dodac zmienna globalna:

rozdziel : TStrings; 

a w OnCreate:

rozdziel := TStringList.Create;

a teraz zabierzemy sie za wyszukiwanie podmiotu :) Teraz tylko wystarczy wziac i rozdzielic zdanie na pojedyncze wyrazy. Robimy to wlasnie ta procedurka ktora napisalem wyzej czyli rozdzielanie(msg, ' '); Teraz w zmiennej rozdziel mamy linia pod linia wyrazy i tylko nalezy sprawdzic ktory spelnia warunki podmiotu. Wiec bierzemy zwykla petle i:

for i := 0 to rozdziel.Count-1 do
begin
  if nie_podmiot(rozdziel.Strings[i]) = false then  // to jest funkcja sprawdzajaca czy dany wyraz nie jest wykluczony opisana nizej
  begin
    podmiot := rozdziel.Strings[i];  
    break;  //jezeli znalezlismy juz podmiot to mozna zakonczyc petle
  end;
end;

Pewnie was zaskoczyla funkcja niepodmiot ale juz ja opisuje :) Albo zamiast opisywac ja podam :)

function nie_podmiot(text : string):boolean;
begin
  Result := false;
  if (Length(text) < 3) then  Result := true;
  if (Pos('jest',text) <> 0) then  result := true;
  if (Pos('naj',text) <> 0) then  result := true;
  ...
end;

No mozna zamiast funkcji Pos uzyc np zywklego porownania ale czasami to moze sprawic ze znajdziemy wyraz ktory nie jest podmiotem, np. 'jestem' Jakbysmy uzyli porownania czyli if text <> 'jest' then false to ten wyraz zostanie potraktowany jako podmiot a raczej nim nie bedzie. No ale jak chcecie porownywanie to prosze bardzo mnie to wsio kukurydza :) Dobra mamy znaczacy wyraz (albo i nie ale to pozniej :) ) Jezeli mamy juz nasz ukochany podmiot to teraz tylko wystarczy wyszukac odpowiedzi ktore zawieraja to co przed chwila znalezlismy :) No chyba ze nic nie znalezlismy to trzeba to zrobic inaczej :) Ale to moze na przykladzie :)

if podmiot <> '' then
begin
  for i := 0 to texty.Count-1 do //texty to zmienna TStrings i do niej wczytalismy wczesniej odpowiedzi
  begin
    if Pos(podmiot, texty.Strings[i]) <> 0 then
      odpowiedzi.Add(texty.Strings[i])
  end;
  //teraz tylko losujemy z tego co przed chwila wybralismy ze zmiennej texty ale pamietajmy zeby wczesniej gdzies Randomize wrzucic :)
  odpowiedz := odpowiedzi.Strings[Random(odpowiedzi.Count-1)];
end
else //no gdy jednak nie udalo nam sie znalesc podmiotu bo ktos napisal, np. 'no to co'; to poprostu losujemy z calosci cos moze jednak sie cos trafi pasujacego do rozmowy :)
  odpowiedz := teksty.Strings[Random(teksty.Count-1)];

Pewnie niektorym juz sie wydaje ze mozna zrobic result := odpowiedz ale jeszcze chwila bo to nie koniec naszej funkcji :) Przeciez nasz bot mial miec jeszcze mozliwosc uczenia sie no i chyba przydaloby sie to tez napisac :) No to bedzie tylko proste dopisywanie do pliku zdania na ktorym sie skupilismy. No oczywiscie jezeli to zdanie spelnia odpowiednie warunki :) No u mnie warunkiem bylo aby zdanie zawieralo wiecej niz 3 wyrazy. Mozna oczywiscie jeszcze dodac zeby nie dodawac zdan w ktorych sa, np. adresy www ale to juz sobie sami dopiszecie :) A do sprawdzenia czy w danym zdaniu jest wiecej niz 3 wyrazy znow posluzymy sie procedurka ktora juz podalem wyzej czyli piszemy:

rozdzielanie(msg);
if rozdziel.Count > 3 then
begin
  if przeklenstwa(msg) then
    //dopisujemy do pliku z przeklenstwami
  else
    //dopisujemy do pliku z normalnymi odzywkami
end;
//teraz tylko wystarczy na sam koniec dodac
result := odpowiedz;

No to juz chyba bedzie koniec mojego debiutanckiego artykulu :) Dodam jeszcze ze naszego bota mozna wzbogacic o mnustwo dodatkow, np. zeby zamienial koncowki wyrazwo na meskie lub zenskie :) W funkcjach przeklenstwa i nie_podmiot specjalnie sa te ... no bo tam mozecie sobie dodac co tylko chcecie ja wam tylko dalem szkielet ktory wykozystacie jak tylko bedziecie chcieli. Moze jeszcze dodam ze niektore przyklady byly pisane bez sprawdzania i moga nie dzialac ale powinny :) Mam nadzieje ze Monika nie bedzie miala za duzej konkurencji z innymi botami :)

Poniewaz wielu plakalo ze nie ma przykladu napisalem specjalnie dla was przyklad i jest dostepny w dziale kody zrodlowe: delphi_bot.zip

21 komentarzy

dał bys jakis link bo mi cały czas jakies błędy wyskakuja

mam problem
co wstawic na forme
jak maja sie nazywac pliki z odpowiedziami
prosze o pomoc

@ten link nie działa już od dawna...
A i nawet ten internetowy bot (monika) już nie działa.
I dziękuję za tego gotowca, dzięki niemu robię coś w stylu mojamagda.pl

ten link z załoncznikiem nie działa :( :(

Swego czasu pisałem takie coś w PHP, ale jak mu powiedziałem, że ma cenzurować wszelkie napisy "huj", to napisałem mu "podsłuchuj", a on mi wywalił "podsłuch**j" :-)

Gadałem z monią. Szkoda że to blondynka z ujemnym IQ...

strasznie fajna zabawka!

function BezPol(s: string): string; var i, p: integer;
const pol: string = 'ąćęłńóśźżĄĆĘŁŃÓŚŹŻ';
lac: string = 'acelnoszzACELNOSZZ';
begin
for i:=1 to Length(s) do
begin p:=Pos(s[i],pol); if p>0 then s[i]:=lac[p] end;
BezPol:=s
end;

Jesteś wielki, Pedros.
Ave.

wszystko spoko, tylko inteligencja botMoniki to coś około 10IQ, mój pies byłby mądrzejszy gdybym tylko go miał...
no ale rozumiem, że od czegoś trzeba zacząć.

Jak można zaprogramować zamianę końcówek? Nic mi do głowy nie prxychodzi

nie ma najmneijszego sensu i potrzeby sprawdzania czy znak jest w tekscie przed zamiania przez StringReplace - po prostu jesli go nie ma to nie zamieni - tylko niepotrzebnie obciazasz procka :)

Przenosze do gotowcow...

Niezły artykuł.. ja bym tylko miał objekcje co do funkcji na pozbycie się polskich liter. Oto skrócona pełna wersja:

function Pol(s: string): string; // Usuwanie "ogonków"
var
  i:integer;
begin
  result := s;
  for i:=1 to Length(s) do
  begin
    case s[i] of
      'ą' : Result[i] := 'a';
      'ę' : Result[i] := 'e';
      'ś' : Result[i] := 's';
      'ć' : Result[i] := 'c';
      'ń' : Result[i] := 'n';
      'ż' : Result[i] := 'z';
      'ź' : Result[i] := 'z';
      'ó' : Result[i] := 'o';
      'ł' : Result[i] := 'l';
      'Ą' : Result[i] := 'A';
      'Ę' : Result[i] := 'E';
      'Ś' : Result[i] := 'S';
      'Ć' : Result[i] := 'C';
      'Ń' : Result[i] := 'N';
      'Ż' : Result[i] := 'Z';
      'Ź' : Result[i] := 'Z';
      'Ó' : Result[i] := 'O';
      'Ł' : Result[i] := 'L';
      else
      Result[i] := s[i];
    end;
  end;  
end;

Różnica tylko w nazwie (Tu jest POL a tam WYTNIJPOL). Czy nie prościej? :)

Funkcja pobrana z kodu źródłowego NSP 3.0 beta release soon...

Brawo Pedros

szkoda że nie ma 7 :)

kod może być ,ale nie ma kodu źródłowego, to co jest na stronie jest niepełne, daje 4, a ty Pedros wrzuć kodzik do działu kody źródłowe !!!

Po pierwsze to nie jest gotowiec tylko artykul On wam nie da gotowego zrodla tylko jest napisane jak po kolei wszystko zrobic z malymi przykladami funkcji mysle ze wystarczajaco Teraz tylko siasc i napisac wszystko. A jesli chodzi o kod zrodlowy to go nie bedzie :) Bo jak chcecie sie czegos nauczyc jak bedziecie kozystac z gotowcow nie lepiej jest punkt po punkcie sobie samemu napisac? :) No bardzo prawdopodobne ze wrzuce do dzialu Kody zrodlowe funkcje do tworzenia zdan na podstawie algorytmu ktory jakis czas temu przedstawil Kapustka ale to jak go troche poprawie bo teraz czasami sie wiesza. I pamietajcie to jest artykul a nie gotowiec :)

Super- daje 6!!!! tylko kiedy będzie żródło ??