From 3f4753a8c66e85c804c6407a6885b6dd1ece3dfa Mon Sep 17 00:00:00 2001 From: Kirill Volinsky Date: Sun, 14 Oct 2012 09:52:45 +0000 Subject: Boltun: folders restructurization git-svn-id: http://svn.miranda-ng.org/main/trunk@1921 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/Boltun/src/Engine/COPYING.txt | 339 ++++++++++++++ plugins/Boltun/src/Engine/CriticalSection.h | 56 +++ plugins/Boltun/src/Engine/Mind.cpp | 446 +++++++++++++++++++ plugins/Boltun/src/Engine/Mind.h | 88 ++++ plugins/Boltun/src/Engine/MyCodeCvt.cpp | 81 ++++ plugins/Boltun/src/Engine/MyCodeCvt.h | 59 +++ plugins/Boltun/src/Engine/PerContactData.h | 173 ++++++++ plugins/Boltun/src/Engine/TalkEngine.cpp | 609 ++++++++++++++++++++++++++ plugins/Boltun/src/Engine/TalkEngine.h | 112 +++++ plugins/Boltun/src/Engine/UnrecentChooser.cpp | 100 +++++ plugins/Boltun/src/Engine/UnrecentChooser.h | 47 ++ plugins/Boltun/src/Engine/ValueChooser.h | 88 ++++ plugins/Boltun/src/Engine/WordsList.cpp | 169 +++++++ plugins/Boltun/src/Engine/WordsList.h | 56 +++ plugins/Boltun/src/Engine/boltun.mindw | Bin 0 -> 342176 bytes plugins/Boltun/src/Engine/tstring.h | 34 ++ 16 files changed, 2457 insertions(+) create mode 100644 plugins/Boltun/src/Engine/COPYING.txt create mode 100644 plugins/Boltun/src/Engine/CriticalSection.h create mode 100644 plugins/Boltun/src/Engine/Mind.cpp create mode 100644 plugins/Boltun/src/Engine/Mind.h create mode 100644 plugins/Boltun/src/Engine/MyCodeCvt.cpp create mode 100644 plugins/Boltun/src/Engine/MyCodeCvt.h create mode 100644 plugins/Boltun/src/Engine/PerContactData.h create mode 100644 plugins/Boltun/src/Engine/TalkEngine.cpp create mode 100644 plugins/Boltun/src/Engine/TalkEngine.h create mode 100644 plugins/Boltun/src/Engine/UnrecentChooser.cpp create mode 100644 plugins/Boltun/src/Engine/UnrecentChooser.h create mode 100644 plugins/Boltun/src/Engine/ValueChooser.h create mode 100644 plugins/Boltun/src/Engine/WordsList.cpp create mode 100644 plugins/Boltun/src/Engine/WordsList.h create mode 100644 plugins/Boltun/src/Engine/boltun.mindw create mode 100644 plugins/Boltun/src/Engine/tstring.h (limited to 'plugins/Boltun/src/Engine') diff --git a/plugins/Boltun/src/Engine/COPYING.txt b/plugins/Boltun/src/Engine/COPYING.txt new file mode 100644 index 0000000000..82fa1daad4 --- /dev/null +++ b/plugins/Boltun/src/Engine/COPYING.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/plugins/Boltun/src/Engine/CriticalSection.h b/plugins/Boltun/src/Engine/CriticalSection.h new file mode 100644 index 0000000000..59bc91beb9 --- /dev/null +++ b/plugins/Boltun/src/Engine/CriticalSection.h @@ -0,0 +1,56 @@ +//*********************************************************** +// Copyright © 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// Boltun is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Boltun. If not, see . +// +//*********************************************************** + +#ifndef CriticalSectionH +#define CriticalSectionH + +#include + +class CriticalSection +{ + CRITICAL_SECTION csQueue; +public: + inline CriticalSection() + { + InitializeCriticalSection(&csQueue); + } + + inline ~CriticalSection() + { + DeleteCriticalSection(&csQueue); + } + + inline void Enter() + { + EnterCriticalSection(&csQueue); + } + + inline void Leave() + { + LeaveCriticalSection(&csQueue); + } + + inline bool TryEnter() + { + return TryEnterCriticalSection(&csQueue) != 0; + } +}; + +#endif /* CriticalSectionH */ \ No newline at end of file diff --git a/plugins/Boltun/src/Engine/Mind.cpp b/plugins/Boltun/src/Engine/Mind.cpp new file mode 100644 index 0000000000..fc4520de55 --- /dev/null +++ b/plugins/Boltun/src/Engine/Mind.cpp @@ -0,0 +1,446 @@ +//*********************************************************** +// Copyright © 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// Boltun is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Boltun. If not, see . +// +//*********************************************************** + +#include "Mind.h" +#include +#include +#include "tstring.h" +#include "assert.h" + +#include + +#include "MyCodeCvt.h" + +using namespace std; + +typedef vector string_vec; +typedef multimap string_mmap; + +Mind::Mind() +{ + data = new MindData(); + data->referenceCount = 1; + data->maxSmileLen = 0; +} + +Mind::~Mind() +{ + if (--data->referenceCount == 0) + delete data; +} + +Mind::Mind(const Mind& mind) +{ + mind.data->referenceCount++; + data = mind.data; +} + +const MindData *Mind::GetData() const +{ + return data; +} + +Mind& Mind::operator= (const Mind& mind) +{ + if (--data->referenceCount == 0) + delete data; + mind.data->referenceCount++; + data = mind.data; + return *this; +} + +inline void format(tstring& s) +{ + int pos = (int)s.length() - 1; + if (s[pos] == _T('\r')) + s.resize(pos); +} + +void toLowerStr(TCHAR* ch) +{ + CharLower(ch); +} + +vector Mind::Parse(tstring s) +{ + int len = (int)s.length() - 1; + vector res; + while (len != -1 && _istspace(s[len])) + len--; + if (len < 0) + return res; + s.resize(len); + int it = 0; + while (it != len) + { + while (it != len && _istspace(s[it])) + it++; + if (it == len) + break; + int start = it; + while (it != len && !_istspace(s[it])) + it++; + res.push_back(s.substr(start, it - start)); + } + return res; +} + +void Mind::Load(tstring filename) +{ + basic_ifstream > file; + setlocale(LC_ALL, ""); + + locale ulocale(locale(), new MyCodeCvt); + file.imbue(ulocale); + + file.open(filename.c_str(), ios_base::in | ios_base::binary); + tstring s1, st; + TCHAR *c, *co; + size_t count; + int error = 0; + int line = 1; + + bool start = true; + + try + { + while (file.good()) + { + getline(file, st); + if (st.empty()) + break; + line++; + + if (start) + { + if (st[0] == 65279) + { + st.erase(0, 1); + fileTypeMark = true; + } + else + fileTypeMark = false; + start = false; + } + + format(st); + count = st.length(); + c = co = new TCHAR[count+1]; + _tcscpy(c, st.c_str()); + size_t pos = 0; + while (pos < count && _istspace(*c)) + { + ++pos; + ++c; + } + count -= pos; + if (count > 2) + { + switch (*c) + { + case '(': + if (c[count - 1] != ')') + abort(); + if (file.eof()) + throw error; + getline(file, s1); + line++; + format(s1); + ++c; + count -= 2; + c[count] = '\0'; + toLowerStr(c); + { + WordsList l(c); + if (!l.IsEmpty()) + if (l.IsQuestion()) + data->qkeywords.insert(make_pair(l, s1)); + else + data->keywords.insert(make_pair(l, s1)); + } + break; + case '{': + if (c[count - 1] != '}') + abort(); + if (file.eof()) + throw error; + getline(file, s1); + line++; + format(s1); + ++c; + count -= 2; + c[count] = '\0'; + toLowerStr(c); + { + WordsList l(c); + if (!l.IsEmpty()) + if (l.IsQuestion()) + data->qspecialEscapes.insert(make_pair(l, s1)); + else + data->specialEscapes.insert(make_pair(l, s1)); + } + break; + case '[': + if (c[count - 1] != ']') + throw error; + if (file.eof()) + throw error; + getline(file, s1); + line++; + format(s1); + ++c; + count -= 2; + c[count] = '\0'; + toLowerStr(c); + data->widelyUsed.insert(make_pair(c, s1)); + break; + case '<': + if (c[count - 1] != '>') + throw error; + if (file.eof()) + throw error; + getline(file, s1); + line++; + format(s1); + ++c; + count -= 2; + c[count] = '\0'; + if (_tcscmp(c,_T("QUESTION")) == 0) + { + toLowerStr(c); + data->question.insert(s1); + } + else + if (_tcscmp(c,_T("IGNORED")) == 0) + { + toLowerStr(c); + data->special.insert(s1); + } + else + if (_tcscmp(c,_T("ESCAPE")) == 0) + { + data->escape.push_back(s1); + } + else + if (_tcscmp(c,_T("FAILURE")) == 0) + { + data->failure.push_back(s1); + } + else + if (_tcscmp(c,_T("REPEAT")) == 0) + { + data->repeats.push_back(s1); + } + else + { + if (_tcscmp(c,_T("INITIAL")) != 0) + throw error; + data->initial.push_back(s1); + } + break; + case '@': + { + if (file.eof()) + throw error; + getline(file, s1); + line++; + format(s1); + ++c; + count -= 1; + toLowerStr(c); + tstring sc(c); + int count1 = (int)s1.length(); + TCHAR *c = new TCHAR[count1 + 1]; + _tcscpy(c, s1.c_str()); + CharLower(c); + s1 = c; + delete c; + vector strs = Parse(s1); + data->raliases.insert(make_pair(sc, strs)); + for (vector::const_iterator it = strs.begin(); it != strs.end(); it++) + data->aliases.insert(make_pair(*it, sc)); + } + break; + default: + if (file.eof()) + throw error; + getline(file, s1); + line++; + format(s1); + toLowerStr(c); + data->study.insert(make_pair(c, s1)); + } + } + else + if (count) + { + if (file.eof()) + throw error; + getline(file, s1); + line++; + format(s1); + data->study.insert(make_pair(c, s1)); + } + } + if (!file.eof()) + { + throw error; + } + delete co; + } + catch(...) + { + throw CorruptedMind(line); + delete co; + } +} + +void Mind::Save(tstring filename) const +{ + basic_ofstream > file; + + locale ulocale(locale(), new MyCodeCvt); + file.imbue(ulocale); + + file.open(filename.c_str(), ios_base::out | ios_base::binary); + + if (fileTypeMark) + file << TCHAR(65279); + + for (string_mmap::iterator it = data->study.begin(); it != data->study.end(); it++) + { + file << (*it).first << _T('\r') << endl; + file << (*it).second << _T('\r') << endl; + } + for (multimap::iterator it = data->keywords.begin(); it != data->keywords.end(); it++) + { + file << _T(" (") << (tstring)(*it).first << _T(")") << _T('\r') << endl; + file << (*it).second << _T('\r') << endl; + } + for (multimap::iterator it = data->qkeywords.begin(); it != data->qkeywords.end(); it++) + { + file << _T(" (") << (tstring)(*it).first << _T(")") << _T('\r') << endl; + file << (*it).second << _T('\r') << endl; + } + for (multimap::iterator it = data->specialEscapes.begin(); it != data->specialEscapes.end(); it++) + { + file << _T(" {") << (tstring)(*it).first << _T("}") << _T('\r') << endl; + file << (*it).second << _T('\r') << endl; + } + for (multimap::iterator it = data->qspecialEscapes.begin(); it != data->qspecialEscapes.end(); it++) + { + file << _T(" {") << (tstring)(*it).first << _T("}") << _T('\r') << endl; + file << (*it).second << _T('\r') << endl; + } + for (string_mmap::iterator it = data->widelyUsed.begin(); it != data->widelyUsed.end(); it++) + { + file << _T(" [") << (*it).first << _T("]") << _T('\r') << endl; + file << (*it).second << _T('\r') << endl; + } + for (set::iterator it = data->question.begin(); it != data->question.end(); it++) + { + file << _T(" ") << _T('\r') << endl; + file << (*it) << _T('\r') << endl; + } + for (set::iterator it = data->special.begin(); it != data->special.end(); it++) + { + file << _T(" ") << _T('\r') << endl; + file << (*it) << _T('\r') << endl; + } + for (string_vec::iterator it = data->escape.begin(); it != data->escape.end(); it++) + { + file << _T(" ") << _T('\r') << endl; + file << (*it) << _T('\r') << endl; + } + for (string_vec::iterator it = data->initial.begin(); it != data->initial.end(); it++) + { + file << _T(" ") << _T('\r') << endl; + file << (*it) << _T('\r') << endl; + } + for (string_vec::iterator it = data->failure.begin(); it != data->failure.end(); it++) + { + file << _T(" ") << _T('\r') << endl; + file << (*it) << _T('\r') << endl; + } + for (string_vec::iterator it = data->repeats.begin(); it != data->repeats.end(); it++) + { + file << _T(" ") << _T('\r') << endl; + file << (*it) << _T('\r') << endl; + } + for (map>::const_iterator it = data->raliases.begin(); it != data->raliases.end(); it++) + { + tstring s; + const vector& v = (*it).second; + bool first = true; + for (vector::const_iterator it1 = v.begin(); it1 != v.end(); it1++) + { + if (first) + { + first = false; + s = *it1; + } + else + { + s += _T(" ") + *it1; + } + } + file << _T('@') << (*it).first << _T('\r') << endl; + file << s << _T('\r') << endl; + } +} + +void Mind::LoadSmiles(tstring filename) +{ + basic_ifstream > file; + file.open(filename.c_str()); + data->smiles.clear(); + tstring s; + unsigned int l = 0; + while (!file.eof()) + { + getline(file, s); + if (s.length() > l) + l = (int)s.length(); + data->smiles.insert(s); + } + data->maxSmileLen = l; +} + +void Mind::LoadSmiles(void *smiles, size_t size) +{ + data->smiles.clear(); + TCHAR* buf = (TCHAR*)smiles; + unsigned l = 0; + TCHAR* end = buf + size; + while (buf != end) + { + TCHAR *lend = buf; + while (lend != end && *lend != _T('\r')) + lend++; + tstring s(buf, lend - buf); + if ((unsigned)(lend - buf) > l) + l = (int)s.length(); + data->smiles.insert(s); + if (lend == end) + break; + buf = lend + 2; + } + data->maxSmileLen = l; +} diff --git a/plugins/Boltun/src/Engine/Mind.h b/plugins/Boltun/src/Engine/Mind.h new file mode 100644 index 0000000000..23e0a41bd3 --- /dev/null +++ b/plugins/Boltun/src/Engine/Mind.h @@ -0,0 +1,88 @@ +//*********************************************************** +// Copyright © 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// Boltun is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Boltun. If not, see . +// +//*********************************************************** + +#ifndef MindH +#define MindH + +#include +#include +#include +#include +#include "WordsList.h" +#include +#include "tstring.h" + + +class Mind; + +typedef struct +{ + friend class Mind; + std::vector initial; + std::set question; + std::set special; + std::vector escape; + std::vector failure; + std::vector repeats; + unsigned int maxSmileLen; + std::set smiles; + std::multimap keywords; + std::multimap qkeywords; + std::multimap widelyUsed; + std::multimap specialEscapes; + std::multimap qspecialEscapes; + std::multimap study; + std::map aliases; + std::map> raliases; +private: + int referenceCount; +} MindData; + +class Mind +{ +private: + MindData *data; + bool fileTypeMark; + + std::vector Parse(tstring s); +public: + Mind(); + ~Mind(); + Mind(const Mind& mind); + Mind& operator= (const Mind& mind); + + class CorruptedMind + { + public: + int line; + CorruptedMind(int aline) + : line(aline) + { + }; + }; + + const MindData *GetData() const; + void Load(tstring filename); + void Save(tstring filename) const; + void LoadSmiles(tstring filename); + void LoadSmiles(void* smiles, size_t size); +}; + +#endif diff --git a/plugins/Boltun/src/Engine/MyCodeCvt.cpp b/plugins/Boltun/src/Engine/MyCodeCvt.cpp new file mode 100644 index 0000000000..5d7baf4d88 --- /dev/null +++ b/plugins/Boltun/src/Engine/MyCodeCvt.cpp @@ -0,0 +1,81 @@ +//*********************************************************** +// Copyright © 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// Boltun is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Boltun. If not, see . +// +//*********************************************************** + +#include "MyCodeCvt.h" + +using namespace std; + +MyCodeCvt::MyCodeCvt(size_t _R) + : MyCodeCvtBase(_R) +{ +} + +MyCodeCvt::result MyCodeCvt::do_in(_St& _State , + const _To* _F1, const _To* _L1, const _To*& _Mid1, + _E* F2, _E* _L2, _E*& _Mid2) const +{ + return noconv; +} + +#ifdef MSVC +MyCodeCvt::result MyCodeCvt::do_out(_St& _State, + const _E* _F1, const _E* _L1, const _E*& _Mid1, + _To* F2, _E* _L2, _To*& _Mid2) const +#else +MyCodeCvt::result MyCodeCvt::do_out(_St& _State, + const _E* _F1, const _E* _L1, const _E*& _Mid1, + _To* F2, _To* _L2, _To*& _Mid2) const +#endif +{ + return noconv; +} + +MyCodeCvt::result MyCodeCvt::do_unshift( _St& _State, + _To* _F2, _To* _L2, _To*& _Mid2) const +{ + return noconv; +} + +#ifdef MSVC +int MyCodeCvt::do_length(_St& _State, const _To* _F1, + const _To* _L1, size_t _N2) const _THROW0() +#else +int MyCodeCvt::do_length(const _St& _State, const _To* _F1, + const _To* _L1, size_t _N2) const _THROW0() +#endif + +{ + return (_N2 < (size_t)(_L1 - _F1)) ? (int)_N2 : (int)(_L1 - _F1); +} + +bool MyCodeCvt::do_always_noconv() const _THROW0() +{ + return true; +} + +int MyCodeCvt::do_max_length() const _THROW0() +{ + return 2; +} + +int MyCodeCvt::do_encoding() const _THROW0() +{ + return 2; +} diff --git a/plugins/Boltun/src/Engine/MyCodeCvt.h b/plugins/Boltun/src/Engine/MyCodeCvt.h new file mode 100644 index 0000000000..b4508c66de --- /dev/null +++ b/plugins/Boltun/src/Engine/MyCodeCvt.h @@ -0,0 +1,59 @@ +//*********************************************************** +// Copyright © 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// Boltun is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Boltun. If not, see . +// +//*********************************************************** + +#ifndef MYCODECVT_H +#define MYCODECVT_H + +#include +#include +#include + +typedef std::codecvt MyCodeCvtBase; + +class MyCodeCvt + : public MyCodeCvtBase +{ +public: + typedef wchar_t _E; + typedef char _To; + typedef std::mbstate_t _St; + explicit MyCodeCvt( size_t _R=0 ); +protected: + virtual result do_in(_St& _State, const _To* _F1, const _To* _L1, const _To*& _Mid1, + _E* F2 , _E* _L2 , _E*& _Mid2) const; +#ifdef MSVC + virtual result do_out(_St& _State, const _E* _F1, const _E* _L1, const _E*& _Mid1, + _To* F2, _E* _L2 , _To*& _Mid2) const; +#else + virtual result do_out(_St& _State, const _E* _F1, const _E* _L1, const _E*& _Mid1, + _To* F2, _To* _L2 , _To*& _Mid2) const; +#endif + virtual result do_unshift(_St& _State, _To* _F2, _To* _L2, _To*& _Mid2) const; +#ifdef MSVC + virtual int do_length(_St& _State, const _To* _F1, const _To* _L1, size_t _N2) const _THROW0(); +#else + virtual int do_length(const _St& _State, const _To* _F1, const _To* _L1, size_t _N2) const _THROW0(); +#endif + virtual bool do_always_noconv() const _THROW0(); + virtual int do_max_length() const _THROW0(); + virtual int do_encoding() const _THROW0(); +} ; + +#endif /* MYCODECVT_H */ \ No newline at end of file diff --git a/plugins/Boltun/src/Engine/PerContactData.h b/plugins/Boltun/src/Engine/PerContactData.h new file mode 100644 index 0000000000..14b17784b9 --- /dev/null +++ b/plugins/Boltun/src/Engine/PerContactData.h @@ -0,0 +1,173 @@ +//*********************************************************** +// Copyright © 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// Boltun is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Boltun. If not, see . +// +//*********************************************************** + +#ifndef PerContactDataH +#define PerContactDataH + +#include +#include +#include + +#include "CriticalSection.h" + +static std::map perContactDataObjects; + +template +class PerContactData +{ + template + struct InternalData + { + CriticalSection lock; + Data *data; + time_t time; + inline InternalData(const Source& src) + :time(0) + { + data = new Data(src); + } + + inline InternalData() + :data(NULL) + { + assert(false); + } + + inline ~InternalData() + { + delete data; + } + }; + CriticalSection mapLock; + unsigned timerID; + std::map* > datas; + typedef typename std::map* >::iterator mapIt; + const Source& source; + void CleanupData(); + template + friend VOID CALLBACK RunTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime); +public: + PerContactData(const Source& src); + ~PerContactData(); + Data* GetData(ContactHandle Contact); + void PutData(ContactHandle Contact); +}; + +template +PerContactData::PerContactData(const Source& src) + :source(src), timerID(0) +{ +} + +template +PerContactData::~PerContactData() +{ + mapLock.Enter(); + if (timerID) + { + KillTimer(NULL, timerID); + perContactDataObjects.erase(timerID); + } + while (!datas.empty()) + { + while (!(*datas.begin()).second->lock.TryEnter()) + { + mapLock.Leave(); + Sleep(10); + mapLock.Enter(); + } + //Now we know exactly that no-one onws a contact lock + InternalData* data = (*datas.begin()).second; + data->lock.Leave(); + delete data; + datas.erase(datas.begin()); + } + mapLock.Leave(); +} + +template +Data* PerContactData::GetData(ContactHandle Contact) +{ + mapLock.Enter(); + mapIt it; + if ((it = datas.find(Contact)) == datas.end()) + it = datas.insert(make_pair(Contact, new InternalData(source))).first; + (*it).second->lock.Enter(); + (*it).second->time = 0; + Data* data = (*it).second->data; + mapLock.Leave(); + return data; +} + +template +void PerContactData::PutData(ContactHandle Contact) +{ + mapLock.Enter(); + datas[Contact]->lock.Leave(); + ::time(&(datas[Contact]->time)); + if (!timerID) + { + timerID = SetTimer(NULL, 0, 30000, RunTimerProc); + assert(timerID); + perContactDataObjects[timerID] = this; + } + mapLock.Leave(); +} + +template +void PerContactData::CleanupData() +{ + mapLock.Enter(); + time_t now; + time(&now); + for (mapIt it = datas.begin(); it != datas.end(); ) + { + if ((*it).second->time) //it's being in use + { + int diff = (int)difftime(now, (*it).second->time); + if (diff >= 30*60) //half of an hour + { + mapIt tmp = it; + it++; + delete (*tmp).second; + datas.erase(tmp); + } + else + it++; + } + else + it++; + } + if (timerID && datas.empty()) //timerID may become NULL before locking, so should check + { + KillTimer(NULL, timerID); + perContactDataObjects.erase(timerID); + } + mapLock.Leave(); +} + +template +VOID CALLBACK RunTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + PerContactData* val = (PerContactData*)perContactDataObjects[idEvent]; + val->CleanupData(); +} + +#endif /* PerContactDataH */ \ No newline at end of file diff --git a/plugins/Boltun/src/Engine/TalkEngine.cpp b/plugins/Boltun/src/Engine/TalkEngine.cpp new file mode 100644 index 0000000000..550aac66cf --- /dev/null +++ b/plugins/Boltun/src/Engine/TalkEngine.cpp @@ -0,0 +1,609 @@ +//*********************************************************** +// Copyright © 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// Boltun is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Boltun. If not, see . +// +//*********************************************************** + +#include "TalkEngine.h" +#include +#include + +#ifdef _DEBUG + +//#define DEBUG_PREFIXES +//#define DEBUG_SHOW_LEVEL +//#define DEBUG_SHOW_VARIANTS +//#define DEBUG_SHOW_SOLUTION_REASON + +#endif + +//Enabling next define will make a bot more stupid: +//#define EXCLUDE_SPECIAL_WORDS + +#ifdef DEBUG_SHOW_VARIANTS +extern void AddBotMessage(tstring s); +#endif + +using namespace std; + +void TalkBot::UpdateStartChar(tstring& str) +{ + if (!makeLowercase) + return; + size_t l = str.length(); + if (l) + { + //Answers starting with ' ' must remain unchanged. + if (str[0] == _T(' ')) + { + str = str.substr(1); + return; + } + for (size_t i = 0; i < l; i++) + { + TCHAR cl = (TCHAR)CharLower((LPTSTR)(void*)(long)str[i]); + TCHAR cu = (TCHAR)CharUpper((LPTSTR)(void*)(long)str[i]); + if (i != l - 1) + { + //Do not react to BLONDE ANSWERS + TCHAR ncl = (TCHAR)CharLower((LPTSTR)(void*)(long)str[i + 1]); + TCHAR ncu = (TCHAR)CharUpper((LPTSTR)(void*)(long)str[i + 1]); + if (ncl != ncu && str[i + 1] == ncu) + break; + } + if (cl != cu) + { + str[i] = cl; + break; + } + } + } +} + +TalkBot::TalkBot(const Mind& goodMind) + :mind(goodMind), beSilent(false), makeLowercase(false), + understandAlways(false) +{ + contactDatas = new PerContactData(mind); +} + +TalkBot::~TalkBot() +{ + delete contactDatas; +} + +tstring TalkBot::GetInitMessage(void* contact) +{ + ContactData* d = contactDatas->GetData(contact); + tstring s = d->initial.GetString(); + contactDatas->PutData(contact); + return s; +} + +tstring TalkBot::ReplaceAliases(const tstring &message) +{ + const TCHAR dividers[] = _T(" \t\n\r,./?\\|;:'\"~!#^&*()_-+=[{]}—\1"); + tstring sentence = message; + tstring result; + int len = (int)sentence.length(); + vector words; + map sm; + //Find smiles + for (size_t i = 0; i < sentence.length() - 1; i++) + { + unsigned max = (int)(sentence.length() - i); + if (max > mind.GetData()->maxSmileLen) + max = mind.GetData()->maxSmileLen; + for (unsigned j = max; j > 0; j--) + { + tstring item = sentence.substr(i, j); + if (mind.GetData()->smiles.find(item) + != mind.GetData()->smiles.end()) + { + sm[i] = item; + sentence.replace(i, j, _T("\1")); + break; + } + } + } + len = (int)sentence.length(); + bool hadQuestionSigns = false; + int it = 0; + while (it != len) + { + while (it != len && _tcschr(dividers, sentence[it])) + { + if (sentence[it] == _T('?')) + hadQuestionSigns = true; + map::iterator smit; + if (sentence[it] == '\1') + { + smit = sm.find(it); + result.append((*smit).second); + } + else + result.push_back(sentence[it]); + it++; + } + if (it == len) + break; + int start = it; + while (true) + { + while (it != len && !_tcschr(dividers, sentence[it])) + it++; + if (it == len || sentence[it] != _T('-')) + break; + //If we have-a-word-with-minus, we shouldn't split it + if (_tcschr(dividers, sentence[it + 1])) + break; + it += 2; + } + tstring str = sentence.substr(start, it - start); + map::const_iterator al = mind.GetData()->aliases.find(str); + if (al != mind.GetData()->aliases.end()) + result.append((*al).second); + else + result.append(str); + } + return result; +} + +tstring TalkBot::AllReplies(const tstring &incomingMessage, ContactData* contactData, Level &maxValue, std::multimap &mm) +{ + tstring res; + //Part 1 + if (FindExact(contactData, incomingMessage, mind.GetData()->widelyUsed, res)) //widelyUsed + { + return res; + } + //Part 2 + if (FindExact(contactData, incomingMessage, mind.GetData()->study, res)) //study + { +#ifdef DEBUG_PREFIXES + mm.insert(make_pair(LOOKSLIKE, _T("(study_all) ")+res)); +#else + mm.insert(make_pair(LOOKSLIKE, res)); +#endif + maxValue = LOOKSLIKE; + } + //Part 3 + vector sentences; + SplitSectences(incomingMessage, sentences); + ValueChooser<> ch(sentences, true); //Using random order of sentences. + while ((res = ch.GetString()) != _T("")) + { + //Part 4 + if (FindExact(contactData, res, mind.GetData()->widelyUsed, res)) //widelyUsed + { +#ifdef DEBUG_PREFIXES + mm.insert(make_pair(BEST, _T("(widelyused_sent) ")+res)); +#else + mm.insert(make_pair(BEST, res)); +#endif + if (maxValue > BEST) + maxValue = BEST; + } + //Part 5 + if (FindExact(contactData, res, mind.GetData()->study, res)) //study + { +#ifdef DEBUG_PREFIXES + mm.insert(make_pair(LOOKSLIKE, _T("(study_sent) ")+res)); +#else + mm.insert(make_pair(LOOKSLIKE, res)); +#endif + if (maxValue > LOOKSLIKE) + maxValue = LOOKSLIKE; + } + //Part 6 + vector keywords, otherwords; + bool isQuestion; + SplitAndSortWords(res, keywords, otherwords, isQuestion); + //Part 7, 8 + res = _T(""); + FindByKeywords(contactData, keywords, res/*, ures*/, isQuestion); //keywords + if (res != _T("")) + { +#ifdef DEBUG_PREFIXES + mm.insert(make_pair(LOOKSLIKE, _T("(keywords) ")+res)); +#else + mm.insert(make_pair(LOOKSLIKE, res)); +#endif + if (maxValue > LOOKSLIKE) + maxValue = LOOKSLIKE; + } +/* if (ures != _T("")) + { +#ifdef DEBUG_PREFIXES + mm.insert(make_pair(LOOKSLIKE2, _T("(keywords_unstrict) ")+ures)); +#else + mm.insert(make_pair(LOOKSLIKE2, ures)); +#endif + if (maxValue > LOOKSLIKE2) + maxValue = LOOKSLIKE2; + }*/ + //Part 9 + if (FindByOthers(contactData, otherwords, res, isQuestion)) //specialEscapes + { +#ifdef DEBUG_PREFIXES + mm.insert(make_pair(BAD, _T("(otherwords) ")+res)); +#else + mm.insert(make_pair(BAD, res)); +#endif + if (maxValue > BAD) + maxValue = BAD; + } + } + if (!beSilent) + { + //Part 10 + if (FindAny(contactData->escape, res)) //escape + { +#ifdef DEBUG_PREFIXES + mm.insert(make_pair(FAIL, _T("(escape) ") + res)); +#else + mm.insert(make_pair(FAIL, res)); +#endif + if (maxValue > FAIL) + maxValue = FAIL; + } + //Part 11 + if (!understandAlways && FindAny(contactData->failure, res)) //failure + { +#ifdef DEBUG_PREFIXES + mm.insert(make_pair(FAIL, _T("(failure) ") + res)); +#else + mm.insert(make_pair(FAIL, res)); +#endif + if (maxValue > FAIL) + maxValue = FAIL; + } + } + return tstring(); +} + +TalkBot::MessageInfo* TalkBot::Reply(void* contact, tstring incomingMessage, bool saveChoice) +{ + TCHAR* str = new TCHAR[incomingMessage.length()+1]; + _tcscpy(str, incomingMessage.c_str()); + CharLower(str); + incomingMessage = str; + delete str; + ContactData* contactData = contactDatas->GetData(contact); + + if (incomingMessage == contactData->lastMessage && GetTickCount() < contactData->lastMessageTime + 30*60*1000) + { + MessageInfo *info; + //only 2-3 repeats + if (contactData->repeatCount < 2 || contactData->repeatCount == 2 && (rand() % 2)) + { + const vector& v = mind.GetData()->repeats; + tstring res = v[rand() % v.size()]; +#ifdef DEBUG_PREFIXES + info = new MessageInfo(incomingMessage, _T("(repeat_norm) ") + res); +#else + info = new MessageInfo(incomingMessage, res); +#endif + } + else +#ifdef DEBUG_PREFIXES + info = new MessageInfo(incomingMessage, _T("(repeat_silence)")); +#else + info = new MessageInfo(incomingMessage, _T("")); +#endif + if (saveChoice) + RecordAnswer(contactData, *info); + contactDatas->PutData(contact); + return info; + } + + multimap mm; + Level maxValue = NOTHING; + + tstring res = AllReplies(incomingMessage, contactData, maxValue, mm); + if (!res.empty()) + { + UpdateStartChar(res); +#ifdef DEBUG_PREFIXES + MessageInfo *info = new MessageInfo(incomingMessage, _T("(widelyused_all) ") + res); +#else + MessageInfo *info = new MessageInfo(incomingMessage, res); +#endif + if (saveChoice) + RecordAnswer(contactData, *info); + contactDatas->PutData(contact); + return info; + } + + incomingMessage = ReplaceAliases(incomingMessage); + + res = AllReplies(incomingMessage, contactData, maxValue, mm); + if (!res.empty()) + { + UpdateStartChar(res); +#ifdef DEBUG_PREFIXES + MessageInfo *info = new MessageInfo(incomingMessage, _T("(widelyused_all) ") + res); +#else + MessageInfo *info = new MessageInfo(incomingMessage, res); +#endif + if (saveChoice) + RecordAnswer(contactData, *info); + contactDatas->PutData(contact); + return info; + } + + //Also does Part 12 + tstring final = ChooseResult(contactData, maxValue, mm); + MessageInfo *info = new MessageInfo(incomingMessage, final); + UpdateStartChar(final); + if (saveChoice) + RecordAnswer(contactData, *info); + contactDatas->PutData(contact); + return info; +} + +bool TalkBot::FindExact(ContactData* contactData, const tstring &incomingMessage, + const multimap& map, tstring& res) +{ + int max = (int)map.count(incomingMessage); + if (!max) + { + TCHAR c = incomingMessage[incomingMessage.length() - 1]; + if (c != _T('?') && c != _T('.') && c != _T('!')) + return FindExact(contactData, incomingMessage + _T('.'), map, res); + return false; + } + pair range = map.equal_range(incomingMessage); + for (mm_cit it = range.first; it != range.second; it++) + contactData->chooser.AddChoice((*it).second); + res = contactData->chooser.Choose(); + return true; +} + +void TalkBot::AnswerGiven(void* contact, const TalkBot::MessageInfo& info) +{ + ContactData* contactData = contactDatas->GetData(contact); + RecordAnswer(contactData, info); + contactDatas->PutData(contact); +} + +void TalkBot::RecordAnswer(ContactData *contactData, const TalkBot::MessageInfo& info) +{ + contactData->chooser.SaveChoice(info.Answer); + if (contactData->lastMessage == info.Question) + contactData->repeatCount++; + else + contactData->repeatCount = 0; + contactData->lastMessageTime = GetTickCount(); + contactData->lastMessage = info.Question; +} + +bool TalkBot::FindAny(ValueChooser<> &ch, tstring& res) +{ + if (!ch.GetContainer().size()) + return false; + res = ch.GetString(); + return true; +} + +void TalkBot::SplitSectences(const tstring &incomingMessage, vector& vec) +{ + //FIXME: (THINK ABOUT IT:-))these chars not always mark the end of sentence. + const TCHAR symbols[] = _T(".?!"); + int it = 0, len = (int)incomingMessage.length(); + while (it != len) + { + while (it != len && _istspace(incomingMessage[it])) + it++; + int start = it; + while (it != len) + { + if (_tcschr(symbols, incomingMessage[it++])) + { + //Test for a :-! smile + if (it > 2 && incomingMessage[it-1] == _T('!') + && incomingMessage[it-2] == _T('-') + && incomingMessage[it-3] == _T(':')) + continue; + while (it != len && _tcschr(symbols, incomingMessage[it])) + it++; + break; + } + } + vec.insert(vec.end(), incomingMessage.substr(start, it - start)); + } +} + +#ifdef _DEBUG +tstring LevelToStr(TalkBot::Level target) +{ + tstring lev; + switch (target) + { + case TalkBot::BEST: lev = _T("BEST(0)"); break; + case TalkBot::LOOKSLIKE: lev = _T("LOOKSLIKE(1)"); break; + case TalkBot::BAD: lev = _T("BAD(2)"); break; + case TalkBot::FAIL: lev = _T("FAIL(3)"); break; + case TalkBot::NOTHING: lev = _T("NOTHING(4)"); break; + } + return lev; +} +#endif + +tstring TalkBot::ChooseResult(ContactData* contactData, Level maxValue, const multimap &mm) +{ +#ifdef DEBUG_SHOW_VARIANTS + AddBotMessage(_T(">>Availabe:")); + for (multimap::iterator it = mm.begin(); it != mm.end(); it++) + AddBotMessage(LevelToStr((*it).first) + _T(": ") + (*it).second); + AddBotMessage(_T(">>Result:")); +#endif + if (maxValue == NOTHING) + return _T(""); + Level target = maxValue; + int num = (int)mm.count(target); +/* if (!num) + { + target = maxValue; + num = mm.count(target); + }*/ + typedef multimap::const_iterator lt_cit; + pair range = mm.equal_range(target); + for (lt_cit it = range.first; it != range.second; it++) + contactData->chooser.AddChoice((*it).second); +#ifdef DEBUG_SHOW_LEVEL + tstring lev = LevelToStr(target); + return lev + _T(": ") + contactData->chooser.Choose(); +#else + return contactData->chooser.Choose(); +#endif +} + +void TalkBot::FindByKeywords(ContactData* contactData, const vector &keywords, tstring& res/*, tstring& ures*/, + bool isQuestion) +{ + if (keywords.size() == 0) + return; + const multimap &keys = isQuestion ? mind.GetData()->qkeywords : + mind.GetData()->keywords; + for (multimap::const_iterator it = keys.begin(); it != keys.end(); it++) + { + float prio; + if ((*it).first.MatchesAll(keywords/*, strict*/, prio)) +#ifdef DEBUG_SHOW_SOLUTION_REASON + contactData->chooser.AddChoice((tstring)(*it).first + _T(": - ") + (*it).second, prio); +#else + contactData->chooser.AddChoice((*it).second, prio); +#endif + } + res = contactData->chooser.Choose(); +} + +bool TalkBot::FindByOthers(ContactData* contactData, const vector &otherwords, tstring& res, bool isQuestion) +{ + //vector results; + const multimap &specs = isQuestion ? mind.GetData()->qspecialEscapes : + mind.GetData()->specialEscapes; + for (multimap::const_iterator it = specs.begin(); + it != specs.end(); it++) + if ((*it).first.MatchesAny(otherwords)) + { +#ifdef DEBUG_SHOW_SOLUTION_REASON + contactData->chooser.AddChoice((tstring)(*it).first + _T(": - ") + (*it).second); +#else + contactData->chooser.AddChoice((*it).second); +#endif + } + res = contactData->chooser.Choose(); + if (res.empty()) + return false; + return true; +} + +const Mind& TalkBot::GetMind() const +{ + return mind; +} + +void TalkBot::SplitAndSortWords(tstring sentence, vector& keywords, + vector& otherwords, bool& isQuestion) +{ + const TCHAR dividers[] = _T(" \t\n\r,./?\\|;:'\"~!#^&*()_-+=[{]}—"); + int len = (int)sentence.length(); + vector words; + map sm; + //Find smiles + for (size_t i = 0; i < sentence.length() - 1; i++) + { + unsigned max = (int)(sentence.length() - i); + if (max > mind.GetData()->maxSmileLen) + max = mind.GetData()->maxSmileLen; + for (unsigned j = max; j > 0; j--) + { + tstring item = sentence.substr(i, j); + if (mind.GetData()->smiles.find(item) + != mind.GetData()->smiles.end()) + { + sm[i] = item; + sentence.replace(i, j, _T(" ")); + break; + } + } + } + len = (int)sentence.length(); + bool hadQuestionSigns = false; + int it = 0; + while (it != len) + { + while (it != len && _tcschr(dividers, sentence[it])) + { + if (sentence[it] == _T('?')) + hadQuestionSigns = true; + map::iterator smit; + if (_istspace(sentence[it]) && (smit = sm.find(it)) != sm.end()) + words.push_back((*smit).second); + it++; + } + if (it == len) + break; + hadQuestionSigns = false; + int start = it; + while (true) + { + while (it != len && !_tcschr(dividers, sentence[it])) + it++; + if (it == len || sentence[it] != _T('-')) + break; + //If we have-a-word-with-minus, we shouldn't split it + if (_tcschr(dividers, sentence[it + 1])) + break; + it += 2; + } + tstring str = sentence.substr(start, it - start); + words.push_back(str); + } + isQuestion = hadQuestionSigns; + for (vector::iterator it = words.begin(); it != words.end(); it++) + { + if (!isQuestion) + { + if (mind.GetData()->question.find(*it) != mind.GetData()->question.end()) + isQuestion = true; + } + if (mind.GetData()->special.find(*it) != mind.GetData()->special.end()) + otherwords.push_back(*it); +#ifdef EXCLUDE_SPECIAL_WORDS + else +#endif + keywords.push_back(*it); + } +} + +void TalkBot::SetSilent(const bool isSilent) +{ + beSilent = isSilent; +} + +void TalkBot::SetLowercase(const bool isLowercase) +{ + makeLowercase = isLowercase; +} + +void TalkBot::SetUnderstandAlways(const bool understandAlways) +{ + this->understandAlways = understandAlways; +} \ No newline at end of file diff --git a/plugins/Boltun/src/Engine/TalkEngine.h b/plugins/Boltun/src/Engine/TalkEngine.h new file mode 100644 index 0000000000..364f4193d1 --- /dev/null +++ b/plugins/Boltun/src/Engine/TalkEngine.h @@ -0,0 +1,112 @@ +//*********************************************************** +// Copyright © 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// Boltun is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Boltun. If not, see . +// +//*********************************************************** + +#ifndef TalkEngineH +#define TalkEngineH + +#include "Mind.h" +#include "ValueChooser.h" +#include "PerContactData.h" +#include "UnrecentChooser.h" + +class TalkBot +{ +public: + struct MessageInfo + { + private: + tstring Question; + MessageInfo(tstring q, tstring a) + :Question(q), Answer(a) + { + } + public: + tstring Answer; + MessageInfo(tstring q) + :Question(q) + { + } + friend class TalkBot; + }; +private: + typedef enum + { + BEST, LOOKSLIKE/*, LOOKSLIKE2*/, BAD, FAIL, NOTHING + } Level; + friend tstring LevelToStr(TalkBot::Level target); + + struct ContactData + { + ValueChooser<> initial; + //ValueChooser > question; + //ValueChooser > special; + ValueChooser<> escape; + ValueChooser<> failure; + UnRecentChooser chooser; + tstring lastMessage; + long long lastMessageTime; + int repeatCount; + inline ContactData(const Mind& mind) + :initial(mind.GetData()->initial), + //question(mind.GetData()->question), + //special(mind.GetData()->special), + escape(mind.GetData()->escape), + failure(mind.GetData()->failure), + repeatCount(0) + { + } + }; + + PerContactData* contactDatas; + const Mind mind; + bool beSilent; + bool makeLowercase; + bool understandAlways; + void UpdateStartChar(tstring& str); + typedef std::multimap::const_iterator mm_cit; + bool FindExact(ContactData* contactData, const tstring &incomingMessage, + const std::multimap& map, tstring& res); + bool FindAny(ValueChooser<> &ch, tstring& res); + void FindByKeywords(ContactData* contactData, const std::vector &keywords, tstring& res/*, tstring& ures*/, bool isQuestion); + bool FindByOthers(ContactData* contactData, const std::vector &otherwords, tstring& res, bool isQuestion); + tstring AllReplies(const tstring &incomingMessage, ContactData* contactData, Level &maxValue, std::multimap &mm); + tstring ReplaceAliases(const tstring &message); + tstring ChooseResult(ContactData* contactData, Level maxValue, const std::multimap &mm); + void RecordAnswer(ContactData *contactData, const TalkBot::MessageInfo& info); +#ifdef _DEBUG +public: +#endif + void SplitSectences(const tstring &incomingMessage, std::vector& vec); + void SplitAndSortWords(tstring sentence, std::vector& keywords, + std::vector& otherwords, bool& isQuestion); +public: + TalkBot(const Mind& goodMind); + ~TalkBot(); + const Mind& GetMind() const; + void SetSilent(const bool isSilent); + void SetLowercase(const bool isLowercase); + void SetUnderstandAlways(const bool understandAlways); + //const MindData *GetData(); + tstring GetInitMessage(void* contact); + MessageInfo* Reply(void* contact, const tstring incomingMessage, bool saveChoice); + void AnswerGiven(void* contact, const MessageInfo& info); +}; + +#endif diff --git a/plugins/Boltun/src/Engine/UnrecentChooser.cpp b/plugins/Boltun/src/Engine/UnrecentChooser.cpp new file mode 100644 index 0000000000..b2e5303f5a --- /dev/null +++ b/plugins/Boltun/src/Engine/UnrecentChooser.cpp @@ -0,0 +1,100 @@ +//*********************************************************** +// Copyright © 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// Boltun is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Boltun. If not, see . +// +//*********************************************************** + +#include "UnrecentChooser.h" + +using namespace std; + +UnRecentChooser::UnRecentChooser() + :last(-1), min(-1), newItemsPrio(-1), maxOldPrio(-1) +{ +} + +void UnRecentChooser::AddChoice(tstring value, float prio) +{ + if (items.count(value) != 0) + { + int val = (int)items[value]; + oldItems.insert(make_pair(val, value)); + oldPrios.insert(make_pair(value, prio)); + if (min > val || min == -1) + min = val; + if (maxOldPrio < prio) + maxOldPrio = prio; + } + else + { + if (prio > newItemsPrio) + { + newItems.push_back(value); + newItemsPrio = prio; + } + } +} + +tstring UnRecentChooser::Choose() +{ + tstring res; + //Find answer + if (newItemsPrio != -1) + { + int num = rand() % newItems.size(); + res = newItems[num]; + } + else + if (min == -1) + res = _T(""); + else + { + float minprio = maxOldPrio / 1.5F; + while (oldPrios[oldItems[min]] < minprio) + min++; + res = oldItems[min]; + } + //Clean items + min = -1; + newItemsPrio = -1; + maxOldPrio = -1; + oldItems.clear(); + oldPrios.clear(); + newItems.clear(); + return res; +} + +void UnRecentChooser::SaveChoice(tstring choice) +{ + //Add answer + if (items.find(choice) != items.end()) + { + for (vector::iterator it = itemsList.begin(); it != itemsList.end(); it++) + if (*it == choice) + { + itemsList.erase(it); + break; + } + } + items[choice] = ++last; + itemsList.push_back(choice); + if (itemsList.size() > maxItems) + { + items.erase(*itemsList.begin()); + itemsList.erase(itemsList.begin()); + } +} \ No newline at end of file diff --git a/plugins/Boltun/src/Engine/UnrecentChooser.h b/plugins/Boltun/src/Engine/UnrecentChooser.h new file mode 100644 index 0000000000..91a961e307 --- /dev/null +++ b/plugins/Boltun/src/Engine/UnrecentChooser.h @@ -0,0 +1,47 @@ +//*********************************************************** +// Copyright © 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// Boltun is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Boltun. If not, see . +// +//*********************************************************** + +#ifndef UnRecentChooserH +#define UnRecentChooserH + +#include +#include +#include +#include "tstring.h" + +class UnRecentChooser +{ + std::map items; + std::vector itemsList; + std::vector newItems; + float newItemsPrio, maxOldPrio; + std::map oldItems; + std::map oldPrios; + size_t last; + int min; + static const size_t maxItems = 100; +public: + UnRecentChooser(); + void AddChoice(tstring value, float prio = 1.0); + tstring Choose(); + void SaveChoice(tstring choice); +}; + +#endif /* UnRecentChooserH */ \ No newline at end of file diff --git a/plugins/Boltun/src/Engine/ValueChooser.h b/plugins/Boltun/src/Engine/ValueChooser.h new file mode 100644 index 0000000000..219a55a8f2 --- /dev/null +++ b/plugins/Boltun/src/Engine/ValueChooser.h @@ -0,0 +1,88 @@ +//*********************************************************** +// Copyright © 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// Boltun is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Boltun. If not, see . +// +//*********************************************************** + +#ifndef StringChooserH +#define StringChooserH + +#include +#include + +template > +class ValueChooser +{ +private: + int freeNumbers; + bool *numbers; + const container data; + bool notifyOnReset; +public: + ValueChooser(const container& vec, bool NotifyOnReset = false) + :data(vec), notifyOnReset(NotifyOnReset) + { + //randomize(); + numbers = NULL; + UpdateLength(); + } + + ~ValueChooser() + { + delete numbers; + } + + void UpdateLength() + { + delete numbers; //normal if numbers == NULL + numbers = new bool[data.size()]; + Reset(); + } + + void Reset() + { + for (size_t i = 0; i < data.size(); i++) + numbers[i] = false; + freeNumbers = (int)data.size(); + } + + typename container::value_type GetString() + { + if (!freeNumbers) + { + Reset(); + if (notifyOnReset) + return _T(""); + } + int result; + while (numbers[result = rand() % data.size()]) + ; + freeNumbers--; + numbers[result] = true; + return data[result]; + } + + container GetContainer() const; +}; + +template +container ValueChooser::GetContainer() const +{ + return data; +} + +#endif diff --git a/plugins/Boltun/src/Engine/WordsList.cpp b/plugins/Boltun/src/Engine/WordsList.cpp new file mode 100644 index 0000000000..3209bf2db6 --- /dev/null +++ b/plugins/Boltun/src/Engine/WordsList.cpp @@ -0,0 +1,169 @@ +//*********************************************************** +// Copyright © 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// Boltun is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Boltun. If not, see . +// +//*********************************************************** + +#include "WordsList.h" + +using namespace std; + +WordsList::WordsList(const tstring &data/*, bool allowUnstrict*/) +{ + Parse(data/*, allowUnstrict*/); +} + +WordsList::operator tstring() const +{ + tstring res; + //if (unstrict) + // res = _T("~"); + set::const_iterator it = words.begin(); + if (!words.empty()) + while (true) + { + res += *it; + it++; + if (it != words.end()) + res += _T(" "); + else + break; + } + res += isQuestion ? _T("?") : _T("."); + return res; +} + +WordsList& WordsList::operator= (const tstring& s) +{ + Parse(s); + return *this; +}; + +void WordsList::Parse(tstring s/*, bool allowUnstrict*/) +{ + isQuestion = false; + /*if (allowUnstrict && s.length() && s[0] == _T('~')) + { + s = s.substr(1, s.npos); + unstrict = true; + } + else + unstrict = false;*/ + int len = (int)s.length() - 1; + while (len != -1 && _istspace(s[len])) + len--; + if (len < 0) + return; + if (s[len] == '?') + isQuestion = true; + else + if (s[len] != '.') + return; + s.resize(len); + int it = 0; + while (it != len) + { + while (it != len && _istspace(s[it])) + it++; + if (it == len) + break; + int start = it; + while (it != len && !_istspace(s[it])) + it++; + words.insert(s.substr(start, it - start)); + } +} + +bool WordsList::MatchesAll(const vector& s/*, bool& WasStrict*/, float& priority) const +{ + std::set temp; + //WasStrict = true; + for (vector::const_iterator it = s.begin(); it != s.end(); it++) + { +/* if (words.find(*it) == words.end()) + if (unstrict) + { + WasStrict = false; + continue; + } + else + return false; + temp.insert((*it));*/ + if (words.find(*it) != words.end()) + temp.insert((*it)); + } + if (temp.size() != words.size()) + return false; + priority = words.size() * words.size() / (float)s.size(); + return temp.size() == words.size(); +} + +bool WordsList::MatchesAny(const vector& s) const +{ + for (vector::const_iterator it = s.begin(); it != s.end(); it++) + if (words.find(*it) != words.end()) + return true; + return false; +} + +vector WordsList::ConsistsOf(const set& list) const +{ + vector res; + for (set::const_iterator it = words.begin(); it != words.end(); it++) + if (list.find(*it) == list.end()) + res.push_back(*it); + return res; +} + +vector WordsList::DoesntIncludeAny(const set& list) const +{ + vector res; + for (set::const_iterator it = words.begin(); it != words.end(); it++) + if (list.find(*it) != list.end()) + res.push_back(*it); + return res; +} + +bool WordsList::operator<(const WordsList& value) const +{ + return (tstring)*this < (tstring)value; +} + +bool WordsList::operator!=(const WordsList& value) const +{ + return (tstring)*this != (tstring)value; +} + +bool WordsList::operator==(const WordsList& value) const +{ + return (tstring)*this == (tstring)value; +} + +size_t WordsList::Size() const +{ + return words.size(); +} + +bool WordsList::IsQuestion() const +{ + return isQuestion; +} + +bool WordsList::IsEmpty() const +{ + return words.size() == 0; +} \ No newline at end of file diff --git a/plugins/Boltun/src/Engine/WordsList.h b/plugins/Boltun/src/Engine/WordsList.h new file mode 100644 index 0000000000..bd74b2007b --- /dev/null +++ b/plugins/Boltun/src/Engine/WordsList.h @@ -0,0 +1,56 @@ +//*********************************************************** +// Copyright © 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// Boltun is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Boltun. If not, see . +// +//*********************************************************** + +#ifndef WordsListH +#define WordsListH + +#include +#include +#include +#include "tchar.h" +#include "tstring.h" + +class WordsList +{ + WordsList(); + void Parse(tstring s/*, bool allowUnstrict = false*/); + //bool unstrict; +#ifdef _DEBUG +public: +#endif + std::set words; + bool isQuestion; +public: + WordsList(const tstring &data/*, bool allowUnstrict = false*/); + operator tstring() const; + bool MatchesAll(const std::vector& s/*, bool& WasStrict*/, float& priority) const; + bool MatchesAny(const std::vector& s) const; + std::vector ConsistsOf(const std::set& list) const; + std::vector DoesntIncludeAny(const std::set& list) const; + WordsList& operator= (const tstring& s); + bool operator<(const WordsList& value) const; + bool operator==(const WordsList& value) const; + bool operator!=(const WordsList& value) const; + bool IsQuestion() const; + bool IsEmpty() const; + size_t Size() const; +}; + +#endif diff --git a/plugins/Boltun/src/Engine/boltun.mindw b/plugins/Boltun/src/Engine/boltun.mindw new file mode 100644 index 0000000000..a6f9f2103d Binary files /dev/null and b/plugins/Boltun/src/Engine/boltun.mindw differ diff --git a/plugins/Boltun/src/Engine/tstring.h b/plugins/Boltun/src/Engine/tstring.h new file mode 100644 index 0000000000..e21984a12c --- /dev/null +++ b/plugins/Boltun/src/Engine/tstring.h @@ -0,0 +1,34 @@ +//*********************************************************** +// Copyright © 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// Boltun is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Boltun. If not, see . +// +//*********************************************************** + +#ifndef TSTRING_H +#define TSTRING_H + +#include +#include + +#ifndef TCHAR +#define TCHAR _TCHAR +#endif + +typedef std::basic_string, + std::allocator > tstring; + +#endif -- cgit v1.2.3