restemplate/indy/examples/elizaweb/ezEngine.pas

198 lines
6.0 KiB
Plaintext
Raw Normal View History

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