2
0

ezEngine.pas 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. { $HDR$}
  2. {**********************************************************************}
  3. { Unit archived using Team Coherence }
  4. { Team Coherence is Copyright 2002 by Quality Software Components }
  5. { }
  6. { For further information / comments, visit our WEB site at }
  7. { http://www.TeamCoherence.com }
  8. {**********************************************************************}
  9. {}
  10. { $Log: 21828: EZEngine.pas
  11. Rev 1.0 2003.07.13 12:12:02 AM czhower
  12. Initial checkin
  13. Rev 1.0 2003.05.19 2:54:00 PM czhower
  14. }
  15. unit EZEngine;
  16. interface
  17. {$ifdef fpc}
  18. {$mode objfpc}{$H+}
  19. {$endif}
  20. {
  21. ELIZA -- an interactive parroting
  22. Original Source: CREATIVE COMPUTING - MORRISTOWN, NEW JERSEY, late 1970's
  23. Converted from Basic and some language called Inform to Delphi by
  24. Chad Z. Hower aka Kudzu in 2002 - email: chad at hower dot org
  25. Converted to objects, and implementation rewritten from scratch. Logic matched as best possible
  26. but BASIC code also had bugs in logic. Inform version also differed slightly, but probaly more
  27. accurate, but I am no Inform expert.
  28. Since that time I have made several custom modifications an improvements including the addition
  29. of personalities.
  30. Note:
  31. Because of the conversion from older languages, this is not my best code.
  32. Slowly over time I am cleaning it up to make it more proper OO code. I am also
  33. expanding its capabilities beyond its original design.
  34. }
  35. uses
  36. Classes,
  37. ezPersonality;
  38. type
  39. TEZEngine = class(TComponent)
  40. protected
  41. FConjugations: TStrings;
  42. FDone: Boolean;
  43. FLastMsg: string;
  44. FPersonality: TEZPersonality;
  45. //
  46. procedure InitConjugations;
  47. public
  48. constructor Create(AOwner: TComponent); override;
  49. destructor Destroy; override;
  50. procedure SetPersonality(const AName: string);
  51. function TalkTo(AMsg: string): string; overload;
  52. function TalkTo(AMsg: string; var VSound: string): string; overload;
  53. //
  54. property Done: Boolean read FDone;
  55. property Personality: TEZPersonality read FPersonality;
  56. end;
  57. implementation
  58. uses
  59. SysUtils, StrUtils;
  60. { TEZEngine }
  61. constructor TEZEngine.Create(AOwner: TComponent);
  62. begin
  63. inherited;
  64. FConjugations := TStringList.Create;
  65. InitConjugations;
  66. end;
  67. destructor TEZEngine.Destroy;
  68. begin
  69. FreeAndNil(FPersonality);
  70. FreeAndNil(FConjugations);
  71. inherited;
  72. end;
  73. procedure TEZEngine.InitConjugations;
  74. begin
  75. with FConjugations do begin
  76. Add('Are=am');
  77. Add('Were=was');
  78. Add('You=I');
  79. Add('Your=my');
  80. Add('I''ve=you''ve');
  81. Add('I''m=you''re');
  82. Add('Me=you');
  83. end;
  84. end;
  85. procedure TEZEngine.SetPersonality(const AName: string);
  86. begin
  87. FreeAndNil(FPersonality);
  88. FPersonality := TEZPersonality.ConstructPersonality(AName);
  89. end;
  90. function TEZEngine.TalkTo(AMsg: string; var VSound: string): string;
  91. var
  92. i, j: Integer;
  93. s: string;
  94. LConj: string;
  95. LFoundKeyword: string;
  96. LFoundKeywordIdx: Integer;
  97. LFoundKeywordPos: Integer;
  98. LKeyword: string;
  99. LWordIn: string;
  100. LWordOut: string;
  101. begin
  102. VSound := '';
  103. if FPersonality = nil then begin
  104. raise Exception.Create('No personality has been specified.');
  105. end;
  106. Result := '';
  107. LConj := '';
  108. LFoundKeyword := '';
  109. LFoundKeywordIdx := FPersonality.Keywords.IndexOf('--NOKEYFOUND--');
  110. LFoundKeywordPos := 0;
  111. //
  112. AMsg := ' ' + Trim(AMsg) + ' ';
  113. AMsg := StringReplace(AMsg, '''', '', [rfReplaceAll]);
  114. // TODO: Respond to ones with ?
  115. // Replace with spaces so ' bug ' will match ' bug. ' etc.
  116. AMsg := StringReplace(AMsg, '?', ' ', [rfReplaceAll]);
  117. AMsg := StringReplace(AMsg, '!', ' ', [rfReplaceAll]);
  118. AMsg := StringReplace(AMsg, '.', ' ', [rfReplaceAll]);
  119. if AnsiSameText(AMsg, FLastMsg) then begin
  120. Result := 'Please don''t repeat yourself.';
  121. end else if AnsiContainsText(AMsg, 'SHUT ') then begin
  122. Result := 'How would you like it if I told you to shut up? I am sorry but we cannot continue'
  123. + ' like this. Good bye.';
  124. FDone := True;
  125. end else if Trim(AMsg) = '' then begin
  126. Result := 'I cannot help you if you do not talk to me.';
  127. end else begin
  128. FLastMsg := AMsg;
  129. // Find Keyword
  130. for i := 0 to FPersonality.Keywords.Count - 1 do begin
  131. LKeyword := FPersonality.Keywords[i];
  132. for j := 1 to Length(AMsg) - Length(LKeyword) + 1 do begin
  133. if AnsiSameText(Copy(AMsg, j, Length(LKeyword)), LKeyword) then begin
  134. LFoundKeywordIdx := i;
  135. LFoundKeyword := LKeyword;
  136. LFoundKeywordPos := j;
  137. Break;
  138. end;
  139. // Break out of second loop
  140. if LFoundKeyword <> '' then begin
  141. Break;
  142. end;
  143. end;
  144. end;
  145. // Take part of string and conjugate it using the list of strings to be swapped
  146. LConj := ' ' + RightStr(AMsg, Length(AMsg) - Length(LFoundKeyword) - LFoundKeywordPos + 1)
  147. + ' ';
  148. for i := 0 to FConjugations.Count - 1 do begin
  149. LWordIn := FConjugations.Names[i];
  150. LWordOut := FConjugations.Values[LWordIn] + ' ';
  151. LWordIn := LWordIn + ' ';
  152. LConj := StringReplace(LConj, LWordIn, LWordOut, [rfReplaceAll, rfIgnoreCase]);
  153. end;
  154. // Only one space
  155. if Copy(LConj, 1, 1) = ' ' then begin
  156. Delete(LConj, 1, 1);
  157. end;
  158. LConj := StringReplace(LConj, '!', '', [rfReplaceAll]);
  159. // Get reply
  160. s := TEZReply(FPersonality.Keywords.Objects[LFoundKeywordIdx]).NextText;
  161. VSound := TEZReply(FPersonality.Keywords.Objects[LFoundKeywordIdx]).Sound;
  162. if AnsiPos('*', s) = 0 then begin
  163. Result := s;
  164. end else if Trim(LConj) = '' then begin
  165. Result := 'You will have to elaborate more for me to help you.';
  166. end else begin
  167. Result := StringReplace(s, '*', LConj, [rfReplaceAll, rfIgnoreCase]);
  168. end;
  169. end;
  170. end;
  171. function TEZEngine.TalkTo(AMsg: string): string;
  172. var
  173. LSound: string;
  174. begin
  175. Result := TalkTo(AMsg, LSound);
  176. end;
  177. end.