From 745028b080eeaeab4e50e0bc17052995a0be5a4a Mon Sep 17 00:00:00 2001 From: CJBrew Date: Sun, 18 Sep 2011 13:33:20 +0100 Subject: [PATCH 1/7] Try some c++ code to optimise searches through the text. Start with intrinsics and if it works, roll into other dispatch methods. This is intermediate checkin and breaks the functionality temporarily. --- intrinsics.cpp | 131 +++++++++++++++++++++++++++++++++++++++++ noobhack/game/brain.py | 28 +++++++-- scripts/noobhack | 9 ++- setup.py | 5 +- 4 files changed, 163 insertions(+), 10 deletions(-) create mode 100644 intrinsics.cpp diff --git a/intrinsics.cpp b/intrinsics.cpp new file mode 100644 index 0000000..afa6ef5 --- /dev/null +++ b/intrinsics.cpp @@ -0,0 +1,131 @@ +#include +#include +#include + +#include + +using namespace std; + +namespace +{ + static bool firstTime = true; + + struct Effect + { + string intrinsicName_; + bool result_; // enabled or disabled + }; + + static map effects; + + static void ParseDictionary(PyObject* intrinsicsDictionary, wofstream& fs) + { + + PyObject *keys = PyDict_Keys(intrinsicsDictionary); + for(int i = 0; i < PyList_Size(keys); ++i) + { + PyObject *thisKey = PyList_GetItem(keys, i); + PyObject *thisValue = PyDict_GetItem(intrinsicsDictionary, thisKey); + if(PyDict_Check(thisValue)) + { + const string keyString = PyString_AsString(thisKey); + const wstring wsKeyString(keyString.begin(), keyString.end()); + + PyObject *subKeys = PyDict_Keys(thisValue); + + for(int j = 0; j < PyList_Size(subKeys); ++j) + { + PyObject *thisSubKey = PyList_GetItem(subKeys, j); + + const string subKeyString = PyString_AsString(thisSubKey); + const wstring wsSubKeyString(subKeyString.begin(), subKeyString.end()); + + + PyObject *thisSubValue = PyDict_GetItem(thisValue, thisSubKey); + if(thisSubValue) + { + if(PyBool_Check(thisSubValue)) + { + + fs << L"Search Text: " << wsSubKeyString; + fs << L" value: " << (thisSubValue == Py_True ? L"enable" : L"disable"); + fs << L" " << wsKeyString << endl; + } + } + else + { + fs << L"value for " << wsSubKeyString << L" wasn't found" << endl; + } + } + } + } + } +} + +static PyObject* DispatchIntrinsics(PyObject *self, PyObject* args) +{ + wofstream fs("out.txt", ios::app); + fs << L"In DispatchIntrinsics\n"; + + if(PyTuple_Size(args) != 2) + { + fs << L"Two args expected (found " << PyTuple_Size(args) << L")!\n"; + return PyDict_New(); + } + + if(firstTime) + { + fs << L"First time! Collating data!" << endl; + + PyObject *intrinsicsDictionary = PyTuple_GetItem(args, 0); + if(PyDict_Check(intrinsicsDictionary)) + { + ParseDictionary(intrinsicsDictionary, fs); + } + else + { + fs << L" Intrinsics dictionary isn't a dictionary; we're buggered\n"; + return NULL; + } + } + + PyObject *messageData = PyTuple_GetItem(args, 1); + if(PyList_Check(messageData)) + { + fs << L"message data is a list (now expected...)\n"; + int listSize = PyList_Size(messageData); + fs << L"Size of list: " << listSize << endl; + for(int i=0;i(PyUnicode_AS_UNICODE(line))); + fs << L"line (isUnicode) " << i << L" = " << wsLine << endl; + } + } + } + + bool added = true; + PyObject* results = PyDict_New(); + PyObject* trueFalse = added ? Py_True : Py_False; + int res = PyDict_SetItem(results, PyString_FromString("Keyvalue"), trueFalse); + if(res != 0) + { + fs << L"pydict_setitem failed!\n"; + } + return results; +} + +static PyMethodDef IntrinsicsMethods[] = +{ + {"DispatchIntrinsics", DispatchIntrinsics, METH_VARARGS, "Figure out Intrinsics changed..."}, + {NULL, NULL, 0, NULL} +}; + +PyMODINIT_FUNC initintrinsicsC() +{ + (void) Py_InitModule("intrinsicsC", IntrinsicsMethods); +} + diff --git a/noobhack/game/brain.py b/noobhack/game/brain.py index 343bc25..a1abc8f 100644 --- a/noobhack/game/brain.py +++ b/noobhack/game/brain.py @@ -5,10 +5,16 @@ import re +from noobhack import ui +import vt102 +import logging + from noobhack.game.graphics import ibm from noobhack.game import shops, status, intrinsics, sounds, dungeon from noobhack.game.events import dispatcher +import intrinsicsC + class Brain: """ GrraaAAaaaAaaaa... braaaAAaaains... @@ -53,12 +59,22 @@ def _dispatch_level_feature_events(self, data): if match is not None: dispatcher.dispatch("level-feature", feature) - def _dispatch_intrinsic_events(self, data): - for name, messages in intrinsics.messages.iteritems(): - for message, value in messages.iteritems(): - match = re.search(message, data, re.I | re.M) - if match is not None: - dispatcher.dispatch("intrinsic", name, value) + def _dispatch_intrinsic_events(self, data): + + logging.basicConfig(filename="debug.out", level=logging.DEBUG) + logging.debug(ui.size()) + logging.debug(self.term.display) + + intrinsicsResult = intrinsicsC.DispatchIntrinsics( + intrinsics.messages, self.term.display) + + for name, value in intrinsicsResult.items(): + dispatcher.dispatch("intrinsic", name, value) +# for name, messages in intrinsics.messages.iteritems(): +# for message, value in messages.iteritems(): +# match = re.search(message, data, re.I | re.M) +# if match is not None: +# dispatcher.dispatch("intrinsic", name, value) def _dispatch_status_events(self, data): """ diff --git a/scripts/noobhack b/scripts/noobhack index ac86b5c..53ee22f 100755 --- a/scripts/noobhack +++ b/scripts/noobhack @@ -10,6 +10,10 @@ import optparse import cPickle as pickle +#import profile + +import cProfile + import vt102 from noobhack import ui, telnet, process, proxy @@ -314,9 +318,10 @@ class Noobhack: if __name__ == "__main__": locale.setlocale(locale.LC_ALL, "") - + hack = Noobhack() try: - curses.wrapper(hack.run) +# profile.run('curses.wrapper(hack.run); print') + cProfile.run('curses.wrapper(hack.run)', "noobhack.trace") except IOError, exit_message: print exit_message diff --git a/setup.py b/setup.py index 9b9c97d..2707887 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -from distutils.core import setup +from distutils.core import setup, Extension setup( name="noobhack", @@ -11,5 +11,6 @@ requires=["vt102 (>=0.3.2)"], packages=["noobhack", "noobhack.game"], scripts=["scripts/noobhack"], - license="Lesser General Public License v3.0" + license="Lesser General Public License v3.0", + ext_modules=[Extension('intrinsicsC', ['intrinsics.cpp'])], ) From d5d6c950a6f14c749c6ca70114f9e00111dace6f Mon Sep 17 00:00:00 2001 From: CJBrew Date: Mon, 19 Sep 2011 22:56:46 +0100 Subject: [PATCH 2/7] Added a test for the intrinsics search/parsing. --- intrinsics.cpp | 201 ++++++++++++++++++++++------------- test/game/test_intrinsics.py | 33 ++++++ 2 files changed, 158 insertions(+), 76 deletions(-) create mode 100644 test/game/test_intrinsics.py diff --git a/intrinsics.cpp b/intrinsics.cpp index afa6ef5..2318648 100644 --- a/intrinsics.cpp +++ b/intrinsics.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include @@ -12,53 +13,61 @@ namespace struct Effect { - string intrinsicName_; - bool result_; // enabled or disabled + Effect() + {} + + Effect(const string& name, bool result) : intrinsicName_(name), result_(result) + {} + + string intrinsicName_; + bool result_; // enabled or disabled }; - static map effects; + typedef map EffectsMap; + static EffectsMap effects; static void ParseDictionary(PyObject* intrinsicsDictionary, wofstream& fs) { - - PyObject *keys = PyDict_Keys(intrinsicsDictionary); - for(int i = 0; i < PyList_Size(keys); ++i) - { - PyObject *thisKey = PyList_GetItem(keys, i); - PyObject *thisValue = PyDict_GetItem(intrinsicsDictionary, thisKey); - if(PyDict_Check(thisValue)) - { - const string keyString = PyString_AsString(thisKey); - const wstring wsKeyString(keyString.begin(), keyString.end()); - - PyObject *subKeys = PyDict_Keys(thisValue); - - for(int j = 0; j < PyList_Size(subKeys); ++j) - { - PyObject *thisSubKey = PyList_GetItem(subKeys, j); - - const string subKeyString = PyString_AsString(thisSubKey); - const wstring wsSubKeyString(subKeyString.begin(), subKeyString.end()); - - - PyObject *thisSubValue = PyDict_GetItem(thisValue, thisSubKey); - if(thisSubValue) - { - if(PyBool_Check(thisSubValue)) - { - - fs << L"Search Text: " << wsSubKeyString; - fs << L" value: " << (thisSubValue == Py_True ? L"enable" : L"disable"); - fs << L" " << wsKeyString << endl; - } - } - else - { - fs << L"value for " << wsSubKeyString << L" wasn't found" << endl; - } - } - } - } + PyObject *keys = PyDict_Keys(intrinsicsDictionary); + for(int i = 0; i < PyList_Size(keys); ++i) + { + PyObject *thisKey = PyList_GetItem(keys, i); + PyObject *thisValue = PyDict_GetItem(intrinsicsDictionary, thisKey); + if(PyDict_Check(thisValue)) + { + const string keyString = PyString_AsString(thisKey); + const wstring wsKeyString(keyString.begin(), keyString.end()); + + PyObject *subKeys = PyDict_Keys(thisValue); + + for(int j = 0; j < PyList_Size(subKeys); ++j) + { + PyObject *thisSubKey = PyList_GetItem(subKeys, j); + + const string subKeyString = PyString_AsString(thisSubKey); + const wstring wsSubKeyString(subKeyString.begin(), subKeyString.end()); + + + PyObject *thisSubValue = PyDict_GetItem(thisValue, thisSubKey); + if(thisSubValue) + { + if(PyBool_Check(thisSubValue)) + { + + fs << L"Search Text: " << wsSubKeyString; + fs << L" value: " << (thisSubValue == Py_True ? L"enable" : L"disable"); + fs << L" " << wsKeyString << endl; + + effects[wsSubKeyString] = Effect(keyString, thisSubValue == Py_True); + } + } + else + { + fs << L"value for " << wsSubKeyString << L" wasn't found" << endl; + } + } + } + } } } @@ -69,54 +78,94 @@ static PyObject* DispatchIntrinsics(PyObject *self, PyObject* args) if(PyTuple_Size(args) != 2) { - fs << L"Two args expected (found " << PyTuple_Size(args) << L")!\n"; - return PyDict_New(); + fs << L"Two args expected (found " << PyTuple_Size(args) << L")!\n"; + return PyDict_New(); } if(firstTime) { - fs << L"First time! Collating data!" << endl; - - PyObject *intrinsicsDictionary = PyTuple_GetItem(args, 0); - if(PyDict_Check(intrinsicsDictionary)) - { - ParseDictionary(intrinsicsDictionary, fs); - } - else - { - fs << L" Intrinsics dictionary isn't a dictionary; we're buggered\n"; - return NULL; - } + fs << L"First time! Collating data!" << endl; + + PyObject *intrinsicsDictionary = PyTuple_GetItem(args, 0); + if(PyDict_Check(intrinsicsDictionary)) + { + ParseDictionary(intrinsicsDictionary, fs); + } + else + { + fs << L" Intrinsics dictionary isn't a dictionary; we're buggered\n"; + return NULL; + } } + vector added; + vector removed; + PyObject *messageData = PyTuple_GetItem(args, 1); if(PyList_Check(messageData)) { - fs << L"message data is a list (now expected...)\n"; - int listSize = PyList_Size(messageData); - fs << L"Size of list: " << listSize << endl; - for(int i=0;i(PyUnicode_AS_UNICODE(line))); - fs << L"line (isUnicode) " << i << L" = " << wsLine << endl; - } - } + int listSize = PyList_Size(messageData); + + fs << L"Number of rows: " << listSize << endl; + + for(int i=0;i(PyUnicode_AS_UNICODE(line))); + fs << L"line (unicode) " << i << L" = " << wsLine << endl; + + for(EffectsMap::const_iterator it = effects.begin(); + it != effects.end(); + ++it) + { + const wstring& searchterm = (*it).first; + + fs << L"testing for " << searchterm << endl; + if(string::npos != wsLine.find(searchterm)) + { + if(it->second.result_) + { + fs << L"found an Enable term" + << L"for " << wstring(it->second.intrinsicName_.begin(), it->second.intrinsicName_.end()) + << endl; + added.push_back(it->second.intrinsicName_); + } + else + { + fs << L"found a Disable term" + << L"for " << wstring(it->second.intrinsicName_.begin(), it->second.intrinsicName_.end()) + << endl; + removed.push_back(it->second.intrinsicName_); + } + } + } + } + } } - bool added = true; PyObject* results = PyDict_New(); - PyObject* trueFalse = added ? Py_True : Py_False; - int res = PyDict_SetItem(results, PyString_FromString("Keyvalue"), trueFalse); - if(res != 0) - { - fs << L"pydict_setitem failed!\n"; + for(vector::const_iterator it = added.begin(); it != added.end(); ++it) + { + int res = PyDict_SetItem(results, PyString_FromString(it->c_str()), Py_True); + if(res != 0) + { + fs << L"pydict_setitem failed!\n"; + } + } + for(vector::const_iterator it = removed.begin(); it != removed.end(); ++it) + { + int res = PyDict_SetItem(results, PyString_FromString(it->c_str()), Py_False); + if(res != 0) + { + fs << L"pydict_setitem failed!\n"; + } } return results; -} +} + static PyMethodDef IntrinsicsMethods[] = { diff --git a/test/game/test_intrinsics.py b/test/game/test_intrinsics.py new file mode 100644 index 0000000..fbbb810 --- /dev/null +++ b/test/game/test_intrinsics.py @@ -0,0 +1,33 @@ +import unittest + +import intrinsicsC + +testIntrinsics = { + "valA": { "aaa" : True, + "aaZ" : False }, + "valB": { "bbb" :True, + "bbZ" : False }, + } + +class IntrinsicsTest(unittest.TestCase): +# def test_nullTestFail(self): +# self.assertEqual(1, 0) +# +# def test_nullTestPass(self): +# self.assertEqual(1,1) + + def test_parse(self): + testEmpty = "" + uTestEmpty = testEmpty.decode('utf-8') + res = intrinsicsC.DispatchIntrinsics(testIntrinsics, [uTestEmpty]) + + def test_found_valA(self): + testInput = "blah aaa blah" + uTestInput = testInput.decode('utf-8') + res = intrinsicsC.DispatchIntrinsics(testIntrinsics, [uTestInput]) + self.assertEqual(len(res), 1) + self.assertEqual(res.items()[0][0], "valA") + self.assertEqual(res.items()[0][1], True) + +if __name__ == "__main__": + unittest.main() From 46e4d0bcf41840419c618568d017a5bb4f9be8bc Mon Sep 17 00:00:00 2001 From: CJBrew Date: Mon, 19 Sep 2011 23:12:41 +0100 Subject: [PATCH 3/7] added new tests --- intrinsics.cpp | 18 ++++++++++---- test/game/test_intrinsics.py | 47 ++++++++++++++++++++++++++++++------ 2 files changed, 53 insertions(+), 12 deletions(-) diff --git a/intrinsics.cpp b/intrinsics.cpp index 2318648..f67745e 100644 --- a/intrinsics.cpp +++ b/intrinsics.cpp @@ -125,18 +125,22 @@ static PyObject* DispatchIntrinsics(PyObject *self, PyObject* args) fs << L"testing for " << searchterm << endl; if(string::npos != wsLine.find(searchterm)) - { + { + const string name(it->second.intrinsicName_); + const wstring wsName(name.begin(), name.end()); + if(it->second.result_) { fs << L"found an Enable term" - << L"for " << wstring(it->second.intrinsicName_.begin(), it->second.intrinsicName_.end()) + << L"for " << wstring(wsName) << endl; added.push_back(it->second.intrinsicName_); } else { - fs << L"found a Disable term" - << L"for " << wstring(it->second.intrinsicName_.begin(), it->second.intrinsicName_.end()) + + fs << L"found a Disable term for " + << wstring(wsName) << endl; removed.push_back(it->second.intrinsicName_); } @@ -148,7 +152,9 @@ static PyObject* DispatchIntrinsics(PyObject *self, PyObject* args) PyObject* results = PyDict_New(); for(vector::const_iterator it = added.begin(); it != added.end(); ++it) - { + { + const wstring wsIt(it->begin(), it->end()); + fs << L"adding Enabled for " << wsIt << endl; int res = PyDict_SetItem(results, PyString_FromString(it->c_str()), Py_True); if(res != 0) { @@ -157,6 +163,8 @@ static PyObject* DispatchIntrinsics(PyObject *self, PyObject* args) } for(vector::const_iterator it = removed.begin(); it != removed.end(); ++it) { + const wstring wsIt(it->begin(), it->end()); + fs << L"adding Disabled for " << wsIt << endl; int res = PyDict_SetItem(results, PyString_FromString(it->c_str()), Py_False); if(res != 0) { diff --git a/test/game/test_intrinsics.py b/test/game/test_intrinsics.py index fbbb810..516b34c 100644 --- a/test/game/test_intrinsics.py +++ b/test/game/test_intrinsics.py @@ -10,18 +10,14 @@ } class IntrinsicsTest(unittest.TestCase): -# def test_nullTestFail(self): -# self.assertEqual(1, 0) -# -# def test_nullTestPass(self): -# self.assertEqual(1,1) - def test_parse(self): + def test_parseOnlyNoResult(self): testEmpty = "" uTestEmpty = testEmpty.decode('utf-8') res = intrinsicsC.DispatchIntrinsics(testIntrinsics, [uTestEmpty]) + self.assertEqual(len(res), 0) - def test_found_valA(self): + def test_found_valA_Enable(self): testInput = "blah aaa blah" uTestInput = testInput.decode('utf-8') res = intrinsicsC.DispatchIntrinsics(testIntrinsics, [uTestInput]) @@ -29,5 +25,42 @@ def test_found_valA(self): self.assertEqual(res.items()[0][0], "valA") self.assertEqual(res.items()[0][1], True) + def test_found_valA_Disable(self): + testInput = "blah aaZ blah" + uTestInput = testInput.decode('utf-8') + res = intrinsicsC.DispatchIntrinsics(testIntrinsics, [uTestInput]) + self.assertEqual(len(res), 1) + self.assertEqual(res.items()[0][0], "valA") + self.assertEqual(res.items()[0][1], False) + + def test_found_valA_EnableDisable(self): + testInput = "aaa blah aaZ blah" + uTestInput = testInput.decode('utf-8') + res = intrinsicsC.DispatchIntrinsics(testIntrinsics, [uTestInput]) + self.assertEqual(len(res), 1) + self.assertEqual(res.items()[0][0], "valA") + self.assertEqual(res.items()[0][1], False) + + def test_found_valAvalB_Enabled(self): + testInput = "aaa blah bbb blah" + uTestInput = testInput.decode('utf-8') + res = intrinsicsC.DispatchIntrinsics(testIntrinsics, [uTestInput]) + self.assertEqual(len(res), 2) + self.assertEqual(res.items()[0][0], "valB") + self.assertEqual(res.items()[0][1], True) + self.assertEqual(res.items()[1][0], "valA") + self.assertEqual(res.items()[1][1], True) + + def test_found_valBvalA_Enabled(self): + testInput = "bbb blah aaa blah" + uTestInput = testInput.decode('utf-8') + res = intrinsicsC.DispatchIntrinsics(testIntrinsics, [uTestInput]) + self.assertEqual(len(res), 2) + self.assertEqual(res.items()[0][0], "valB") + self.assertEqual(res.items()[0][1], True) + self.assertEqual(res.items()[1][0], "valA") + self.assertEqual(res.items()[1][1], True) + + if __name__ == "__main__": unittest.main() From d584a8fac3f8267824ca049d5a8cba76d40019cd Mon Sep 17 00:00:00 2001 From: CJBrew Date: Tue, 20 Sep 2011 00:10:27 +0100 Subject: [PATCH 4/7] Refactoring --- intrinsics.cpp | 201 ++++++++++++++++++----------------- test/game/test_intrinsics.py | 9 ++ 2 files changed, 114 insertions(+), 96 deletions(-) diff --git a/intrinsics.cpp b/intrinsics.cpp index f67745e..8ca5288 100644 --- a/intrinsics.cpp +++ b/intrinsics.cpp @@ -1,6 +1,6 @@ #include #include -#include +//#include #include #include @@ -11,62 +11,76 @@ namespace { static bool firstTime = true; - struct Effect + struct TextSearchItem { - Effect() + TextSearchItem() {} - Effect(const string& name, bool result) : intrinsicName_(name), result_(result) + TextSearchItem(const string& name, const wstring& searchTerm, bool result) + : name_(name), + searchTerm_(searchTerm), + result_(result) {} - string intrinsicName_; - bool result_; // enabled or disabled + string name_; + wstring searchTerm_; + bool result_; // item enabled or disabled }; - typedef map EffectsMap; - static EffectsMap effects; + typedef vector TextSearchItems; + static TextSearchItems searchItems; - static void ParseDictionary(PyObject* intrinsicsDictionary, wofstream& fs) + string ToStr(PyObject* pyOb) { - PyObject *keys = PyDict_Keys(intrinsicsDictionary); + // is type-check needed? + return PyString_AsString(pyOb); + } + + wstring ToWStr(PyObject* pyOb) + { + // is type-check needed? + const string str = PyString_AsString(pyOb); + return wstring(str.begin(), str.end()); + } + + bool ToBool(PyObject* pyOb) + { + // if PyBool_check(pyOb) ... is type-check needed? + return Py_True == pyOb; + } + + static void ParseDictionary(PyObject* dictionary, wofstream& fs) + { + firstTime = false; // we don't want to do this again... + + PyObject *keys = PyDict_Keys(dictionary); for(int i = 0; i < PyList_Size(keys); ++i) { - PyObject *thisKey = PyList_GetItem(keys, i); - PyObject *thisValue = PyDict_GetItem(intrinsicsDictionary, thisKey); - if(PyDict_Check(thisValue)) - { - const string keyString = PyString_AsString(thisKey); - const wstring wsKeyString(keyString.begin(), keyString.end()); - - PyObject *subKeys = PyDict_Keys(thisValue); + PyObject* pyItemName = PyList_GetItem(keys, i); + const string itemName = ToStr(pyItemName); - for(int j = 0; j < PyList_Size(subKeys); ++j) - { - PyObject *thisSubKey = PyList_GetItem(subKeys, j); + PyObject *itemSearchTerms = PyDict_GetItem(dictionary, pyItemName); + if(!PyDict_Check(itemSearchTerms)) + { + continue; + } - const string subKeyString = PyString_AsString(thisSubKey); - const wstring wsSubKeyString(subKeyString.begin(), subKeyString.end()); + PyObject *subKeys = PyDict_Keys(itemSearchTerms); + for(int j = 0; j < PyList_Size(subKeys); ++j) + { + PyObject* pySearchTerm = PyList_GetItem(subKeys, j); - PyObject *thisSubValue = PyDict_GetItem(thisValue, thisSubKey); - if(thisSubValue) - { - if(PyBool_Check(thisSubValue)) - { + const wstring wsSearchTerm = ToWStr(pySearchTerm); + bool searchTermValue = ToBool(PyDict_GetItem(itemSearchTerms, pySearchTerm)); - fs << L"Search Text: " << wsSubKeyString; - fs << L" value: " << (thisSubValue == Py_True ? L"enable" : L"disable"); - fs << L" " << wsKeyString << endl; + fs << L"Search Text: " << wsSearchTerm; + fs << L" value: " << searchTermValue; + const wstring wsItemName(itemName.begin(), itemName.end()); + fs << L" " << wsItemName << endl; - effects[wsSubKeyString] = Effect(keyString, thisSubValue == Py_True); - } - } - else - { - fs << L"value for " << wsSubKeyString << L" wasn't found" << endl; - } - } - } + searchItems.push_back(TextSearchItem(itemName, wsSearchTerm, searchTermValue)); + } } } } @@ -86,20 +100,21 @@ static PyObject* DispatchIntrinsics(PyObject *self, PyObject* args) { fs << L"First time! Collating data!" << endl; - PyObject *intrinsicsDictionary = PyTuple_GetItem(args, 0); - if(PyDict_Check(intrinsicsDictionary)) + PyObject *dictionary = PyTuple_GetItem(args, 0); + if(PyDict_Check(dictionary)) { - ParseDictionary(intrinsicsDictionary, fs); + ParseDictionary(dictionary, fs); } else { - fs << L" Intrinsics dictionary isn't a dictionary; we're buggered\n"; + fs << L"If the dictionary isn't a dictionary; we're scuppered\n"; return NULL; } } - vector added; - vector removed; + typedef pair StdResult; + typedef vector< StdResult > StdResults; + StdResults stdResults; PyObject *messageData = PyTuple_GetItem(args, 1); if(PyList_Check(messageData)) @@ -108,70 +123,64 @@ static PyObject* DispatchIntrinsics(PyObject *self, PyObject* args) fs << L"Number of rows: " << listSize << endl; - for(int i=0;i( PyUnicode_AS_UNICODE(line) ) ); + fs << L"line (unicode) " << i << L" = " << wsLine << endl; + + if(wsLine == L"") { - const wstring wsLine(reinterpret_cast(PyUnicode_AS_UNICODE(line))); - fs << L"line (unicode) " << i << L" = " << wsLine << endl; - - for(EffectsMap::const_iterator it = effects.begin(); - it != effects.end(); - ++it) - { - const wstring& searchterm = (*it).first; - - fs << L"testing for " << searchterm << endl; - if(string::npos != wsLine.find(searchterm)) - { - const string name(it->second.intrinsicName_); - const wstring wsName(name.begin(), name.end()); - - if(it->second.result_) - { - fs << L"found an Enable term" - << L"for " << wstring(wsName) - << endl; - added.push_back(it->second.intrinsicName_); - } - else - { - - fs << L"found a Disable term for " - << wstring(wsName) - << endl; - removed.push_back(it->second.intrinsicName_); - } - } - } + fs << L"empty. Next?" << endl; + continue; + } + + for(TextSearchItems::const_iterator it = searchItems.begin(); + it != searchItems.end(); + ++it) + { + fs << L"testing for " << it->searchTerm_ << endl; + if(string::npos != wsLine.find(it->searchTerm_)) + { + const string name(it->name_); + const wstring wsName(name.begin(), name.end()); + + if(it->result_) + { + fs << L"found an Enable term " + << L"for " << wstring(wsName) + << endl; + stdResults.push_back( StdResult(it->name_, true) ); + } + else + { + + fs << L"found a Disable term for " + << wstring(wsName) + << endl; + stdResults.push_back( StdResult(it->name_, false) ); + } + } } } } - PyObject* results = PyDict_New(); - for(vector::const_iterator it = added.begin(); it != added.end(); ++it) + PyObject* pyResults = PyDict_New(); + for(StdResults::const_iterator it = stdResults.begin(); it != stdResults.end(); ++it) { - const wstring wsIt(it->begin(), it->end()); - fs << L"adding Enabled for " << wsIt << endl; - int res = PyDict_SetItem(results, PyString_FromString(it->c_str()), Py_True); - if(res != 0) - { - fs << L"pydict_setitem failed!\n"; - } - } - for(vector::const_iterator it = removed.begin(); it != removed.end(); ++it) - { - const wstring wsIt(it->begin(), it->end()); - fs << L"adding Disabled for " << wsIt << endl; - int res = PyDict_SetItem(results, PyString_FromString(it->c_str()), Py_False); + const string name(it->first); + int res = PyDict_SetItem(pyResults, PyString_FromString(name.c_str()), it->second ? Py_True : Py_False); if(res != 0) { fs << L"pydict_setitem failed!\n"; } } - return results; + return pyResults; } diff --git a/test/game/test_intrinsics.py b/test/game/test_intrinsics.py index 516b34c..4e2c796 100644 --- a/test/game/test_intrinsics.py +++ b/test/game/test_intrinsics.py @@ -61,6 +61,15 @@ def test_found_valBvalA_Enabled(self): self.assertEqual(res.items()[1][0], "valA") self.assertEqual(res.items()[1][1], True) + def test_found_valA_Enabled_valB_Disabled(self): + testInput = "aaa blah bbZ blah" + uTestInput = testInput.decode('utf-8') + res = intrinsicsC.DispatchIntrinsics(testIntrinsics, [uTestInput]) + self.assertEqual(len(res), 2) + self.assertEqual(res.items()[0][0], "valB") + self.assertEqual(res.items()[0][1], False) + self.assertEqual(res.items()[1][0], "valA") + self.assertEqual(res.items()[1][1], True) if __name__ == "__main__": unittest.main() From d518cc85f3f539a274b7767ee83fc3b697204572 Mon Sep 17 00:00:00 2001 From: CJBrew Date: Tue, 20 Sep 2011 19:48:31 +0100 Subject: [PATCH 5/7] Moved Intrinsic module to within the codebase, removed logging that was causing a perfomance issue. --- noobhack/game/brain.py | 11 ----- .../game/cpp/intrinsics.cpp | 42 +++---------------- setup.py | 5 ++- 3 files changed, 10 insertions(+), 48 deletions(-) rename intrinsics.cpp => noobhack/game/cpp/intrinsics.cpp (74%) diff --git a/noobhack/game/brain.py b/noobhack/game/brain.py index a1abc8f..4954903 100644 --- a/noobhack/game/brain.py +++ b/noobhack/game/brain.py @@ -7,7 +7,6 @@ from noobhack import ui import vt102 -import logging from noobhack.game.graphics import ibm from noobhack.game import shops, status, intrinsics, sounds, dungeon @@ -60,21 +59,11 @@ def _dispatch_level_feature_events(self, data): dispatcher.dispatch("level-feature", feature) def _dispatch_intrinsic_events(self, data): - - logging.basicConfig(filename="debug.out", level=logging.DEBUG) - logging.debug(ui.size()) - logging.debug(self.term.display) - intrinsicsResult = intrinsicsC.DispatchIntrinsics( intrinsics.messages, self.term.display) for name, value in intrinsicsResult.items(): dispatcher.dispatch("intrinsic", name, value) -# for name, messages in intrinsics.messages.iteritems(): -# for message, value in messages.iteritems(): -# match = re.search(message, data, re.I | re.M) -# if match is not None: -# dispatcher.dispatch("intrinsic", name, value) def _dispatch_status_events(self, data): """ diff --git a/intrinsics.cpp b/noobhack/game/cpp/intrinsics.cpp similarity index 74% rename from intrinsics.cpp rename to noobhack/game/cpp/intrinsics.cpp index 8ca5288..7884551 100644 --- a/intrinsics.cpp +++ b/noobhack/game/cpp/intrinsics.cpp @@ -1,10 +1,8 @@ -#include +#include + #include -//#include #include -#include - using namespace std; namespace @@ -24,7 +22,7 @@ namespace string name_; wstring searchTerm_; - bool result_; // item enabled or disabled + bool result_; // intrinsic/status enabled or disabled }; typedef vector TextSearchItems; @@ -49,7 +47,7 @@ namespace return Py_True == pyOb; } - static void ParseDictionary(PyObject* dictionary, wofstream& fs) + static void ParseDictionary(PyObject* dictionary) { firstTime = false; // we don't want to do this again... @@ -74,11 +72,6 @@ namespace const wstring wsSearchTerm = ToWStr(pySearchTerm); bool searchTermValue = ToBool(PyDict_GetItem(itemSearchTerms, pySearchTerm)); - fs << L"Search Text: " << wsSearchTerm; - fs << L" value: " << searchTermValue; - const wstring wsItemName(itemName.begin(), itemName.end()); - fs << L" " << wsItemName << endl; - searchItems.push_back(TextSearchItem(itemName, wsSearchTerm, searchTermValue)); } } @@ -87,27 +80,20 @@ namespace static PyObject* DispatchIntrinsics(PyObject *self, PyObject* args) { - wofstream fs("out.txt", ios::app); - fs << L"In DispatchIntrinsics\n"; - if(PyTuple_Size(args) != 2) { - fs << L"Two args expected (found " << PyTuple_Size(args) << L")!\n"; return PyDict_New(); } if(firstTime) { - fs << L"First time! Collating data!" << endl; - PyObject *dictionary = PyTuple_GetItem(args, 0); if(PyDict_Check(dictionary)) { - ParseDictionary(dictionary, fs); + ParseDictionary(dictionary); } else { - fs << L"If the dictionary isn't a dictionary; we're scuppered\n"; return NULL; } } @@ -121,8 +107,6 @@ static PyObject* DispatchIntrinsics(PyObject *self, PyObject* args) { int listSize = PyList_Size(messageData); - fs << L"Number of rows: " << listSize << endl; - for(int i=0 ; i < listSize ; ++i) { PyObject* line = PyList_GetItem(messageData, i); @@ -132,11 +116,9 @@ static PyObject* DispatchIntrinsics(PyObject *self, PyObject* args) } const wstring wsLine( reinterpret_cast< wchar_t* >( PyUnicode_AS_UNICODE(line) ) ); - fs << L"line (unicode) " << i << L" = " << wsLine << endl; if(wsLine == L"") { - fs << L"empty. Next?" << endl; continue; } @@ -144,7 +126,6 @@ static PyObject* DispatchIntrinsics(PyObject *self, PyObject* args) it != searchItems.end(); ++it) { - fs << L"testing for " << it->searchTerm_ << endl; if(string::npos != wsLine.find(it->searchTerm_)) { const string name(it->name_); @@ -152,17 +133,10 @@ static PyObject* DispatchIntrinsics(PyObject *self, PyObject* args) if(it->result_) { - fs << L"found an Enable term " - << L"for " << wstring(wsName) - << endl; stdResults.push_back( StdResult(it->name_, true) ); } else { - - fs << L"found a Disable term for " - << wstring(wsName) - << endl; stdResults.push_back( StdResult(it->name_, false) ); } } @@ -174,11 +148,7 @@ static PyObject* DispatchIntrinsics(PyObject *self, PyObject* args) for(StdResults::const_iterator it = stdResults.begin(); it != stdResults.end(); ++it) { const string name(it->first); - int res = PyDict_SetItem(pyResults, PyString_FromString(name.c_str()), it->second ? Py_True : Py_False); - if(res != 0) - { - fs << L"pydict_setitem failed!\n"; - } + PyDict_SetItem(pyResults, PyString_FromString(name.c_str()), it->second ? Py_True : Py_False); } return pyResults; } diff --git a/setup.py b/setup.py index 2707887..c5a250f 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,8 @@ from distutils.core import setup, Extension +intrinsicsModule = Extension('intrinsicsC', + sources = ['noobhack/game/cpp/intrinsics.cpp']) + setup( name="noobhack", version="0.3", @@ -12,5 +15,5 @@ packages=["noobhack", "noobhack.game"], scripts=["scripts/noobhack"], license="Lesser General Public License v3.0", - ext_modules=[Extension('intrinsicsC', ['intrinsics.cpp'])], + ext_modules=[intrinsicsModule], #Extension('intrinsicsC', ['noobhack/game/cpp/intrinsics.cpp'])], ) From ff3d7e60ed24b338cfcebe506ee3fd4a6f80529e Mon Sep 17 00:00:00 2001 From: Chris Yate Date: Fri, 7 Oct 2011 20:06:53 +0100 Subject: [PATCH 6/7] Collate all the lines of message data together before searching for messages, in case the message goes across multiple lines. --- noobhack/game/cpp/intrinsics.cpp | 53 ++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/noobhack/game/cpp/intrinsics.cpp b/noobhack/game/cpp/intrinsics.cpp index 7884551..7ee285a 100644 --- a/noobhack/game/cpp/intrinsics.cpp +++ b/noobhack/game/cpp/intrinsics.cpp @@ -1,6 +1,7 @@ #include #include +#include #include using namespace std; @@ -107,6 +108,8 @@ static PyObject* DispatchIntrinsics(PyObject *self, PyObject* args) { int listSize = PyList_Size(messageData); + wostringstream lines; + for(int i=0 ; i < listSize ; ++i) { PyObject* line = PyList_GetItem(messageData, i); @@ -116,39 +119,43 @@ static PyObject* DispatchIntrinsics(PyObject *self, PyObject* args) } const wstring wsLine( reinterpret_cast< wchar_t* >( PyUnicode_AS_UNICODE(line) ) ); - + lines << wsLine; + if(wsLine == L"") { continue; } + } - for(TextSearchItems::const_iterator it = searchItems.begin(); - it != searchItems.end(); - ++it) - { - if(string::npos != wsLine.find(it->searchTerm_)) + const wstring fullScreenData = lines.str(); + + for(TextSearchItems::const_iterator it = searchItems.begin(); + it != searchItems.end(); + ++it) + { + if(string::npos != fullScreenData.find(it->searchTerm_)) { - const string name(it->name_); - const wstring wsName(name.begin(), name.end()); - - if(it->result_) - { - stdResults.push_back( StdResult(it->name_, true) ); - } - else - { - stdResults.push_back( StdResult(it->name_, false) ); - } + const string name(it->name_); + const wstring wsName(name.begin(), name.end()); + + if(it->result_) + { + stdResults.push_back( StdResult(it->name_, true) ); + } + else + { + stdResults.push_back( StdResult(it->name_, false) ); + } } - } } + } PyObject* pyResults = PyDict_New(); for(StdResults::const_iterator it = stdResults.begin(); it != stdResults.end(); ++it) { - const string name(it->first); - PyDict_SetItem(pyResults, PyString_FromString(name.c_str()), it->second ? Py_True : Py_False); + const string name(it->first); + PyDict_SetItem(pyResults, PyString_FromString(name.c_str()), it->second ? Py_True : Py_False); } return pyResults; } @@ -156,12 +163,12 @@ static PyObject* DispatchIntrinsics(PyObject *self, PyObject* args) static PyMethodDef IntrinsicsMethods[] = { - {"DispatchIntrinsics", DispatchIntrinsics, METH_VARARGS, "Figure out Intrinsics changed..."}, - {NULL, NULL, 0, NULL} + {"DispatchIntrinsics", DispatchIntrinsics, METH_VARARGS, "Figure out Intrinsics changed..."}, + {NULL, NULL, 0, NULL} }; PyMODINIT_FUNC initintrinsicsC() { - (void) Py_InitModule("intrinsicsC", IntrinsicsMethods); + (void) Py_InitModule("intrinsicsC", IntrinsicsMethods); } From e142574b38e669afdd7ed947466c17c4cff9661c Mon Sep 17 00:00:00 2001 From: Chris Yate Date: Fri, 7 Oct 2011 22:11:02 +0100 Subject: [PATCH 7/7] intrinsics.cpp : Using Boost::regex to search in C++ for intrinsics. intrinsics.py : Since we're now looking at regex search we don't want full stops in the search strings - removed. Also removed are exclamation marks. setup.py : modified the Extensions build info to link against libboost_regex --- noobhack/game/cpp/intrinsics.cpp | 8 +++-- noobhack/game/intrinsics.py | 52 ++++++++++++++++---------------- setup.py | 5 ++- 3 files changed, 36 insertions(+), 29 deletions(-) diff --git a/noobhack/game/cpp/intrinsics.cpp b/noobhack/game/cpp/intrinsics.cpp index 7ee285a..8b1e907 100644 --- a/noobhack/game/cpp/intrinsics.cpp +++ b/noobhack/game/cpp/intrinsics.cpp @@ -1,5 +1,7 @@ #include +#include + #include #include #include @@ -48,7 +50,7 @@ namespace return Py_True == pyOb; } - static void ParseDictionary(PyObject* dictionary) +static void ParseDictionary(PyObject* dictionary) { firstTime = false; // we don't want to do this again... @@ -89,6 +91,7 @@ static PyObject* DispatchIntrinsics(PyObject *self, PyObject* args) if(firstTime) { PyObject *dictionary = PyTuple_GetItem(args, 0); + // is type-check needed? if(PyDict_Check(dictionary)) { ParseDictionary(dictionary); @@ -104,6 +107,7 @@ static PyObject* DispatchIntrinsics(PyObject *self, PyObject* args) StdResults stdResults; PyObject *messageData = PyTuple_GetItem(args, 1); + // is type-check needed? if(PyList_Check(messageData)) { int listSize = PyList_Size(messageData); @@ -133,7 +137,7 @@ static PyObject* DispatchIntrinsics(PyObject *self, PyObject* args) it != searchItems.end(); ++it) { - if(string::npos != fullScreenData.find(it->searchTerm_)) + if(boost::regex_search(fullScreenData, boost::wregex(it->searchTerm_))) { const string name(it->name_); const wstring wsName(name.begin(), name.end()); diff --git a/noobhack/game/intrinsics.py b/noobhack/game/intrinsics.py index b5894e2..8ddd7f9 100644 --- a/noobhack/game/intrinsics.py +++ b/noobhack/game/intrinsics.py @@ -1,42 +1,42 @@ messages = { "Warning": { - "You feel sensitive!":True, - "You feel less sensitive!":False, + "You feel sensitive":True, + "You feel less sensitive":False, }, "Shock resistance": { - "Your health currently feels amplified!":True, - "You feel insulated!":True, + "Your health currently feels amplified":True, + "You feel insulated":True, "You are shock resistant":True, - "You feel grounded in reality.":True, + "You feel grounded in reality":True, "You feel conductive":False }, "Fire resistance": { - "You be chillin'.":True, - "You feel cool!":True, + "You be chillin'":True, + "You feel cool":True, "You are fire resistant":True, - "You feel a momentary chill.":True, - "You feel warmer!":False + "You feel a momentary chill":True, + "You feel warmer":False }, "Cold resistance": { "You are cold resistant":True, - "You feel warm!":True, - "You feel full of hot air.":True, - "You feel cooler!":False + "You feel warm":True, + "You feel full of hot air":True, + "You feel cooler":False }, - "Disintegration resist.": { + "Disintegration resist": { "You are disintegration-resistant":True, - "You feel very firm.":True, - "You feel totally together, man.":True + "You feel very firm":True, + "You feel totally together, man":True }, "Poison resistance": { "You are poison resistant":True, "You feel( especially)? (healthy)|(hardy)":True, - "You feel a little sick!":False + "You feel a little sick":False }, "Sleep resistance": { "You are sleep resistant":True, "You feel( wide)? awake":True, - "You feel tired!":False + "You feel tired":False }, "Aggravate monster": { "You feel that monsters are aware of your presence":True, @@ -46,22 +46,22 @@ "You feel vulnerable":False }, "Invisible": { - "You feel hidden!":True + "You feel hidden":True }, "See invisible": { - "You see an image of someone stalking you.":True, + "You see an image of someone stalking you":True, "You feel transparent":True, "You feel very self-conscious":True, "Your vision becomes clear":True }, "Searching": { - "You feel perceptive!":True + "You feel perceptive":True }, "Speed": { - "You feel quick!":True, - "You feel yourself speed up.":True, # speed boots put on (want this here?)! - "You feel yourself slow down.":False, # speed boots removed (want this here?)! - "You feel slow!":False + "You feel quick":True, + "You feel yourself speed up":True, # speed boots put on (want this here?)! + "You feel yourself slow down":False, # speed boots removed (want this here?)! + "You feel slow":False }, "Teleportitis": { "You feel very jumpy":True, @@ -70,9 +70,9 @@ }, "Teleport control": { "You feel in control of yourself":True, - "You feel controlled!":True, + "You feel controlled":True, "You feel centered in your personal space":True, - "You feel less jumpy":False + "You feel less jumpy":False }, "Telepathy": { "You feel in touch with the cosmos":True, diff --git a/setup.py b/setup.py index c5a250f..c8626fa 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,8 @@ from distutils.core import setup, Extension intrinsicsModule = Extension('intrinsicsC', - sources = ['noobhack/game/cpp/intrinsics.cpp']) + sources = ['noobhack/game/cpp/intrinsics.cpp'], + libraries = ['boost_regex']) setup( name="noobhack", @@ -17,3 +18,5 @@ license="Lesser General Public License v3.0", ext_modules=[intrinsicsModule], #Extension('intrinsicsC', ['noobhack/game/cpp/intrinsics.cpp'])], ) + +