| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- { $HDR$}
- {**********************************************************************}
- { Unit archived using Team Coherence }
- { Team Coherence is Copyright 2002 by Quality Software Components }
- { }
- { For further information / comments, visit our WEB site at }
- { http://www.TeamCoherence.com }
- {**********************************************************************}
- {}
- { $Log: 21828: EZEngine.pas
- Rev 1.0 2003.07.13 12:12:02 AM czhower
- Initial checkin
- Rev 1.0 2003.05.19 2:54:00 PM czhower
- }
- unit EZEngine;
- interface
- {$ifdef fpc}
- {$mode objfpc}{$H+}
- {$endif}
- {
- ELIZA -- an interactive parroting
- Original Source: CREATIVE COMPUTING - MORRISTOWN, NEW JERSEY, late 1970's
- Converted from Basic and some language called Inform to Delphi by
- Chad Z. Hower aka Kudzu in 2002 - email: chad at hower dot org
- Converted to objects, and implementation rewritten from scratch. Logic matched as best possible
- but BASIC code also had bugs in logic. Inform version also differed slightly, but probaly more
- accurate, but I am no Inform expert.
- Since that time I have made several custom modifications an improvements including the addition
- of personalities.
- Note:
- Because of the conversion from older languages, this is not my best code.
- Slowly over time I am cleaning it up to make it more proper OO code. I am also
- expanding its capabilities beyond its original design.
- }
- uses
- Classes,
- ezPersonality;
- type
- TEZEngine = class(TComponent)
- protected
- FConjugations: TStrings;
- FDone: Boolean;
- FLastMsg: string;
- FPersonality: TEZPersonality;
- //
- procedure InitConjugations;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure SetPersonality(const AName: string);
- function TalkTo(AMsg: string): string; overload;
- function TalkTo(AMsg: string; var VSound: string): string; overload;
- //
- property Done: Boolean read FDone;
- property Personality: TEZPersonality read FPersonality;
- end;
- implementation
- uses
- SysUtils, StrUtils;
- { TEZEngine }
- constructor TEZEngine.Create(AOwner: TComponent);
- begin
- inherited;
- FConjugations := TStringList.Create;
- InitConjugations;
- end;
- destructor TEZEngine.Destroy;
- begin
- FreeAndNil(FPersonality);
- FreeAndNil(FConjugations);
- inherited;
- end;
- procedure TEZEngine.InitConjugations;
- begin
- with FConjugations do begin
- Add('Are=am');
- Add('Were=was');
- Add('You=I');
- Add('Your=my');
- Add('I''ve=you''ve');
- Add('I''m=you''re');
- Add('Me=you');
- end;
- end;
- procedure TEZEngine.SetPersonality(const AName: string);
- begin
- FreeAndNil(FPersonality);
- FPersonality := TEZPersonality.ConstructPersonality(AName);
- end;
- function TEZEngine.TalkTo(AMsg: string; var VSound: string): string;
- var
- i, j: Integer;
- s: string;
- LConj: string;
- LFoundKeyword: string;
- LFoundKeywordIdx: Integer;
- LFoundKeywordPos: Integer;
- LKeyword: string;
- LWordIn: string;
- LWordOut: string;
- begin
- VSound := '';
- if FPersonality = nil then begin
- raise Exception.Create('No personality has been specified.');
- end;
- Result := '';
- LConj := '';
- LFoundKeyword := '';
- LFoundKeywordIdx := FPersonality.Keywords.IndexOf('--NOKEYFOUND--');
- LFoundKeywordPos := 0;
- //
- AMsg := ' ' + Trim(AMsg) + ' ';
- AMsg := StringReplace(AMsg, '''', '', [rfReplaceAll]);
- // TODO: Respond to ones with ?
- // Replace with spaces so ' bug ' will match ' bug. ' etc.
- AMsg := StringReplace(AMsg, '?', ' ', [rfReplaceAll]);
- AMsg := StringReplace(AMsg, '!', ' ', [rfReplaceAll]);
- AMsg := StringReplace(AMsg, '.', ' ', [rfReplaceAll]);
- if AnsiSameText(AMsg, FLastMsg) then begin
- Result := 'Please don''t repeat yourself.';
- end else if AnsiContainsText(AMsg, 'SHUT ') then begin
- Result := 'How would you like it if I told you to shut up? I am sorry but we cannot continue'
- + ' like this. Good bye.';
- FDone := True;
- end else if Trim(AMsg) = '' then begin
- Result := 'I cannot help you if you do not talk to me.';
- end else begin
- FLastMsg := AMsg;
- // Find Keyword
- for i := 0 to FPersonality.Keywords.Count - 1 do begin
- LKeyword := FPersonality.Keywords[i];
- for j := 1 to Length(AMsg) - Length(LKeyword) + 1 do begin
- if AnsiSameText(Copy(AMsg, j, Length(LKeyword)), LKeyword) then begin
- LFoundKeywordIdx := i;
- LFoundKeyword := LKeyword;
- LFoundKeywordPos := j;
- Break;
- end;
- // Break out of second loop
- if LFoundKeyword <> '' then begin
- Break;
- end;
- end;
- end;
- // Take part of string and conjugate it using the list of strings to be swapped
- LConj := ' ' + RightStr(AMsg, Length(AMsg) - Length(LFoundKeyword) - LFoundKeywordPos + 1)
- + ' ';
- for i := 0 to FConjugations.Count - 1 do begin
- LWordIn := FConjugations.Names[i];
- LWordOut := FConjugations.Values[LWordIn] + ' ';
- LWordIn := LWordIn + ' ';
- LConj := StringReplace(LConj, LWordIn, LWordOut, [rfReplaceAll, rfIgnoreCase]);
- end;
- // Only one space
- if Copy(LConj, 1, 1) = ' ' then begin
- Delete(LConj, 1, 1);
- end;
- LConj := StringReplace(LConj, '!', '', [rfReplaceAll]);
- // Get reply
- s := TEZReply(FPersonality.Keywords.Objects[LFoundKeywordIdx]).NextText;
- VSound := TEZReply(FPersonality.Keywords.Objects[LFoundKeywordIdx]).Sound;
- if AnsiPos('*', s) = 0 then begin
- Result := s;
- end else if Trim(LConj) = '' then begin
- Result := 'You will have to elaborate more for me to help you.';
- end else begin
- Result := StringReplace(s, '*', LConj, [rfReplaceAll, rfIgnoreCase]);
- end;
- end;
- end;
- function TEZEngine.TalkTo(AMsg: string): string;
- var
- LSound: string;
- begin
- Result := TalkTo(AMsg, LSound);
- end;
- end.
|