EZEngine.pas

<< Click to Display Table of Contents >>

Navigation:  Demos > X > Eliza >

EZEngine.pas

{ $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

 

{

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.