[Tutor] Already Initialized Object Inheritance?
I can not get this to behave in the manor that I would like. I am trying to have an object refereed to as CursesApp.Screen become the already initialized object "stdscr". To elaborate I would like it to become that object but to also be able to define additional methods and properties, so more along the lines of inherit from "stdscr". Is this even possible? Well I can make it equal to that object I can not add additional methods and properties to it? Additionally, so that I learn; where has my thinking been too short sited? Thank you for your help. -- Jordan CODE BELOW #!/usr/bin/python3 """With thi method I can make the class "Screen" become "stdscr" but if I refernce any of the new methods or properties the applications promptly fails and notifies me that the method or property does not exist. Another downside of this method is I can not reference self.Screen.* or it crashes.""" import curses class CursesApp: def __init__(self, stdscr): self.Screen(stdscr) #This is the stdscr object. curses.init_pair(1,curses.COLOR_BLUE,curses.COLOR_YELLOW) #self.Screen.bkgd(' ', curses.color_pair(1)) #self.mainLoop() #def mainLoop(self): #while 1: #self.Screen.refresh() #key=self.Screen.getch() #if key==ord('q'): break class Screen: def __init__(self,stdscr): self=stdscr #self.height, self.width = self.getmaxyx() # any reference to these crashes #self.offsety, self.offsetx = -self.height/2, -self.width/2 # any reference to these crashes #self.curx, self.cury = 1, 1 # any reference to these crashes self.clear() self.border(0) while 1: self.refresh() key=self.getch() if key==ord('q'): break def main(): cursesapp = curses.wrapper(setup) def setup(stdscr): CursesApp(stdscr) if __name__ == '__main__': main() CODE BELOW #!/usr/bin/python3 """With this method I can make "Screen" become "stdscr" but if I obviously can not even define any new methods or properties. But atleast the references can be used through out the class with out crashing.""" import curses class CursesApp: def __init__(self, stdscr): self.Screen=stdscr #This is the stdscr object. curses.init_pair(1,curses.COLOR_BLUE,curses.COLOR_YELLOW) self.Screen.bkgd(' ', curses.color_pair(1)) self.mainLoop() def mainLoop(self): while 1: self.Screen.refresh() key=self.Screen.getch() if key==ord('q'): break def main(): cursesapp = curses.wrapper(setup) def setup(stdscr): CursesApp(stdscr) if __name__ == '__main__': main() ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Already Initialized Object Inheritance?
Unfortunately I am not able to inherit "stdscr" using that method. As Python returns with an error stating that "stdscr" is not defined. This error is returned at run time and by the compiler prior to actual execution. If you would like I can write a quick example that will generate the error message for that method. -- Jordan On Wed, 2011-06-15 at 02:04 -0400, Japhy Bartlett wrote: > When you're subclassing something, you use the syntax: > > class Foo(Bar): > > It seems like you're trying to do: > > class Bar: > class Foo: > > - Japhy > > On Wed, Jun 15, 2011 at 12:47 AM, WolfRage wrote: > > I can not get this to behave in the manor that I would like. I am trying > > to have an object refereed to as CursesApp.Screen become the already > > initialized object "stdscr". To elaborate I would like it to become that > > object but to also be able to define additional methods and properties, > > so more along the lines of inherit from "stdscr". Is this even possible? > > Well I can make it equal to that object I can not add additional methods > > and properties to it? Additionally, so that I learn; where has my > > thinking been too short sited? Thank you for your help. > > -- > > Jordan > > > > CODE BELOW > > > > #!/usr/bin/python3 > > """With thi method I can make the class "Screen" become "stdscr" but if > > I refernce any of the new methods or properties the applications > > promptly fails and notifies me that the method or property does not > > exist. Another downside of this method is I can not reference > > self.Screen.* or it crashes.""" > > import curses > > class CursesApp: > >def __init__(self, stdscr): > >self.Screen(stdscr) #This is the stdscr object. > >curses.init_pair(1,curses.COLOR_BLUE,curses.COLOR_YELLOW) > >#self.Screen.bkgd(' ', curses.color_pair(1)) > >#self.mainLoop() > > > >#def mainLoop(self): > >#while 1: > >#self.Screen.refresh() > >#key=self.Screen.getch() > >#if key==ord('q'): break > > > >class Screen: > >def __init__(self,stdscr): > >self=stdscr > >#self.height, self.width = self.getmaxyx() # any reference > > to these crashes > >#self.offsety, self.offsetx = -self.height/2, -self.width/2 > > # any reference to these crashes > >#self.curx, self.cury = 1, 1 # any reference to these > > crashes > >self.clear() > >self.border(0) > >while 1: > >self.refresh() > >key=self.getch() > >if key==ord('q'): break > > > > def main(): > >cursesapp = curses.wrapper(setup) > > > > def setup(stdscr): > >CursesApp(stdscr) > > > > if __name__ == '__main__': > >main() > > > > > > > > CODE BELOW > > > > #!/usr/bin/python3 > > """With this method I can make "Screen" become "stdscr" but if I > > obviously can not even define any new methods or properties. But atleast > > the references can be used through out the class with out crashing.""" > > import curses > > class CursesApp: > >def __init__(self, stdscr): > >self.Screen=stdscr #This is the stdscr object. > >curses.init_pair(1,curses.COLOR_BLUE,curses.COLOR_YELLOW) > >self.Screen.bkgd(' ', curses.color_pair(1)) > >self.mainLoop() > > > >def mainLoop(self): > >while 1: > >self.Screen.refresh() > >key=self.Screen.getch() > >if key==ord('q'): break > > > > def main(): > >cursesapp = curses.wrapper(setup) > > > > def setup(stdscr): > >CursesApp(stdscr) > > > > if __name__ == '__main__': > >main() > > > > ___ > > Tutor maillist - Tutor@python.org > > To unsubscribe or change subscription options: > > http://mail.python.org/mailman/listinfo/tutor > > ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Already Initialized Object Inheritance?
Christopher, Thank you for the explanation of the error. I see now why I am unable to reference it outside of __init__'s scope. No, I did not mean to do that. I will include further details in my reply to Steven. Please feel free to jump in on that conversation to continue my learning. Thank you for your help and time thus far. -- Jordan On Wed, 2011-06-15 at 09:45 -0400, Christopher King wrote: > Oh, I think I see the error. > self=stdscr > This will just make the variable called self be assigned to > stdscr with in __init__ This will not make the object actually turn > into stdscr > Or maybe you meant do that, because I don't know what stdscr or > the curses module is > > On Wed, Jun 15, 2011 at 12:47 AM, WolfRage > wrote: > I can not get this to behave in the manor that I would like. I > am trying > to have an object refereed to as CursesApp.Screen become the > already > initialized object "stdscr". To elaborate I would like it to > become that > object but to also be able to define additional methods and > properties, > so more along the lines of inherit from "stdscr". Is this even > possible? > Well I can make it equal to that object I can not add > additional methods > and properties to it? Additionally, so that I learn; where has > my > thinking been too short sited? Thank you for your help. > -- > Jordan > > CODE BELOW > > #!/usr/bin/python3 > """With thi method I can make the class "Screen" become > "stdscr" but if > I refernce any of the new methods or properties the > applications > promptly fails and notifies me that the method or property > does not > exist. Another downside of this method is I can not reference > self.Screen.* or it crashes.""" > import curses > class CursesApp: >def __init__(self, stdscr): >self.Screen(stdscr) #This is the stdscr object. > > curses.init_pair(1,curses.COLOR_BLUE,curses.COLOR_YELLOW) >#self.Screen.bkgd(' ', curses.color_pair(1)) >#self.mainLoop() > >#def mainLoop(self): >#while 1: >#self.Screen.refresh() >#key=self.Screen.getch() >#if key==ord('q'): break > >class Screen: >def __init__(self,stdscr): >self=stdscr >#self.height, self.width = self.getmaxyx() # any > reference > to these crashes >#self.offsety, self.offsetx = -self.height/2, > -self.width/2 > # any reference to these crashes >#self.curx, self.cury = 1, 1 # any reference to > these > crashes >self.clear() >self.border(0) >while 1: >self.refresh() >key=self.getch() >if key==ord('q'): break > > def main(): >cursesapp = curses.wrapper(setup) > > def setup(stdscr): >CursesApp(stdscr) > > if __name__ == '__main__': >main() > > > > CODE BELOW > > #!/usr/bin/python3 > """With this method I can make "Screen" become "stdscr" but if > I > obviously can not even define any new methods or properties. > But atleast > the references can be used through out the class with out > crashing.""" > import curses > class CursesApp: >def __init__(self, stdscr): >self.Screen=stdscr #This is the stdscr object. > > curses.init_pair(1,curses.COLOR_BLUE,curses.COLOR_YELLOW) >self.Screen.bkgd(' ', curses.color_pair(1)) >self.mainLoop() > >def mainLoop(self): >while 1: >self.Screen.refresh() >key=self.Screen.getch() >if key==ord('q'): break > > def main(): >cursesapp = curses.wrapper(setup) > > def setup(stdscr): >CursesApp(stdscr) > > if __name__ == '__main__': >main() > > ___ > Tutor maillist - Tutor@python.org > To unsubscribe or change subscription options: > http://mail.python.org/mailman/listinfo/tutor > > ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Tutor Digest, Vol 88, Issue 56
> From: Steven D'Aprano > To: Python Tutor > Subject: Re: [Tutor] Already Initialized Object Inheritance? > Message-ID: <4df898e9.5050...@pearwood.info> > Content-Type: text/plain; charset=ISO-8859-1; format=flowed > > WolfRage wrote: > > Unfortunately I am not able to inherit "stdscr" using that method. As > > Python returns with an error stating that "stdscr" is not defined. This > > error is returned at run time and by the compiler prior to actual > > execution. If you would like I can write a quick example that will > > generate the error message for that method. > > You shouldn't need to ask that question, just do it. Ahh... sorry? CODE BELOW #!/usr/bin/python3 """With this method I can make the class "Screen" become "stdscr" but if I refernce any of the new methods or properties the applications promptly fails and notifies me that the attribute does not exist.""" import curses class CursesApp: def __init__(self, stdscr): self.Screen=stdscr #This is the stdscr object. curses.init_pair(1,curses.COLOR_BLUE,curses.COLOR_YELLOW) self.Screen.bkgd(' ', curses.color_pair(1)) self.mainLoop() def mainLoop(self): while 1: self.Screen.refresh() key=self.Screen.getch() if key==ord('q'): break self.Screen.height=10 #This is the line that crashes, because it is not an attribute of "stdscr". class Screen: def __init__(self): self.height, self.width = self.getmaxyx() self.offsety, self.offsetx = -self.height/2, -self.width/2 self.curx, self.cury = 1, 1 def main(): cursesapp = curses.wrapper(setup) def setup(stdscr): CursesApp(stdscr) if __name__ == '__main__': main() CODE ABOVE > > My guess is that the error you get is a NameError. The solution to that > is to fix the name error, not to run off chasing wild geese. Object > inheritance? This has nothing to do with that! Hmm... You seem to think that I should know this automatically, but obviously I do not. Did I write the correct mailing-list? Is this not a place to learn? Exclamation points are very similar to all caps. The error is actually an attribute does not exist error, output as requested is further down in the email. Although you would think I would cause a name collision, but Python ignores the class defined as Screen; even if I initialize it, because it is already defined. So this does not cause a NameError, but it does cause a TypeError, because "self.Screen" is a "curses.curses window" which is not a callable object. The code demonstrating this error is also listed below at the end of the email. > What is stdscr? Where does it come from? How is it defined? "stdscr" is a Curses window object. Window objects in Curses are usually created with the "curses.newwin()" function. However "stdscr" is special in that it is created when "curses.initscr()" is run. "curses.initscr()" creates a window object and returns it, "stdscr", that takes up the available space in the terminal or screen. "curses.initscr()" is not present in the code because it is executed by "curses.wrapper()", as part of the terminal safe initialization process for Curses. Hopefully this answers your three questions satisfactorily. Reference: http://docs.python.org/library/curses.html > > Please copy and paste the *exact* error message you get, including the > full traceback. > CODE/ERROR OUTPUT BELOW $ python3 quick_test.py Traceback (most recent call last): File "quick_test.py", line 31, in main() File "quick_test.py", line 25, in main cursesapp = curses.wrapper(setup) File "/usr/lib/python3.2/curses/wrapper.py", line 43, in wrapper return func(stdscr, *args, **kwds) File "quick_test.py", line 28, in setup CursesApp(stdscr) File "quick_test.py", line 9, in __init__ self.mainLoop() File "quick_test.py", line 16, in mainLoop self.Screen.height=10 #This is the line that crashes, because it is not an attribute of "stdscr". AttributeError: '_curses.curses window' object has no attribute 'height' CODE/ERROR OUTPUT ABOVE > > -- > Steven CODE BELOW #!/usr/bin/python3 """With this method we cause a TypeError, because the window object is not callable.""" import curses class CursesApp: def __init__(self, stdscr): self.Screen=stdscr #This is the stdscr object. curses.init_pair(1,curses.COLOR_BLUE,curses.COLOR_YELLOW) self.Screen() #So now we will initialize "self.Scree
Re: [Tutor] Already Initialized Object Inheritance?
All, I have found a way to use __getattr__() to redirect failed calls to the variable that holds 'stdscr'. I will draw up some better potential code tomorrow, and then you can provide me feedback, for a potentially better method. Or perhaps optimized code. I think I also understand OOP a little better and realize I was making some simple silly mistakes with things like trying to call static methods versus initializing a object and thus my examples need a drastic re-work to make them make more sense. Thank you Steven and Christopher for your help so far. I should have the new code out tomorrow night. But now it is time for bed. -- Jordan ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] CPU Scheduling
On 04/27/2015 01:13 PM, Danny Yoo wrote: On 27/04/15 02:18, alex gonsalez wrote: Need help trying to implement a CPU scheduling algorithm. Can I recommend that you read this: http://www.dabeaz.com/coroutines/Coroutines.pdf About half way through it has a Excellent example of how an OS schedules processes. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
[Tutor] Integrating TDD into my current project work-flows
I would like some help integrating TDD into my current projects. My chosen TDD framework is unittest from the standard library. My system details are: Linux Mint 17.1 64-bit, Python 3.4, bzr(for version control). My projects are structured like: Project > develop > Project > Project > __main__.py tests > __main__.py I want to be able to execute my Project from a cwd of: Project/develop/Project as: Python3 -m Project That currently works. But executing my tests as: Python3 -m tests requires that test_Project.py has this hack to import the Project module: sys.path.append(os.path.join(os.path.dirname(__file__), '..')) do you consider that OK? Is there a better way? I call it a hack because every testcase file will have to have this line added to it in order to work. I am also using coverage.py and it is good but seems to be testing the coverage of my tests, which is not desired, how can I stop this behaviour. Or is it really OK. Output of running the tests: python3 -m tests Ran Main. . -- Ran 1 test in 0.001s OK Name Stmts Miss Cover Missing -- Project/Project 3 0 100% tests/test_Project 8 0 100% -- TOTAL 11 0 100% The test files: {FileName = __main__.py} # -*- coding: utf-8 -*- if __name__ == '__main__': import coverage import unittest cov = coverage.coverage() cov.start() # .. call your code .. from .test_Project import ProjectTestCase # lint:ok unittest.main(exit=False) cov.stop() cov.save() import sys cov.report(file=sys.stdout) {FileName = test_Project.py} # -*- coding: utf-8 -*- import os import sys import unittest sys.path.append(os.path.join(os.path.dirname(__file__), '..')) from Project import Project class ProjectTestCase(unittest.TestCase): def test_example(self): self.assertTrue(Project.main()) The Project Files: {FileName = __main__.py} # -*- coding: utf-8 -*- if __name__ == '__main__': from . import Project Project.main() {FileName = Project.py} # -*- coding: utf-8 -*- def main(): return True ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Integrating TDD into my current project work-flows
On 05/05/2015 10:59 AM, Oscar Benjamin wrote: My projects are structured like: Project > develop > Project > Project > __main__.py tests > __main__.py I want to be able to execute my Project from a cwd of: Project/develop/Project as: Python3 -m Project That currently works. That will only work if there is also a file __init__.py under the Project/develop/Project/Project directory (alongside the __main__.py file). Adding a __main__.py file allows the directory to be treated as a Python script e.g.: But actually there is no __init__.py in Project/develop/Project/Project/ There is only __main__.py and Project.py files. The __main__.py file imports Project.py. $ python3 Project/develop/Project/Project $ python3 Project # Assuming cwd is Project/develop/Project I tested the above on the terminal and it does not work. I get: wolfrage@wolfrage-Lemur-UltraThin ~/HomePlusWolfrage/Projects/Project/develop/Project $ python3 Project Traceback (most recent call last): File "/usr/lib/python3.4/runpy.py", line 170, in _run_module_as_main "__main__", mod_spec) File "/usr/lib/python3.4/runpy.py", line 85, in _run_code exec(code, run_globals) File "Project/__main__.py", line 4, in from . import Project SystemError: Parent module '' not loaded, cannot perform relative import The -m switch searches for a script as if it were a module using the module search path. In this case the directory containing the package Project must be on sys.path and one way to achieve this is to change directory to the Project/develop/Project directory. Then the Project folder in this directory is on sys.path. Did you perhaps mean the Project/develop/Project/Project/ directory? However a directory is not considered a package unless it contains a file __init__.py. So if the directory is on sys.path (e.g. in the cwd) AND their is an __init__.py file then you can do $ python3 -m Project and the code in __main__.py will run. Assuming you have the same setup in the Project/develop/Project/Project/tests directory (both __init__.py and __main__.py and Project is on sys.path) then you can run tests/__main__.py using the module search path as I think I may have confused you. The layout is like this: Project/develop/Project/Project Project/develop/Project/tests Thus tests is not contained in module's directory. My reasoning for this is that the tests would be shipped with my production code. I am currently undecided as to whether this is a good or bad thing. But the more that I read about testing the more it seems to be a good thing. So perhaps the best solution is to move the tests into the module's directory. Then the below information would probably work. $ python3 -m Project.tests Note that this is the same name that you would use to import from the tests package in interpreter e.g. from Project.tests import test_stuff imports from the __init__.py in the tests folder. Oscar ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Integrating TDD into my current project work-flows
On 05/04/2015 04:49 PM, Martin A. Brown wrote: Hi there, Yes, a bit ugly. Have you tried using nose? I have used a similar project development tree and use nose to run the tests. I had thought about it, but decided not too, since it was not part of the standard library. But then again, it is not like I don't know how to install additional dependencies for my projects. Here are a few sample command-lines (I'm on an opensuse-13.2 system with Python 3.4 and nose for Python-3.4, which is called 'nosetests-3.4'): nosetests-3.4 -- ./tests/ nosetests-3.4 --with-coverage -- ./tests/ nosetests-3.4 --with-coverage --cover-package=Project -- ./tests/ I like nose because it will discover any unittest and doctest testing code under the specified files/directories. It looks pretty easy to use, does it have an API like coverage and unittest so that I can write my test scripts and simply execute them rather than running commands from the terminal? I find that scripts prevent errors as compared to typing commands on the terminal. -Martin ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Integrating TDD into my current project work-flows
Update: My previous hack, has been changed. I now put: import os import sys sys.path.append(os.path.join(os.path.dirname(__file__), '..')) in the __main__.py file located under the tests/ directory and it is only needed the one time in that one file. Not sure why I was thinking I would need to do that for every test. But that now makes the tests standalone. Also I understand the benefit of coverage showing the coverage for test files too, so this is not a problem. As I am reading about TDD and unittests and the likes. I am thinking that testing from a "higher" level is better as compared to the "unit" level testing. It seems to me that in order to get the benefits of testing I need to have less test code that will actually test more of my real code. I am seeing many potential names for this concept (Blackbox Automated Testing; System Level Test; API Level Tests) and would like your inputs on it. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Integrating TDD into my current project work-flows
On 05/05/2015 06:49 PM, Alan Gauld wrote: Not better, just necessary. The two concepts are complementary. You need both. The developer primarily needs unit testing, the integrator*(who may of course be the developer in a different role) needs integration testing and the client/project manager needs system testing and acceptance testing. They are all part of a project (especially big/commercial projects) So how low level of unit testing is acceptable. My use case is the sole programmer on a team project. Their is potential for another programmer to join the ranks but that has not happened yet. Additionally the project is well under way. But Feature additions have slowed so I want to make the code less buggy, and so I am hoping to re-factor my code now. I think some unit tests could improve the end result of my re-factoring, but where to start is the toughest problem for me to solve. Especially given the time trade off that is at least initially required for unit tests. Don't underestimate the scale of testing. It is not unusual to have more test code than functional code! (although it is still the exception!) In real-world commercial projects testing (and the associated debugging) typically consumes about 25-40% of the total project budget. Baseline coding by contrast is only about 10-25%, sometimes much less. I agree I have seen this sort of budget numbers in the government project that I have been involved in. Especially once the project hits a more general life cycle/maintenance mode. So how can I make unit testing apply to my project without starting from scratch? And how low should I test(ie. every function; every class; every interface; system level)? Thank you for any insight and all of your help. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Integrating TDD into my current project work-flows
I find myself in the same mind set as this individual: http://stackoverflow.com/a/64453/4285911 It is hard to write a proper test with out me initially outlining where I am going. Perhaps I need to better understand planning and drafting a programming project before I can hope to emulate TDD. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
[Tutor] Making Doubly Linked List with Less Lines of Code.
I wrote some code recently to make a linked list of Nodes for a 2d graph, so it consists of rows and columns. Now I wanted to make the code support being doubly linked, forwards and backwards. The difficult part of this is that the links are per row and per column. But the code I think is overly bloated. I am currently working on reducing the complexity of it. If any one has the time to look at it, if you have ideas for how I can re-write it to be much smaller I would appreciate the information. If you need more code let me know, but I tried to condense it since this singular function is around 325 lines of code. Thank you. The function to make the linked list: def make_linked_lists(self): previous_row_node = None previous_col0_node = None previous_col1_node = None previous_col2_node = None previous_col3_node = None previous_col4_node = None previous_col5_node = None previous_col6_node = None previous_col7_node = None current_node = None self.tile_list = list() for row in range(0, self.rows): for col in range(0, self.cols): current_node = self.get_instance_of_id(str(col) + ',' + str(row)) self.tile_list.append(current_node) if row == 0: if col == 0: self.row0 = current_node self.col0 = current_node previous_col0_node = current_node elif col == 1: self.col1 = current_node previous_col1_node = current_node elif col == 2: self.col2 = current_node previous_col2_node = current_node elif col == 3: self.col3 = current_node previous_col3_node = current_node elif col == 4: self.col4 = current_node previous_col4_node = current_node elif col == 5: self.col5 = current_node previous_col5_node = current_node elif col == 6: self.col6 = current_node previous_col6_node = current_node elif col == 7: self.col7 = current_node previous_col7_node = current_node if previous_row_node is not None: previous_row_node.next_row_node = current_node current_node.prev_row_node = previous_row_node previous_row_node = current_node elif row == 1: if col == 0: self.row1 = current_node previous_row_node = None previous_col0_node.next_col_node = current_node current_node.prev_col_node = previous_col0_node previous_col0_node = current_node elif col == 1: previous_col1_node.next_col_node = current_node current_node.prev_col_node = previous_col1_node previous_col1_node = current_node elif col == 2: previous_col2_node.next_col_node = current_node current_node.prev_col_node = previous_col2_node previous_col2_node = current_node elif col == 3: previous_col3_node.next_col_node = current_node current_node.prev_col_node = previous_col3_node previous_col3_node = current_node elif col == 4: previous_col4_node.next_col_node = current_node current_node.prev_col_node = previous_col4_node previous_col4_node = current_node elif col == 5: previous_col5_node.next_col_node = current_node current_node.prev_col_node = previous_col5_node previous_col5_node = current_node elif col == 6: previous_col6_node.next_col_node = current_node current_node.prev_col_node = previous_col6_node previous_col6_node = current_node elif col == 7: previous_col7_node.next_col_node = current_node current_node.prev_col_node = previous_col7_node previous_col7_node = current_node if previous_row_node is not None: previous_row_node.next_row_node = current_node previous_row_node = current_node el
Re: [Tutor] Making Doubly Linked List with Less Lines of Code.
OK thanks for the rapid response, I will start rewriting the functions in this way now, and will come back with what I wind up with. Also Merry Christmas! On 12/24/2014 04:56 PM, Steven D'Aprano wrote: On Wed, Dec 24, 2014 at 04:35:06PM -0500, WolfRage wrote: I wrote some code recently to make a linked list of Nodes for a 2d graph, so it consists of rows and columns. Now I wanted to make the code support being doubly linked, forwards and backwards. The difficult part of this is that the links are per row and per column. But the code I think is overly bloated. I am currently working on reducing the complexity of it. If any one has the time to look at it, if you have ideas for how I can re-write it to be much smaller I would appreciate the information. If you need more code let me know, but I tried to condense it since this singular function is around 325 lines of code. Wow. It certainly is bloated. I don't have time to look at it in any detail right now, as it is Christmas Day here, but I'll give you a suggestion. Any time you find yourself writing more than two numbered variables, like this: previous_col0_node = None previous_col1_node = None previous_col2_node = None previous_col3_node = None previous_col4_node = None previous_col5_node = None previous_col6_node = None previous_col7_node = None you should instead think about writing a list: previous_col_nodes = [None]*8 Then, instead of code like this: if col == 0: self.col0 = current_node previous_col0_node = current_node elif col == 1: self.col1 = current_node previous_col1_node = current_node elif col == 2: self.col2 = current_node previous_col2_node = current_node etc. you can just write: for col in range(number_of_columns): self.columns[col] = current_node previous_col_nodes[col] = current_node Look for the opportunity to write code like this instead of using range: for col, the_column in enumerate(self.columns): self.columns[col] = process(the_column) Any time you write more than a trivial amount of code twice, you should move it into a function. Then, instead of: if row == 0: if col == 0: a elif col == 1: b elif col == 2: c elif col == 3: d elif col == 4: e elif row == 1: if col == 0: a elif col == 1: b elif col == 2: c elif col == 3: d elif col == 4: e elif row == 3: # same again you can write a function: def process_cell(row, col): if col == 0: a elif col == 1: b elif col == 2: c elif col == 3: d elif col == 4: e # later on for row in rows: for col in cols: process_cell(row, col) Try those suggestions, and come back to us if you still need help. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Making Doubly Linked List with Less Lines of Code.
Here is a condensed version of all of the applicable code but with out Linked List filled in, as I am preparing to re-write it. class GameTile(): def __init__(self, id, **kwargs): self.id = id class GameGrid(): def __init__(self, **kwargs): self.cols = 8 self.rows = 10 # Each variable below is a link to the head Node in the respective # row or column. self.row0 = None self.row1 = None self.row2 = None self.row3 = None self.row4 = None self.row5 = None self.row6 = None self.row7 = None self.row8 = None self.row9 = None self.col0 = None self.col1 = None self.col2 = None self.col3 = None self.col4 = None self.col5 = None self.col6 = None self.col7 = None self.skip_to_row = None self.skip_to_col = None self.tile_list = list() def make_linked_lists(self): prev_row_node = None prev_col0_node = None current_node = None for row in range(0, self.rows): for col in range(0, self.cols): for node in self.tile_list: if node.id == str(col) + ',' + str(row): current_node = node def update(self): for row in range(0, self.rows): element = None if row < 7: pass for column in range(0, self.cols): self.tile_list.append(GameTile(id=str(column) + ',' + str(row))) def print_lists(self): for node in self.tile_list: print(node.id) temp = GameGrid() temp.update() temp.make_linked_lists() temp.print_lists() ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Making Doubly Linked List with Less Lines of Code.
Thanks, definitely adding this concept into my code. And re-writing. I originally hard coded everything just to get it working... but obviously, it would have been more time efficient to have thought in these terms from the beginning. Hopefully I can learn to write code more like this to begin with, even when I just want to get something working. Reading the rest of your recommendations now. On 12/25/2014 12:15 AM, Danny Yoo wrote: Quick comment: the structure of the code here catches my eye: # Each variable below is a link to the head Node in the respective # row or column. self.row0 = None self.row1 = None self.row2 = None self.row3 = None self.row4 = None self.row5 = None self.row6 = None self.row7 = None self.row8 = None self.row9 = None It seems highly regular; the code here is maintaining a collection of row variables. Because it's so regular, you might consider using a list to represent this collection. Concretely: self.rows = [None, None, None, None, None, None, None, None, None, None] We can express this more concisely in Python as: self.row = [None] * 10 Once we have this, then we can get at any particular row through its offset. So instead of: self.row0 we say: self.row[0] The big win with a list representation is that the offset can be computed. So if we need to do an operation on each row, we might say: for i in range(10): ## ... Do something with self.row[i] And if you see the full power of this, you'll realize that this allows us to express loops to do something to _all_ the rows, expressing that action just once. Or if we need to do something for every other row, that too is not too difficult to express: for i in range(0, 10, 2): ## ... Do something with self.row[i] In contrast, doing the same thing without using an explicit container representation means that doing container-wide actions is harder to do. This is the code smell that we saw at the beginning of this post, where we see repetitive code. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Making Doubly Linked List with Less Lines of Code.
This is my most recent rendition of the code. It still needs to be improved. Below I am answering some questions that were posed. Also I think my code is currently wrong because I think the print_by functions are both printing the list the same way. Tomorrow I will fix this and improve the code. Thank you guys for your help so far. class GameTile(): def __init__(self, id, **kwargs): self.id = id self.value = None self.next_node_in_row = None self.next_node_in_col = None self.prev_node_in_row = None self.prev_node_in_col = None class GameGrid(): def __init__(self, **kwargs): self.num_of_cols = 8 self.num_of_rows = 10 # Each variable below is a list of links to the head # node in the respective row or column. self.rows = [None] * self.num_of_rows self.cols = [None] * self.num_of_cols self.skip_to_row = None self.skip_to_col = None self.tile_list = list() def make_grid_nodes(self): for row in range(0, self.num_of_rows): for column in range(0, self.num_of_cols): tile = GameTile(id=str(column) + ',' + str(row)) self.tile_list.append(tile) if column == 0: # New Head of Row self.rows[row] = tile else: prev_row.next_node_in_row = tile tile.prev_node_in_row = prev_row prev_row = tile if row == 0: # New Head of Column self.cols[column] = tile else: prev_col.next_node_in_col = tile tile.prev_node_in_col = prev_col prev_col = tile def print_by_rows(self): for col, the_column in enumerate(self.cols): print(the_column.id) if the_column.next_node_in_row is not None: node = the_column.next_node_in_row while node.next_node_in_row is not None: print(node.id) node = node.next_node_in_row def print_by_row(self): for row in self.rows: print(row.id) if row.next_node_in_row is not None: node = row.next_node_in_row while node.next_node_in_row is not None: print(node.id) node = node.next_node_in_row def print_by_col(self): for col in self.cols: print(col.id) if col.next_node_in_col is not None: node = col.next_node_in_col while node.next_node_in_col is not None: print(node.id) node = node.next_node_in_col def draw_grid(self): import time sep = '─' f = '░│' l = '◈│' row = sep + '\n│' last_col = None current_col = None val = None for node in self.tile_list: if node.value == None: val = l else: val = f current_col = node.id.split(',')[1] if last_col is None: row += val elif current_col == last_col: row += val else: row += '\n' + sep + '\n│' + val last_col = node.id.split(',')[1] row += '\n' + sep print(row) #time.sleep(1) temp = GameGrid() temp.make_grid_nodes() #temp.draw_grid() temp.print_by_row() print('BREAK Now COLUMNS') temp.print_by_col() On 12/25/2014 12:31 AM, Danny Yoo wrote: What are the _operations_ you want to support? Can you say more about this? I need to support lookups, no insertions or deletions are required. This code will be used to quickly lookup nodes, and check for specific patterns by checking the nodes values in either a row or column. The code to perform the pattern matching was already written and is fast, but I will add it to the code once the creation On 12/24/2014 04:56 PM, Steven D'Aprano wrote: Wow. It certainly is bloated. Agreed. Look for the opportunity to write code like this instead of using range: for col, the_column in enumerate(self.columns): self.columns[col] = process(the_column) This caught my eye, and I did try to implement it. But why use this instead of range? I am using Python3. I did find that enumerate is potentially faster but sometimes slower, as it depends on what is being done. Perhaps because it is considered more Pythonic? So what is your reason for this suggestion? Any time you write more than a trivial amount of code twice, you should move it into a function. Then, instead of: I agree, should have done, and need to look for these opportunities sooner. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Help on Python drop-down list options
What is the user interface that your program is using, currently? IE: QT, GTK, Tkinter, Curses, Kivy, Pygame, Or None? What is the target system on which your program runs? How are you currently viewing the mean and standard deviation results? What version of Python are you using and what is your OS? On 12/31/2014 08:49 AM, Tammy Miller wrote: Hello All, I need help on the following: I have a created a project from a csv file to calculate the mean and standard deviation. However, I would like to create a drop-down list and display the mean and standard deviation? Is there a module for that? Thank you, Tammy ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Convert string to bytes
I wrote a program to help me break out hex strings awhile ago. It was written to communicate with a Atmega 168. This is written for Python 3. Here is a snippet, see if this helps you. s4 = "28 40 7A 7C 05 00 00 34" hex_array = bytearray.fromhex(s4) print(s4) print(list(hex_array)) print(hex_array) for byte in list(hex_array): print(hex(byte)) print(bytes([byte])) On 12/31/2014 05:08 AM, shweta kaushik wrote: Hi all, I need help on this problem. I have one message packet in form of string s = '0xFE, 0x01, 0x01, 0x22, 0xFE, 0x02'. I have to send this data to MSP430 microcontroller, but it is not taking data if it is string. If I am passing this as hardcoded value s1 = 0xFE, 0x01, 0x01, 0x22, 0xFE, 0x02 then board is responding. I want to convert s as s1 using python. Please help me out to convert string in normal format for microcontroller to respond. Thanks in advance. Regards, Shweta ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Making Doubly Linked List with Less Lines of Code.
Final Code Using 2d List instead of Doubly Linked List. class GameTile(): def __init__(self, id, **kwargs): # id is (X,Y) self.id = id class GameGrid(): def __init__(self, **kwargs): self.cols = 7 self.rows = 8 # grid is 2d array as y, x ie [y][x]. self.grid = [[None] * self.rows for i in range(self.cols)] def make_grid(self): for row in range(0, self.rows): for col in range(0, self.cols): self.grid[col][row] = GameTile(id=str(row) + ',' + str(col)) def print_by_row(self): for col in range(0, self.cols): for row in range(0, self.rows): print(self.grid[col][row].id) def print_by_col(self): for row in range(0, self.rows): for col in range(0, self.cols): print(self.grid[col][row].id) def check_bounds(self, x, y): if (0 <= x < self.rows) and (0 <= y < self.cols): return True return False def lookup_node(self, x, y): if not self.check_bounds(x, y): return False return self.grid[y][x] def draw_grid(self): for col in range(0, self.cols): print(end='| ') for row in range(0, self.rows): print(self.grid[col][row].id, end=' | ') print() temp = GameGrid() temp.make_grid() temp.draw_grid() Any feedback for my code is appreciated. Thank you. On 12/31/2014 06:57 PM, Steven D'Aprano wrote: Trust me on this, there is no linked list code you can write in Python that will be faster than using a list of lists. Even in C, traversing a linked list is slower than array access, and Python is not C. OK. I do trust you. Bounds checking is easy: cell [i, j] is in bounds if this is true: (0 <= i < NUM_ROWS) and (0 <= j < NUM_COLS) Fast access to any cell is possible: array[i][j] Implemented both. from sys import getsizeof Thanks I forgot about getsizeof. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Making Doubly Linked List with Less Lines of Code.
On 01/02/2015 12:28 AM, Dave Angel wrote: On 01/01/2015 11:48 PM, WolfRage wrote: Final Code Using 2d List instead of Doubly Linked List. Please don't top-post. Instead, post your comments inline with the parts of the previous message to which you're responding. I did reply in-line, but it appears even though I selected plan-text only. Thunderbird still messed it up. Not much I can do about that. Sorry I am used to top posting. But the rest of my response was in-line even if Thunderbird messed it up. Is there a reason you doublespaced the whole thing? And why did you retype it instead of just copy/pasting it? And why lose the indentation, so nobody can actually try it without guessing at your indentation? No I did not double-space it, not in what I sent or was shown by Thunderbird. I definitely did not re-type it, I copy and pasted. But it seems that Thunderbird has a real hard time when also replying in-line to quotes. As far as the rest I will repost with just the code so that hopefully it is not messed up as I imagine that made it incredibly hard to read. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Making Doubly Linked List with Less Lines of Code.
import sys class GameTile(): def __init__(self, id, **kwargs): # id is (X,Y) self.id = id class GameGrid(): def __init__(self, **kwargs): self.cols = 8 self.rows = 8 # grid is 2d array as y, x ie [y][x]. self.grid = [[None] * self.rows for i in range(self.cols)] def make_grid(self): for row in range(0, self.rows): for col in range(0, self.cols): self.grid[col][row] = GameTile(id=str(row) + ',' + str(col)) def print_by_row(self): for col in range(0, self.cols): for row in range(0, self.rows): print(self.grid[col][row].id) def print_by_col(self): for row in range(0, self.rows): for col in range(0, self.cols): print(self.grid[col][row].id) def check_bounds(self, x, y): if (0 <= x < self.rows) and (0 <= y < self.cols): return True return False def lookup_node(self, x, y): if not self.check_bounds(x, y): return False return self.grid[y][x] def draw_grid(self): for col in range(0, self.cols): print(end='| ') for row in range(0, self.rows): print(self.grid[col][row].id, end=' | ') print() temp = GameGrid() temp.make_grid() temp.draw_grid() print(sys.getsizeof(temp.grid)) #The above code shows fine to me with indentation preserved. Plain-Text was selected in Thunderbird. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Making Doubly Linked List with Less Lines of Code.
On 01/02/2015 02:21 AM, Steven D'Aprano wrote: Fixing the mangled formatting, as best as I am able (and can be bothered). On Thu, Jan 01, 2015 at 11:48:18PM -0500, WolfRage wrote: class GameTile(): def __init__(self, id, **kwargs): # id is (X,Y) self.id = id What is the purpose of the **kwargs? It doesn't get used, it just silently ignores them. These are Kivy Buttons, when GameTile is written as a whole. But I broke it out in order to solve this specific problem. Actually, what is the purpose of this GameTile class? It has no methods apart from the constructor. That is a sign of a class that isn't pulling its weight, its not doing anything. All the other code in your program looks inside the GameTile and accesses self.id directly. This is a sure sign of a class that doesn't need to exist. It manages the on_press, on_release, and the image currently being displayed on the displayed tiles. But that is all that it does. But I still think I have to have it, since it is a button which inherits from Kivy's Button class. It may be better to give this at least a __str__ method, so if nothing else you can print it without looking inside: Excellent idea, I will add this __str__ method so that I can print it directly. class GameTile(): def __init__(self, x, y): self.x = x self.y = y def __str__(self): return "%d, %d" % (self.x, self.y) class GameGrid(): def __init__(self, **kwargs): self.cols = 7 self.rows = 8 # grid is 2d array as y, x ie [y][x]. self.grid = [[None] * self.rows for i in range(self.cols)] Why do you have GameTiles use X,Y but the grid uses the opposite order, Y,X? This is going to cause confusion. I'm already confused! Well my lack of understanding as to how to implement the 2d list resulted in the row and col count being opposite, but I see now simply re-arranging those would fix this problem and the resulting hacks in the rest of the code, as it goes back and forth. def make_grid(self): for row in range(0, self.rows): for col in range(0, self.cols): self.grid[col][row] = GameTile(id=str(row) + ',' + str(col)) No need to write range(0, Whatever), since range defaults to 0. Better to write range(Whatever). Good point. Why does the GameTile record the coordinates as strings? I would prefer something like this: def make_grid(self): for row in range(self.rows): for col in range(self.cols): self.grid[col][row] = GameTile(row, col) I did this when I was writing the previous Kivy code, the coordinates actually serve as the id which is a Kivy variable that I am able to quickly lookup via there method, but I have mostly replaced this lookup with the new 2d list lookup now and so it is no longer necessary (At least I think, I will have to see how much of my previous code relied on this functionality and then weed it out). http://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget.id although it looks strange due to the backwards ordering of col/row. Your __init__ method should automatically call make_grid. That is: def __init__(self, **kwargs): self.cols = 7 self.rows = 8 # grid is 2d array as y, x ie [y][x]. self.grid = [[None] * self.rows for i in range(self.cols)] self.make_grid() Actually, even better will be to move the self.grid = ... line out of the __init__ method, and make it part of make_grid. Since it is part of making the grid. The making of the grid was put in the update because of Kivy, literally. I did not want to delay the display of the next screen while I was building my linked list. The previous linked list code was even bigger than what I posted initially and the execution of this code took around 1-2 seconds which caused the previous screen to hang. To prevent that I called update as a task to happen after the screens had flipped. But now that the grid creation is so fast, I can do this and no delay will be experienced. def print_by_row(self): for col in range(0, self.cols): for row in range(0, self.rows): print(self.grid[col][row].id) This now becomes: def print_by_row(self): for col in range(0, self.cols): for row in range(0, self.rows): print(self.grid[col][row]) That is a cool feature with the __str__ method. haven't really learned to use the "Magic" or "special" methods yet. But will definitely start too now. since GameTiles now know how to print themselves. Likewise for this: def print_by_col(self): for row in range(0, self.rows): for col in range(0, self.cols): print(self.grid[col][row]) Another simplification here: def check_bounds(self, x, y): retu
Re: [Tutor] Making Doubly Linked List with Less Lines of Code.
Dave or Steve, what mail program do you use? It appears Thunderbird is still posting the code all messed up. Which makes it impossible to communicate effectively with the list. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Making Doubly Linked List with Less Lines of Code.
On 01/02/2015 10:37 AM, Alan Gauld wrote: I use Thunderbird for posting too, and nobody has complained yet about my code layout. My account settings are: Composition&Addressing Compose in HTML - OFF Auto quote original then "START REPLY BELOW QUOTE" My Tbird prefs are: Composition->General tab-> Send Options button Text Format set to "Convert to plain text" Plain Text domains tab -> includes python.org and gmane.org And in my Address book I have the python tutor list entry set to Prefers messages formatted as PLAIN TEXT HTH Using Alan's settings above I can already see the difference in the composition window. Reposting my code to see if it comes out correctly now. I am still applying Steve's suggestions. import sys class GameTile(): def __init__(self, col, row, **kwargs): # id is (X,Y) self.id = str(row) + ',' + str(col) self.col = col self.row = row def __str__(self): return '%d, %d' % (self.col, self.row) class GameGrid(): def __init__(self, **kwargs): self.cols = 8 self.rows = 8 self.make_grid() def make_grid(self): # grid is 2d array as x, y ie [x][y]. self.grid = [[None] * self.cols for i in range(self.rows)] for row in range(self.rows): for col in range(self.cols): self.grid[row][col] = GameTile(row=row, col=col) def print_by_row(self): for col in range(self.cols): for row in range(self.rows): print(self.grid[row][col]) def print_by_col(self): for row in range(self.rows): for col in range(self.cols): print(self.grid[row][col]) def check_bounds(self, x, y): if (0 <= x < self.rows) and (0 <= y < self.cols): return True return False def lookup_node(self, x, y): if not self.check_bounds(x, y): return False return self.grid[x][y] def draw_grid(self): for col in range(self.cols): print(end='| ') for row in range(self.rows): print(self.grid[row][col], end=' | ') print() grid = GameGrid() grid.draw() print(sys.getsizeof(grid.grid)) ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Making Doubly Linked List with Less Lines of Code.
On 01/02/2015 02:21 AM, Steven D'Aprano wrote: What is the purpose of the **kwargs? It doesn't get used, it just silently ignores them. Hopefully you got the answer for this from the previous message. Why does the GameTile record the coordinates as strings? Hopefully you got the answer for this from the previous message. Your lookup_node method returns a GameTile or False on failure: def lookup_node(self, x, y, ): if not self.check_bounds(x, y): return False return self.grid[y][x] I'm not sure about that design. I wonder whether it would be better to return None, or raise an exception. What would you suggest this code does on error, when the Node looked up is out of bounds? Latest copy of the code. I think I got every ones suggestion. import sys class GameTile(): def __init__(self, col, row, **kwargs): # id is (X,Y) self.id = str(row) + ',' + str(col) self.col = col self.row = row def __str__(self): return '%d, %d' % (self.col, self.row) class GameGrid(): def __init__(self, cols=8, rows=7, **kwargs): self.cols = cols self.rows = rows self.make_grid() def make_grid(self): # grid is 2d array as x, y ie [x][y]. self.grid = [[None] * self.cols for i in range(self.rows)] for row in range(self.rows): for col in range(self.cols): self.grid[row][col] = GameTile(row=row, col=col) def print_by_row(self): for col in self.grid: for row in col: print(row) def print_by_col(self): for row in self.grid: for col in row: print(col) def check_bounds(self, x, y): return (0 <= x < self.rows) and (0 <= y < self.cols) def lookup_node(self, x, y): if not self.check_bounds(x, y): return False return self.grid[x][y] def draw(self): for col in self.grid: print(end='| ') for row in col: print(row, end=' | ') print() grid = GameGrid(3, 3) grid.draw() print(sys.getsizeof(grid.grid)) ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Making Doubly Linked List with Less Lines of Code.
On 01/02/2015 12:08 PM, Dave Angel wrote: class GameGrid(): def __init__(self, cols=8, rows=7, **kwargs): You probably want to reverse the order of the parameters; you've got almost everything else row-major You are right, a lot of inconsistency that will lead to errors latter on. I need to make everything column-major. So that the grid (x,y) are the same to grid (col,row). I have too much confusion throughout my code, so I will correct the code. Since both stages are being done in the same method, you don't need the part which initializes to None. def make_grid(self): # grid is 2d array as x, y ie [x][y]. self.grid = [] for row_num in range(self.rows): self.grid.append( [GameTile(row=row_num, col=col_num) for col_num in range(self.cols)] ) Implemented the second version. def print_by_row(self): for col in self.grid: for row in col: print(row) This cannot work. The items in self.grid are rows. Calling one of them col doesn't make it so. In other words, the method as written will do exactly what print_by_col() does. Good point, I did not read the output thoroughly enough to catch this. Try the following: def print_by_row(self): for col_number in range(self.cols): for row in self.grid: print(row[col_number]) Implemented. This one should work fine. But one of the names could be improved: def print_by_col(self): for row in self.grid: for tile in row: print(tile) Thanks, improved. All code untested. i hope it helps. Definitely. Thanks. I have updated the code and I realized that all of my earlier confusion was even greater, so I have also added comments to make things make sense. Now the print_by_ methods work as I envision and in accordance with the comments. import sys class GameTile(): def __init__(self, col, row, **kwargs): # id is grid (X,Y) which is equal to grid (col,row) self.id = str(col) + ',' + str(row) self.col = col self.row = row def __str__(self): return '%d, %d' % (self.col, self.row) class GameGrid(): def __init__(self, cols=8, rows=7, **kwargs): self.cols = cols self.rows = rows self.make_grid() def make_grid(self): # grid is 2d array as x, y ie [x][y]. self.grid = [] for row_num in range(self.rows): self.grid.append([GameTile(col=col_num, row=row_num) for col_num in range(self.cols)]) def print_by_col(self): # As in going down the column assuming we started at the top. for col_num in range(self.cols): for row in self.grid: print(row[col_num]) def print_by_row(self): # As in going right across the row assuming we started at the left. for row in self.grid: for node in row: print(node) def check_bounds(self, x, y): return (0 <= x < self.rows) and (0 <= y < self.cols) def lookup_node(self, x, y): if not self.check_bounds(x, y): return False return self.grid[x][y] def draw(self): for col in self.grid: print(end='| ') for row in col: print(row, end=' | ') print() grid = GameGrid(3, 3) grid.draw() print(sys.getsizeof(grid.grid)) print() grid.print_by_row() print() grid.print_by_col() ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Making Doubly Linked List with Less Lines of Code.
Tutors, on my next iteration I am going to add more of the game code. Since I am no longer using Doubly Linked Lists, should I create a new thread? Or should I continue with this thread to continue with the established context? ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
[Tutor] Improving My Simple Game Code for Speed, Memory and Learning
First an explanation of how the game works: The game is a simple matching game but with a twist. Instead of matching a straight 3 in a row, we have some rules that only certain combinations will result in an elimination. In general 2 of the same value in a row with with 1 of 2 other possible values will eliminate all three nodes. Eliminations can occur either horizontally or vertically but not diagonally. Each tile has a value now, that value is used when evaluating the rules. Currently there are only 5 allowed values of 0-4 although more could be added later, so any solution needs to be expandable. These are the basic rules that allow for an elimination to occur(values are put in quotes to distinguish values): 2 "5"s followed or proceeded by a "19" will eliminate all 3 nodes. 2 "5"s followed or proceeded by an "11" will eliminate all 3 nodes. 2 "6"s followed or proceeded by a "5" will eliminate all 3 nodes. 2 "6"s followed or proceeded by a "19" will eliminate all 3 nodes. 2 "11"s followed or proceeded by a "6" will eliminate all 3 nodes. 2 "11"s followed or proceeded by a "20" will eliminate all 3 nodes. 2 "19"s followed or proceeded by a "20" will eliminate all 3 nodes. 2 "19"s followed or proceeded by an "11" will eliminate all 3 nodes. 2 "20"s followed or proceeded by a "6" will eliminate all 3 nodes. 2 "20"s followed or proceeded by a "5" will eliminate all 3 nodes. The main focus of the code is the find_eliminations method. I think its implementation is smart since it uses a math trick, but then again I wrote it. My math trick works by first finding 2 matching nodes next to each other out of every 3 nodes, then adding the values of all 3 nodes together and checking for specific totals. None of the possible totals overlap. Here is the code: import random class GameTile(): def __init__(self, value, col, row, **kwargs): # id is grid (X,Y) which is equal to grid (col,row) self.id = str(col) + ',' + str(row) self.col = col self.row = row self.value = value self.eliminated = False def __str__(self): #return '%d, %d' % (self.col, self.row) if len(str(self.value)) == 1: return ' ' + str(self.value) return str(self.value) class GameGrid(): def __init__(self, cols=8, rows=7, **kwargs): self.cols = cols self.rows = rows self.make_grid() def make_grid(self): # grid is 2d array as x, y ie [x][y]. self.grid = [] for row_num in range(self.rows): self.grid.append([GameTile(value=random.choice([5, 6, 11, 19, 20]), col=col_num, row=row_num) for col_num in range(self.cols)]) def print_by_col(self): # As in going down the column assuming we started at the top. for col_num in range(self.cols): for row_list in self.grid: print(row_list[col_num]) def print_by_row(self): # As in going right across the row assuming we started at the left. for row in self.grid: for node in row: print(node) def check_bounds(self, x, y): return (0 <= x < self.rows) and (0 <= y < self.cols) def lookup_node(self, x, y): if not self.check_bounds(x, y): return False return self.grid[x][y] def draw(self): for col in self.grid: print(end='| ') for node in col: print(node, end=' | ') print() def find_eliminations(self): # I define 3 variables for holding the 3 nodes/tiles that I am # currently checking to see if an elimination possibility exists. # It uses a math trick to check for elimination by adding the values # and checking for specific totals. None of the possible totals overlap. #First Down the columns. for col_num in range(self.cols): first = None second = None third = None for row_list in self.grid: if row_list[col_num].row == 0: first = row_list[col_num] elif row_list[col_num].row == 1: second = row_list[col_num] elif row_list[col_num].row == 2: third = row_list[col_num] else: first = second second = third third = row_list[col_num] if third is not None: self.check_total_and_eliminate(first, second, third) # Now across the rows. for row in self.grid: first = None second = None third = None for node in row: if node.col == 0: first = node elif node.col == 1: second = node elif node.col == 2: third = node else: first =
[Tutor] Improving My Simple Game Code for Speed, Memory and Learning
Python3.4+ Linux Mint 17.1 but the code will be cross platform (Mobile, Windows, Linux, OSX). First an explanation of how the game works: The game is a simple matching game but with a twist. Instead of matching a straight 3 in a row, we have some rules that only certain combinations will result in an elimination. In general 2 of the same value in a row with with 1 of 2 other possible values will eliminate all three nodes. Eliminations can occur either horizontally or vertically but not diagonally. Each tile has a value now, that value is used when evaluating the rules. Currently there are only 5 allowed values of 0-4 although more could be added later, so any solution needs to be expandable. These are the basic rules that allow for an elimination to occur(values are put in quotes to distinguish values): 2 "5"s followed or proceeded by a "19" will eliminate all 3 nodes. 2 "5"s followed or proceeded by an "11" will eliminate all 3 nodes. 2 "6"s followed or proceeded by a "5" will eliminate all 3 nodes. 2 "6"s followed or proceeded by a "19" will eliminate all 3 nodes. 2 "11"s followed or proceeded by a "6" will eliminate all 3 nodes. 2 "11"s followed or proceeded by a "20" will eliminate all 3 nodes. 2 "19"s followed or proceeded by a "20" will eliminate all 3 nodes. 2 "19"s followed or proceeded by an "11" will eliminate all 3 nodes. 2 "20"s followed or proceeded by a "6" will eliminate all 3 nodes. 2 "20"s followed or proceeded by a "5" will eliminate all 3 nodes. The main focus of the code is the find_eliminations method. I think its implementation is smart since it uses a math trick, but then again I wrote it. My math trick works by first finding 2 matching nodes next to each other out of every 3 nodes, then adding the values of all 3 nodes together and checking for specific totals. None of the possible totals overlap. Here is the code: import random class GameTile(): def __init__(self, value, col, row, **kwargs): # id is grid (X,Y) which is equal to grid (col,row) self.id = str(col) + ',' + str(row) self.col = col self.row = row self.value = value self.eliminated = False def __str__(self): #return '%d, %d' % (self.col, self.row) if len(str(self.value)) == 1: return ' ' + str(self.value) return str(self.value) class GameGrid(): def __init__(self, cols=8, rows=7, **kwargs): self.cols = cols self.rows = rows self.make_grid() def make_grid(self): # grid is 2d array as x, y ie [x][y]. self.grid = [] for row_num in range(self.rows): self.grid.append([GameTile(value=random.choice([5, 6, 11, 19, 20]), col=col_num, row=row_num) for col_num in range(self.cols)]) def print_by_col(self): # As in going down the column assuming we started at the top. for col_num in range(self.cols): for row_list in self.grid: print(row_list[col_num]) def print_by_row(self): # As in going right across the row assuming we started at the left. for row in self.grid: for node in row: print(node) def check_bounds(self, x, y): return (0 <= x < self.rows) and (0 <= y < self.cols) def lookup_node(self, x, y): if not self.check_bounds(x, y): return False return self.grid[x][y] def draw(self): for col in self.grid: print(end='| ') for node in col: print(node, end=' | ') print() def find_eliminations(self): # I define 3 variables for holding the 3 nodes/tiles that I am # currently checking to see if an elimination possibility exists. # It uses a math trick to check for elimination by adding the values # and checking for specific totals. None of the possible totals overlap. #First Down the columns. for col_num in range(self.cols): first = None second = None third = None for row_list in self.grid: if row_list[col_num].row == 0: first = row_list[col_num] elif row_list[col_num].row == 1: second = row_list[col_num] elif row_list[col_num].row == 2: third = row_list[col_num] else: first = second second = third third = row_list[col_num] if third is not None: self.check_total_and_eliminate(first, second, third) # Now across the rows. for row in self.grid: first = None second = None third = None for node in row: if node.col == 0: first = node elif node.col == 1: second = node elif n
Re: [Tutor] Improving My Simple Game Code for Speed, Memory and Learning
On 01/02/2015 10:21 PM, Dave Angel wrote: This code is way too complex for what it accomplishes. See below. Yes, that it why it needs to be optimized. It is unfortunate that my first goes at many tasks are not the most efficient. But hopefully that will get better as I learn from all of you. If the self.rows is 3, this is equivalent to just: first, second, third = row If the self.rows is larger, it's equivalent to: first, second, third = row[p: p+3] for some value of p if third is not None: self.check_total_and_eliminate(first, second, third) But even better, let the method check_total_and_eliminate take a slice as its argument. self.check-total_and_eliminate(row[p: p+3]) I was able to implement this for the rows, but I was not able yet to get it to work with the column code, at least not before I went to sleep last night. Here is what I did for the method find_eliminations, now called find_eliminations2. def find_eliminations2(self): #First Down the columns. i = 0 for col_num in range(self.cols): for row_list in self.grid: try: # row_list[col_num] first, second, third = row_list[i: i + 3] print(first, second, third, sep=' | ') # The print above is not giving me the nodes down # each column as I would expect. # The above print is one of many tries. Will have # to keep trying. #self.check_total_and_eliminate(row_list[i: i + 3]) i += 1 except ValueError: i = 0 break # Now across the rows. i = 0 for row in self.grid: for node in row: try: self.check_total_and_eliminate(row[i: i + 3]) i += 1 except ValueError: i = 0 break # Set all eliminated nodes to a value of 0. for col in self.grid: for node in col: if node.eliminated is True: node.eliminated = False node.value = 0 def check_total_and_eliminate(self, slices): first, second, third = slices total = None if first.value == second.value: total = first.value + second.value + third.value elif second.value == third.value: total = first.value + second.value + third.value if total == 17 or total == 21 or total == 28 or total == 29 or \ total == 31 or total == 42 or total == 45 or total == 46 \ or total == 49 or total == 58: first.eliminated = True second.eliminated = True third.eliminated = True This doesn't come close to implementing the test you describe above. For example, a total of 29 could be your first case, 5,5,19. But it could also be 4,4,21. Or 6,6,17. Etc. Sorry I did not fully explain myself. The test case could not be 4,4,21 because I made a list of acceptable numbers and only acceptable numbers are allowed. Actually it is a table of letters on the top and side, the letters on the top occur once in the sequence, the letters on the side occur twice in the sequence. Each letter is representative of my earlier values. The table resolves all of the possible outcomes or totals from each sequence, allowing me to detect every possibility. |B |N |F |H |W |E |Z |X |Y *1 B|0 |5 |6 |11 |19 |20 |52 |61 |67 N|10 |15 |16 |21 |29 |30 |62 |71 |77 F|12 |17 |18 |23 |31 |32 |64 |73 |79 H|22 |27 |28 |33 |41 |42 |74 |83 |89 W|38 |43 |44 |49 |57 |58 |90 |99 |105 E|40 |45 |46 |51 |59 |60 |92 |101|107 Z|104|109|110|115|123|124|156|165|171 X|122|127|128|133|141|142|174|183|189 Y|134|139|140|145|153|154|186|195|201 *2 B=0 N=5 F=6 H=11 W=19 E=20 Z=52 X=61 Y=67 NNH=21 | NNW=29 FFN=17 | FFW=31 HHF=28 | HHE=42 WWE=58 | WWH=49 EEF=46 | EEN=45 I suggest instead that you compare the values against a table of interesting values. If you make your table a list of 3-tuples, it can be searched simply by: if tuple(nodes) in table: do-something I definitely want to improve the code so if there is a better way that is expandable then I would definitely like to implement it. So you don't need the separate variables first, second, and third at all. SNIP for what you've described so far, it might be convenient to store the board and its transposed equivalent. Then search the one for columns, and the other for rows. That's a later optimization, but it might save time getting the more complicated parts figured out. OK can you give me an example of how this would go. On to reading and answering the next emails. ___ Tutor maillist - Tutor@python.org To unsub
Re: [Tutor] Improving My Simple Game Code for Speed, Memory and Learning
On 01/03/2015 06:58 AM, Dave Angel wrote: My error. Since nodes are GameTile objects, not values, converting to a tuple is a little trickier: values = tuple( [node.value for node in nodes] ) if values in table: do-something I will try an implement this after I see what values winds up yielding. For example, print_by_col would look just like print_by_row, except that it would start with self.transposed_grid The only real assumption needed for this simplification is that once the grid is set up, you never create any more GameTile objects, just manipulate the existing rectangle of objects. To transpose a grid, you want to use the zip() function. self.transposed_grid = zip(*self.grid) Thanks for the example of making the transposed_grid. I will implement this. Also your assumption is correct, once the grid is created it never gets changed as far as it's structure, only the game tiles with in are manipulated, and at that we just change there appearance and value. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Improving My Simple Game Code for Speed, Memory and Learning
On 01/03/2015 10:09 AM, Steven D'Aprano wrote: On Fri, Jan 02, 2015 at 09:00:22PM -0500, WolfRage wrote: Python3.4+ Linux Mint 17.1 but the code will be cross platform (Mobile, Windows, Linux, OSX). First an explanation of how the game works: The game is a simple matching game but with a twist. Instead of matching a straight 3 in a row, we have some rules that only certain combinations will result in an elimination. In general 2 of the same value in a row with with 1 of 2 other possible values will eliminate all three nodes. Do you mean "1 of 2" or "1 or 2"? 1 of 2. Eliminations can occur either horizontally or vertically but not diagonally. Each tile has a value now, that value is used when evaluating the rules. Currently there are only 5 allowed values of 0-4 although more could be added later, so any solution needs to be expandable. Okay, so the values are 0, 1, 2, 3, and 4. This doesn't match your code belong. Is the code wrong or your description? My description was wrong, I am sorry I had started to simplify my code when I was first writing this, but realized that ruined my algorithm for finding matches.That is probably where I confused Dave. These are the basic rules that allow for an elimination to occur(values are put in quotes to distinguish values): 2 "5"s followed or proceeded by a "19" will eliminate all 3 nodes. [...] Since neither 5 nor 19 is a possible value, this can never apply. Sorry again, these are actually the correct values. But my earlier mistake misleads on this section that is actually correct. All the other rules you give include values greater than 4, and likewise can never apply. That means that no eliminations are ever possible. I think your description needs some work :-) Yes. Sorry. Let me re-do that. First an explanation of how the game works: The game is a simple matching game but with a twist. Instead of matching a straight 3 in a row, we have some rules that only certain combinations will result in an elimination. In general 2 of the same value in a row with with 1 of 2 other possible values will eliminate all three nodes. Eliminations can occur either horizontally or vertically but not diagonally. Each tile has a value now, that value is used when evaluating the rules. Currently there are only 5 allowed values of [5, 6, 11, 19, 20] although more could be added [52, 61, 67, etc] later, so any solution needs to be expandable. The remainder of the explanation was correct. Sorry about that. class GameTile(): [...] def __str__(self): #return '%d, %d' % (self.col, self.row) if len(str(self.value)) == 1: return ' ' + str(self.value) return str(self.value) Eliminate comments which no longer apply. Don't use them for keeping old, obsolete or wrong code. OK, good point, I should be using my bzr revision control. This method can be better written like this: def __str__(self): return "%2d" % self.value I was switching between the 2 implementations of __str__ when I was testing some new code, but now need. I will just make it concrete and then directly request any other values. class GameGrid(): def __init__(self, cols=8, rows=7, **kwargs): self.cols = cols self.rows = rows self.make_grid() def make_grid(self): # grid is 2d array as x, y ie [x][y]. self.grid = [] for row_num in range(self.rows): self.grid.append([GameTile(value=random.choice([5, 6, 11, 19, 20]), col=col_num, row=row_num) for col_num in range(self.cols)]) That's rather gnarly code. If you're going to do that, it's probably nice to use a temporary variable to clarify your intention: for row_num in range(self.rows): row = [GameTile( value=random.choice([5, 6, 11,19, 20]), col=col_num, row=row_num) for col_num in range(self.cols) ] self.grid.append(row) Which is still pretty gnarly. You only have three arguments to GameTile, why do you need to use keyword arguments? This is neater and less noisy, although it does require you get the order right: I don't need them. Just hadn't settled on the order of them. But I will eliminate the requirement for the keyword arguments. # untested for row_num in range(self.rows): row = [GameTile(row_num, col_num, random.choice([5, 6, 11,19, 20]) for col_num in range(self.cols) ] self.grid.append(row) Even better: for row_num in range(self.rows): self.make_row(row_num) def make_row(self, row_num): values = self.allowed_values # [5, 6, 11,19, 20] row = [GameTile(row_num, col_num, random.choice(values) for col_num in ran
Re: [Tutor] Improving My Simple Game Code for Speed, Memory and Learning
On 01/03/2015 06:58 AM, Dave Angel wrote: self.transposed_grid = zip(*self.grid) zip() sounds confusing. But I am going to try this and see what it gives me. But Somehow I think it will require me to understand yield, which I still do not totally get how to use. Also from the documentation, will this work on my 2d List given that the lengths of the lists may not be the same? IE: 4 columns and 8 Rows. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Improving My Simple Game Code for Speed, Memory and Learning
On 01/03/2015 06:58 AM, Dave Angel wrote: To transpose a grid, you want to use the zip() function. self.transposed_grid = zip(*self.grid) I see this gives me a list that is the column. Thus it solves the column iteration problem, because now I can feed it to my checking and elimination functions that take a slice. Thanks! Implementing now. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Improving My Simple Game Code for Speed, Memory and Learning
On 01/03/2015 04:42 PM, Dave Angel wrote: On 01/03/2015 04:22 PM, WolfRage wrote: On 01/03/2015 06:58 AM, Dave Angel wrote: To transpose a grid, you want to use the zip() function. self.transposed_grid = zip(*self.grid) I see this gives me a list that is the column. Thus it solves the column iteration problem, because now I can feed it to my checking and elimination functions that take a slice. Thanks! Implementing now. I suspect you want instead: self.transposed_grid = list( zip(*self.grid) ) in Python 3.4. zip gives an iterable for python 3.x, while it gave a list in python 2.x This is what I meant by "untested." OK, I will try that implementation next. But I think this currently works well. Here is the latest iteration of my code. import random class GameTile(): def __init__(self, col, row, values=None, value=None, **kwargs): # values is not required because the value can be directly set. # This is to support a future feature that will allow me to build a # board off of a list. # id is grid (X,Y) which is equal to grid (col,row) self.id = str(col) + ',' + str(row) self.col = col self.row = row if value is None: value = random.choice(values) self.value = value self.eliminated = False def __str__(self): return "%2d" % self.value class GameGrid(): def __init__(self, cols=8, rows=7, **kwargs): if cols < 3 or rows < 3: raise ValueError("Minimum board size is 3x3! %sx%s is too small." % (cols, rows)) self.cols = cols self.rows = rows self.values = [5, 6, 11, 19, 20] self.make_grid() def make_grid(self): # grid is 2d array as x, y ie [x][y]. self.grid = [] for row_num in range(self.rows): # Do you still think this needs to be broken into a smaller method? row = [GameTile(row_num, col_num, self.values) for col_num in range(self.cols)] self.grid.append(row) self.transposed_grid = zip(*self.grid) def draw(self): for col in self.grid: print(end='| ') for node in col: print(node, end=' | ') print() def find_eliminations(self): #First Down the columns. i = 0 for col_list in self.transposed_grid: while True: try: if self.check_total(col_list[i: i + 3]): self.eliminate(col_list[i: i + 3]) i += 1 except ValueError: i = 0 break # Now across the rows. for row_list in self.grid: while True: try: if self.check_total(row_list[i: i + 3]): self.eliminate(row_list[i: i + 3]) i += 1 except ValueError: i = 0 break # Set all eliminated nodes to a value of 0. for col in self.grid: for node in col: if node.eliminated is True: node.eliminated = False node.value = 0 def check_total(self, slices): first, second, third = slices if first.value == second.value or second.value == third.value: total = first.value + second.value + third.value return total in (17, 21, 28, 29, 31, 42, 45, 46, 49, 58) def eliminate(self, slices): first, second, third = slices first.eliminated = True second.eliminated = True third.eliminated = True def drop_floating_nodes(self): pass # Now we can used the transposed_grid! grid = GameGrid(4, 8) grid.draw() grid.find_eliminations() print('After Eliminations') grid.draw() ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Improving My Simple Game Code for Speed, Memory and Learning
On 01/03/2015 04:42 PM, Dave Angel wrote: self.transposed_grid = list( zip(*self.grid) ) This results in the same thing with or with out the list() wrapper. Using Python 3.4.0 (default, Apr 11 2014, 13:05:11) [GCC 4.8.2] on linux ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Improving My Simple Game Code for Speed, Memory and Learning
On 01/03/2015 06:46 PM, Steven D'Aprano wrote: On Sat, Jan 03, 2015 at 06:10:31PM -0500, WolfRage wrote: On 01/03/2015 04:42 PM, Dave Angel wrote: self.transposed_grid = list( zip(*self.grid) ) This results in the same thing with or with out the list() wrapper. Using Python 3.4.0 (default, Apr 11 2014, 13:05:11) [GCC 4.8.2] on linux I don't think so. Perhaps you need to look a little more closely? py> grid = [(1,2), (3,4), (5,6)] py> zip(*grid) py> list(zip(*grid)) [(1, 3, 5), (2, 4, 6)] Zip objects are not lists, although they can often (but not always) be used where you are expecting a list. Yes, you are correct. I was to naive, the result of both work the same in my code. But they are of different types. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Improving My Simple Game Code for Speed, Memory and Learning
On 01/05/2015 06:21 PM, Danny Yoo wrote: SNIP if total in (17, 21, 28, ...): Implemented, thanks. SNIP The other comment I'd make is to start thinking about how you'd _test_ your program automatically. SNIP You are right, I should. But I am fighting with myself on this topic. I have been fighting myself for some time. As it seems the test slow me down. I am sure latter they may speed me up, but then again I am still a relatively new programmer and so my code is very fluid to the situation at hand, so tests for immature code seems like a bad idea. Still you are right. Now I am having problem implementing a way to drop the zero values to the bottom of the grid. I need to look at more of the column at once possibly all of it, or remember where I was dropping. This is my latest code any help would be appreciated. import random class GameTile(): def __init__(self, col, row, values=None, value=None, **kwargs): # values is not required because the value can be directly set. # This is to support a future feature that will allow me to build a # board off of a list. # id is grid (X,Y) which is equal to grid (col,row) self.id = str(col) + ',' + str(row) self.col = col self.row = row if value is None: value = random.choice(values) self.value = value self.eliminated = False def __str__(self): return "%2d" % self.value class GameGrid(): def __init__(self, cols=8, rows=7, **kwargs): if cols < 3 or rows < 3: raise ValueError("Minimum board size is 3x3! %sx%s is too small." % (cols, rows)) self.cols = cols self.rows = rows self.values = [5, 6, 11, 19, 20] self.make_grid() def make_grid(self): # grid is 2d array as x, y ie [x][y]. self.grid = [] for row_num in range(self.rows): # Do you still think this needs to be broken into a smaller method? row = [GameTile(row_num, col_num, self.values) for col_num in range(self.cols)] self.grid.append(row) self.transposed_grid = list(zip(*self.grid)) def draw(self): for col in self.grid: print(end='| ') for node in col: print(node, end=' | ') print() def draw_by_id(self): for col in self.grid: print(end='| ') for node in col: print(node.id, end=' | ') print() def find_eliminations(self): #First Down the columns. i = 0 for col_list in self.transposed_grid: while True: try: if self.check_total(col_list[i: i + 3]): self.eliminate(col_list[i: i + 3]) i += 1 except ValueError: i = 0 break # Now across the rows. for row_list in self.grid: while True: try: if self.check_total(row_list[i: i + 3]): self.eliminate(row_list[i: i + 3]) i += 1 except ValueError: i = 0 break # Set all eliminated nodes to a value of 0. for col in self.grid: for node in col: if node.eliminated is True: node.eliminated = False node.value = 0 def check_total(self, slices): first, second, third = slices if first.value == second.value or second.value == third.value: total = first.value + second.value + third.value return total in (17, 21, 28, 29, 31, 42, 45, 46, 49, 58) def eliminate(self, slices): first, second, third = slices first.eliminated = True second.eliminated = True third.eliminated = True def drop_floating_nodes0(self): i = self.rows # first_zero_row serves as memory for how far to drop non-zero values first_zero_row = None for col_list in self.transposed_grid: while True: low, high = col_list[i - 2: i] # Goes Up the Rows if high.value == 0 and low.value != 0: if first_zero_row is None: high.value = low.value low.value = 0 first_zero_row = low else: first_zero_row.value = low.value low.value = 0 high.value = 0 i -= 1 if i == 1: i = self.rows first_zero_row = None break def drop_floating_nodes1(self): i = 0 for col_list in self.transposed_grid: while True: try: low,
Re: [Tutor] Improving My Simple Game Code for Speed, Memory and Learning
I had an issue in my logic and again my named variables provided for confusion, so I had to add some comments to clarify. I got much closer by editing my code like this: def drop_floating_nodes0(self): i = self.rows # first_zero_row serves as memory for how far to drop non-zero values first_zero_row = None for col_list in self.transposed_grid: while True: # Low is on Top, High is on Bottom low, high = col_list[i - 2: i] # Goes Up the Rows if high.value == 0: if low.value != 0: if first_zero_row is None: high.value = low.value low.value = 0 first_zero_row = low else: first_zero_row.value = low.value low.value = 0 high.value = 0 first_zero_row = low else: if first_zero_row is None: first_zero_row = high i -= 1 if i == 1: i = self.rows first_zero_row = None break But it still fails as you can see here from the output: | 20 | 19 | 11 | 20 | | 11 | 5 | 5 | 11 | | 19 | 5 | 11 | 11 | | 19 | 20 | 20 | 5 | | 11 | 19 | 19 | 11 | | 20 | 6 | 6 | 11 | | 19 | 11 | 5 | 20 | | 11 | 20 | 11 | 20 | After Eliminations | 20 | 0 | 11 | 0 | | 0 | 0 | 0 | 0 | | 0 | 0 | 11 | 0 | | 0 | 0 | 0 | 0 | | 0 | 0 | 0 | 0 | | 20 | 6 | 6 | 0 | | 19 | 11 | 5 | 0 | | 11 | 20 | 11 | 20 | After Drops | 0 | 0 | 0 | 0 | | 0 | 0 | 0 | 0 | | 0 | 0 | 11 | 0 | | 0 | 0 | 0 | 0 | | 20 | 0 | 11 | 0 | | 20 | 6 | 6 | 0 | | 19 | 11 | 5 | 0 | | 11 | 20 | 11 | 20 | ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Improving My Simple Game Code for Speed, Memory and Learning
Ok, now the code works as expected to drop the non zero values. But I think there exist an error in the naming and display of the col and row variables at least from with in the GameTile() class, looking into that now. All Suggestions Welcome! Thank You All. import random class GameTile(): def __init__(self, col, row, values=None, value=None, **kwargs): # values is not required because the value can be directly set. # This is to support a future feature that will allow me to build a # board off of a list. # id is grid (X,Y) which is equal to grid (col,row) self.id = str(col) + ',' + str(row) self.col = col self.row = row if value is None: value = random.choice(values) self.value = value self.eliminated = False def __str__(self): return "%2d" % self.value class GameGrid(): def __init__(self, cols=8, rows=7, **kwargs): if cols < 3 or rows < 3: raise ValueError("Minimum board size is 3x3! %sx%s is too small." % (cols, rows)) self.cols = cols self.rows = rows self.values = [5, 6, 11, 19, 20] self.make_grid() def make_grid(self): # grid is 2d array as x, y ie [x][y]. self.grid = [] for row_num in range(self.rows): # Do you still think this needs to be broken into a smaller method? row = [GameTile(row_num, col_num, self.values) for col_num in range(self.cols)] self.grid.append(row) self.transposed_grid = list(zip(*self.grid)) def draw(self): for col in self.grid: print(end='| ') for node in col: print(node, end=' | ') print() def draw_by_id(self): for col in self.grid: print(end='| ') for node in col: print(node.id, end=' | ') print() def find_eliminations(self): #First Down the columns. i = 0 for col_list in self.transposed_grid: while True: try: if self.check_total(col_list[i: i + 3]): self.eliminate(col_list[i: i + 3]) i += 1 except ValueError: i = 0 break # Now across the rows. for row_list in self.grid: while True: try: if self.check_total(row_list[i: i + 3]): self.eliminate(row_list[i: i + 3]) i += 1 except ValueError: i = 0 break # Set all eliminated nodes to a value of 0. for col in self.grid: for node in col: if node.eliminated is True: node.eliminated = False node.value = 0 def check_total(self, slices): first, second, third = slices if first.value == second.value or second.value == third.value: total = first.value + second.value + third.value return total in (17, 21, 28, 29, 31, 42, 45, 46, 49, 58) def eliminate(self, slices): first, second, third = slices first.eliminated = True second.eliminated = True third.eliminated = True def drop_floating_nodes0(self): i = self.rows # first_zero_row serves as memory for how far to drop non-zero values first_zero_row = None for col_list in self.transposed_grid: while True: # Low is on Top, High is on Bottom low, high = col_list[i - 2: i] # Goes Up the Rows if high.value == 0: if low.value != 0: if first_zero_row is None: high.value = low.value low.value = 0 first_zero_row = low else: first_zero_row.value = low.value low.value = 0 try: row = first_zero_row.row col = first_zero_row.col -1 first_zero_row = self.grid[col][row] except: i = self.rows first_zero_row = None break else: if first_zero_row is None: first_zero_row = high i -= 1 if i == 1: i = self.rows first_zero_row = None break def drop_floating_nodes1(self): i = 0 for col_list in self.transposed_grid: while True: try: low, h
Re: [Tutor] Improving My Simple Game Code for Speed, Memory and Learning
So I was write as I suspected; the grid is not actually being built like I thought it was. Sure the ID's print fine but when the grid positions are procedurally accessed the program fails with IndexError. python3 test1.py | 19 | 5 | 5 | 5 | | 11 | 6 | 19 | 11 | | 6 | 6 | 11 | 19 | | 11 | 20 | 6 | 5 | | 11 | 5 | 20 | 5 | | 20 | 20 | 11 | 11 | | 19 | 19 | 5 | 5 | | 11 | 19 | 19 | 5 | After Eliminations | 0 | 0 | 0 | 5 | | 11 | 0 | 19 | 11 | | 0 | 0 | 11 | 0 | | 0 | 20 | 6 | 0 | | 0 | 5 | 20 | 0 | | 0 | 0 | 0 | 0 | | 19 | 0 | 0 | 0 | | 0 | 0 | 0 | 0 | broke 0 5 0 6 broke 1 6 1 7 broke 2 6 2 7 broke 3 6 3 7 After Drops | 0 | 0 | 0 | 5 | | 0 | 0 | 19 | 0 | | 0 | 0 | 11 | 0 | | 0 | 20 | 6 | 0 | | 0 | 0 | 0 | 0 | | 0 | 0 | 0 | 0 | | 11 | 0 | 0 | 0 | | 19 | 5 | 20 | 11 | Normal | 0,0 | 1,0 | 2,0 | 3,0 | | 0,1 | 1,1 | 2,1 | 3,1 | | 0,2 | 1,2 | 2,2 | 3,2 | | 0,3 | 1,3 | 2,3 | 3,3 | | 0,4 | 1,4 | 2,4 | 3,4 | | 0,5 | 1,5 | 2,5 | 3,5 | | 0,6 | 1,6 | 2,6 | 3,6 | | 0,7 | 1,7 | 2,7 | 3,7 | Procedurally # The first printed pair is the id, the second pair in parentheses is # the procedurally accessed id, which should be all ordered as (column, # row) | 0,0 (0,0) | 1,0 (0,1) | 2,0 (0,2) | 3,0 (0,3) | Traceback (most recent call last): File "test1.py", line 186, in grid.draw_by_id_proc() File "test1.py", line 75, in draw_by_id_proc print(self.grid[col_num][row_num].id, '(' + str(col_num) + ',' + str(row_num) + ')', end=' | ') IndexError: list index out of range I am attempting to fix it now. Any help is appreciated. #Code Below import random class GameTile(): def __init__(self, col, row, values=None, value=None, **kwargs): # values is not required because the value can be directly set. # This is to support a future feature that will allow me to build a # board off of a list. # id is grid (X,Y) which is equal to grid (col,row) self.id = str(col) + ',' + str(row) self.col = col self.row = row if value is None: value = random.choice(values) self.value = value self.eliminated = False # hide_anim = hidden for animation purposes self.hide_anim = False # drop_value = value to be dropped during animation self.drop_value = None # drop_to could have inversely been a drop_from # drop_to = the id of where the value should be dropped too. self.drop_to = None def __str__(self): return "%2d" % self.value class GameGrid(): def __init__(self, cols=8, rows=7, **kwargs): if cols < 3 or rows < 3: raise ValueError("Minimum board size is 3x3! %sx%s is too small." % (cols, rows)) self.cols = cols self.rows = rows self.values = [5, 6, 11, 19, 20] self.make_grid() def make_grid(self): # grid is 2d array as x, y ie [x][y]. self.grid = [] for row_num in range(self.rows): # Do you still think this needs to be broken into a smaller method? row = [GameTile(col_num, row_num, self.values) for col_num in range(self.cols)] self.grid.append(row) self.transposed_grid = list(zip(*self.grid)) def draw(self): for col in self.grid: print(end='| ') for node in col: print(node, end=' | ') print() def draw_by_id(self): for col in self.grid: print(end='| ') for node in col: print(node.id, end=' | ') print() def draw_by_id_trans(self): for col in self.transposed_grid: print(end='| ') for node in col: print(node.id, end=' | ') print() def draw_by_id_proc(self): # Draw Procedurally for col_num in range(self.cols): print(end='| ') for row_num in range(self.rows): print(self.grid[col_num][row_num].id, '(' + str(col_num) + ',' + str(row_num) + ')', end=' | ') print() def find_eliminations(self): #First Down the columns. i = 0 for col_list in self.transposed_grid: while True: try: if self.check_total(col_list[i: i + 3]): self.eliminate(col_list[i: i + 3]) i += 1 except ValueError: i = 0 break # Now across the rows. for row_list in self.grid: while True: try: if self.check_total(row_list[i: i + 3]): self.eliminate(row_list[i: i + 3]) i += 1 except ValueError: i = 0 break # Set all eliminated nodes to a value of 0. for col in self.grid:
Re: [Tutor] Improving My Simple Game Code for Speed, Memory and Learning
Now I have the output that I expect and procedurally they output matches the id of the Node/Tile. But I am thoroughly confused as to why my by_id functions use the opposite grid to get the correct output? # Output python3 test1.py | 6 | 20 | 19 | 11 | 11 | 20 | 5 | 11 | | 20 | 19 | 20 | 11 | 11 | 19 | 19 | 20 | | 6 | 19 | 19 | 6 | 5 | 20 | 5 | 11 | | 11 | 5 | 5 | 11 | 11 | 6 | 6 | 5 | By ID | 0,0 | 1,0 | 2,0 | 3,0 | | 0,1 | 1,1 | 2,1 | 3,1 | | 0,2 | 1,2 | 2,2 | 3,2 | | 0,3 | 1,3 | 2,3 | 3,3 | | 0,4 | 1,4 | 2,4 | 3,4 | | 0,5 | 1,5 | 2,5 | 3,5 | | 0,6 | 1,6 | 2,6 | 3,6 | | 0,7 | 1,7 | 2,7 | 3,7 | Procedurally | 0,0 (0,0) | 1,0 (1,0) | 2,0 (2,0) | 3,0 (3,0) | | 0,1 (0,1) | 1,1 (1,1) | 2,1 (2,1) | 3,1 (3,1) | | 0,2 (0,2) | 1,2 (1,2) | 2,2 (2,2) | 3,2 (3,2) | | 0,3 (0,3) | 1,3 (1,3) | 2,3 (2,3) | 3,3 (3,3) | | 0,4 (0,4) | 1,4 (1,4) | 2,4 (2,4) | 3,4 (3,4) | | 0,5 (0,5) | 1,5 (1,5) | 2,5 (2,5) | 3,5 (3,5) | | 0,6 (0,6) | 1,6 (1,6) | 2,6 (2,6) | 3,6 (3,6) | | 0,7 (0,7) | 1,7 (1,7) | 2,7 (2,7) | 3,7 (3,7) | Tansposed | 0,0 | 0,1 | 0,2 | 0,3 | 0,4 | 0,5 | 0,6 | 0,7 | | 1,0 | 1,1 | 1,2 | 1,3 | 1,4 | 1,5 | 1,6 | 1,7 | | 2,0 | 2,1 | 2,2 | 2,3 | 2,4 | 2,5 | 2,6 | 2,7 | | 3,0 | 3,1 | 3,2 | 3,3 | 3,4 | 3,5 | 3,6 | 3,7 | Transposed & Procedurally | 0,0 (0,0) | 0,1 (0,1) | 0,2 (0,2) | 0,3 (0,3) | 0,4 (0,4) | 0,5 (0,5) | 0,6 (0,6) | 0,7 (0,7) | | 1,0 (1,0) | 1,1 (1,1) | 1,2 (1,2) | 1,3 (1,3) | 1,4 (1,4) | 1,5 (1,5) | 1,6 (1,6) | 1,7 (1,7) | | 2,0 (2,0) | 2,1 (2,1) | 2,2 (2,2) | 2,3 (2,3) | 2,4 (2,4) | 2,5 (2,5) | 2,6 (2,6) | 2,7 (2,7) | | 3,0 (3,0) | 3,1 (3,1) | 3,2 (3,2) | 3,3 (3,3) | 3,4 (3,4) | 3,5 (3,5) | 3,6 (3,6) | 3,7 (3,7) | # Code Below import random class GameTile(): def __init__(self, col, row, values=None, value=None, **kwargs): # values is not required because the value can be directly set. # This is to support a future feature that will allow me to build a # board off of a list. # id is grid (X,Y) which is equal to grid (col,row) self.id = str(col) + ',' + str(row) self.col = col self.row = row if value is None: value = random.choice(values) self.value = value self.eliminated = False # hide_anim = hidden for animation purposes self.hide_anim = False # drop_value = value to be dropped during animation self.drop_value = None # drop_to could have inversely been a drop_from # drop_to = the id of where the value should be dropped too. self.drop_to = None def __str__(self): return "%2d" % self.value class GameGrid(): def __init__(self, cols=8, rows=7, **kwargs): if cols < 3 or rows < 3: raise ValueError("Minimum board size is 3x3! %sx%s is too small." % (cols, rows)) self.cols = cols self.rows = rows self.values = [5, 6, 11, 19, 20] self.make_grid() def make_grid(self): # grid is 2d array as x, y ie [x][y]. self.transposed_grid = [] for row_num in range(self.rows): # Do you still think this needs to be broken into a smaller method? row = [GameTile(col_num, row_num, self.values) for col_num in range(self.cols)] self.transposed_grid.append(row) self.grid = list(zip(*self.transposed_grid)) def draw(self): for row in self.grid: print(end='| ') for node in row: print(node, end=' | ') print() def draw_by_id(self): # Why does this one use self.transposed_grid instead of self.grid ? for row in self.transposed_grid: print(end='| ') for node in row: print(node.id, end=' | ') print() def draw_by_id_proc(self): # Draw Procedurally for row_num in range(self.rows): print(end='| ') for col_num in range(self.cols): print(self.grid[col_num][row_num].id, '(' + str(col_num) + ',' + str(row_num) + ')', end=' | ') print() def draw_by_id_trans(self): # Why does this one use self.grid instead of self.transposed_grid ? for col in self.grid: print(end='| ') for node in col: print(node.id, end=' | ') print() def draw_by_id_proc_trans(self): # Draw Procedurally & Transposed for col_num in range(self.cols): print(end='| ') for row_num in range(self.rows): print(self.transposed_grid[row_num][col_num].id, '(' + str(col_num) + ',' + str(row_num) + ')', end=' | ') print() def find_eliminations(self): #First Down the columns. i = 0 for col_list in self.transposed_grid: while True: try: if self.check_total(col_list[i: i + 3]): self.eliminate(co
Re: [Tutor] Improving My Simple Game Code for Speed, Memory and Learning
I fixed the other functions to again work as expected. But the procedural access of the self.grid and self.transposed_grid also function correctly. That is good because now I can again do lookups if I need to. Although I do not have a need to at this time. Can anyone see anything wrong with the logic as it is at this time? If anyone has any improvements or things to think about, I would love to hear it. I am going to work on some tests that will specifically involve the procedural code to verify that the id's are arranged in the grid as I expect them to be. I would also appreciate an explanation of why my by_id functions use the opposite grid to get the correct output? #Output Below python3 test1.py | 19 | 11 | 5 | 19 | | 11 | 19 | 19 | 5 | | 20 | 19 | 20 | 6 | | 11 | 19 | 11 | 5 | | 11 | 6 | 5 | 20 | | 6 | 5 | 19 | 19 | | 20 | 19 | 20 | 20 | | 6 | 20 | 19 | 20 | After Eliminations | 19 | 0 | 5 | 19 | | 0 | 0 | 0 | 5 | | 0 | 0 | 20 | 6 | | 0 | 19 | 11 | 5 | | 0 | 6 | 5 | 20 | | 0 | 5 | 19 | 19 | | 20 | 19 | 20 | 20 | | 6 | 20 | 19 | 20 | After Drops | 0 | 0 | 0 | 19 | | 0 | 0 | 5 | 5 | | 0 | 0 | 20 | 6 | | 0 | 19 | 11 | 5 | | 0 | 6 | 5 | 20 | | 19 | 5 | 19 | 19 | | 20 | 19 | 20 | 20 | | 6 | 20 | 19 | 20 | By ID | 0,0 | 1,0 | 2,0 | 3,0 | | 0,1 | 1,1 | 2,1 | 3,1 | | 0,2 | 1,2 | 2,2 | 3,2 | | 0,3 | 1,3 | 2,3 | 3,3 | | 0,4 | 1,4 | 2,4 | 3,4 | | 0,5 | 1,5 | 2,5 | 3,5 | | 0,6 | 1,6 | 2,6 | 3,6 | | 0,7 | 1,7 | 2,7 | 3,7 | Procedurally | 0,0 (0,0) | 1,0 (1,0) | 2,0 (2,0) | 3,0 (3,0) | | 0,1 (0,1) | 1,1 (1,1) | 2,1 (2,1) | 3,1 (3,1) | | 0,2 (0,2) | 1,2 (1,2) | 2,2 (2,2) | 3,2 (3,2) | | 0,3 (0,3) | 1,3 (1,3) | 2,3 (2,3) | 3,3 (3,3) | | 0,4 (0,4) | 1,4 (1,4) | 2,4 (2,4) | 3,4 (3,4) | | 0,5 (0,5) | 1,5 (1,5) | 2,5 (2,5) | 3,5 (3,5) | | 0,6 (0,6) | 1,6 (1,6) | 2,6 (2,6) | 3,6 (3,6) | | 0,7 (0,7) | 1,7 (1,7) | 2,7 (2,7) | 3,7 (3,7) | Tansposed | 0,0 | 0,1 | 0,2 | 0,3 | 0,4 | 0,5 | 0,6 | 0,7 | | 1,0 | 1,1 | 1,2 | 1,3 | 1,4 | 1,5 | 1,6 | 1,7 | | 2,0 | 2,1 | 2,2 | 2,3 | 2,4 | 2,5 | 2,6 | 2,7 | | 3,0 | 3,1 | 3,2 | 3,3 | 3,4 | 3,5 | 3,6 | 3,7 | Transposed & Procedurally | 0,0 (0,0) | 0,1 (0,1) | 0,2 (0,2) | 0,3 (0,3) | 0,4 (0,4) | 0,5 (0,5) | 0,6 (0,6) | 0,7 (0,7) | | 1,0 (1,0) | 1,1 (1,1) | 1,2 (1,2) | 1,3 (1,3) | 1,4 (1,4) | 1,5 (1,5) | 1,6 (1,6) | 1,7 (1,7) | | 2,0 (2,0) | 2,1 (2,1) | 2,2 (2,2) | 2,3 (2,3) | 2,4 (2,4) | 2,5 (2,5) | 2,6 (2,6) | 2,7 (2,7) | | 3,0 (3,0) | 3,1 (3,1) | 3,2 (3,2) | 3,3 (3,3) | 3,4 (3,4) | 3,5 (3,5) | 3,6 (3,6) | 3,7 (3,7) | # Code Below import random class GameTile(): def __init__(self, col, row, values=None, value=None, **kwargs): # values is not required because the value can be directly set. # This is to support a future feature that will allow me to build a # board off of a list. # id is grid (X,Y) which is equal to grid (col,row) self.id = str(col) + ',' + str(row) self.col = col self.row = row if value is None: value = random.choice(values) self.value = value self.eliminated = False # hide_anim = hidden for animation purposes self.hide_anim = False # drop_value = value to be dropped during animation self.drop_value = None # drop_to could have inversely been a drop_from # drop_to = the id of where the value should be dropped too. self.drop_to = None def __str__(self): return "%2d" % self.value class GameGrid(): def __init__(self, cols=8, rows=7, **kwargs): if cols < 3 or rows < 3: raise ValueError("Minimum board size is 3x3! %sx%s is too small." % (cols, rows)) self.cols = cols self.rows = rows self.values = [5, 6, 11, 19, 20] self.make_grid() def make_grid(self): # grid is 2d array as x, y ie [x][y]. self.transposed_grid = [] for row_num in range(self.rows): # Do you still think this needs to be broken into a smaller method? row = [GameTile(col_num, row_num, self.values) for col_num in range(self.cols)] self.transposed_grid.append(row) self.grid = list(zip(*self.transposed_grid)) def draw(self): for row in self.transposed_grid: print(end='| ') for node in row: print(node, end=' | ') print() def draw_by_id(self): # Why does this one use self.transposed_grid instead of self.grid ? for row in self.transposed_grid: print(end='| ') for node in row: print(node.id, end=' | ') print() def draw_by_id_proc(self): # Draw Procedurally for row_num in range(self.rows): print(end='| ') for col_num in range(self.cols): print(self.grid[col_num][row_num].id, '(' + str(col_num) + ',' + str(row_num) + ')', end=' | ')
Re: [Tutor] Improving My Simple Game Code for Speed, Memory and Learning
I haven't looked carefully at your code but there's always a smell in Python when you see structure[x][y]. Can you change the grid so you always write something like:- for row in grid: for cell in row: process(cell) I say this as I'm all for short term pain, long term gain, especially when it's guaranteed to eliminate "list index out of range" errors. I think in this case I have to say no. I purposely wrote those "proc" or "procedurally" style functions to ensure that access to the grid in this way would result in the correct output from id, and to test that it worked as expected. However there are other places in my code where I think I can eliminate this smell such as the new function that drops the non-zero values. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Improving My Simple Game Code for Speed, Memory and Learning
On 01/12/2015 05:00 PM, Alan Gauld wrote: Sorry, no time to read the detail, but one thing I thought might be handy is to convert the draw method to return a string and make it the __str__methodf of the grid. Then the draw method becomes print(self) And you can also just use print(aGrid) etc. Something like (untested): def __str__(self): output = [] for row in self.transposed_grid: s='| ' for node in row: s += (str(node) + ' | ') output.append(s) return '\n'.join(output) def draw(self): print (self) Just a thought. OK. I will implement this, thanks. It goes well with the __str__ method of the tiles/nodes. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Improving My Simple Game Code for Speed, Memory and Learning
On 01/12/2015 05:00 PM, Alan Gauld wrote: __str__methodf of the grid. Then the draw method becomes print(self) And you can also just use print(aGrid) etc. Implemented with some other improvements using the same idea but applied to several of the other functions, that provide output. Now I am going to try and add the ability to have the table generated but with a set number of rows empty or pre-set to zero. #CODE BELOW import random class GameTile(): def __init__(self, col, row, values=None, value=None, **kwargs): # values is not required because the value can be directly set. # This is to support a future feature that will allow me to build a # board off of a list. # id is grid(X,Y) which is equal to grid(col,row) self.id = str(col) + ',' + str(row) self.col = col self.row = row if value is None: value = random.choice(values) self.value = value self.eliminated = False # hide_anim = hidden for animation purposes self.hide_anim = False # drop_value = value to be dropped during animation self.drop_value = None # drop_to could have inversely been a drop_from # drop_to = the id of where the value should be dropped too. self.drop_to = None def __str__(self): return "%2d" % self.value class GameGrid(): def __init__(self, cols=8, rows=7, **kwargs): if cols < 3 or rows < 3: raise ValueError("Minimum board size is 3x3! %sx%s is too small." % (cols, rows)) self.cols = cols self.rows = rows self.values = [5, 6, 11, 19, 20] self.make_grid() def __str__(self): output = [] for row in self.transposed_grid: s = '| ' for node in row: s += str(node) + ' | ' output.append(s) return '\n'.join(output) def make_grid(self): # grid is 2d array as x, y ie [x][y]. # transposed_grid is 2d array as y, x ie [y][x] self.transposed_grid = [] for row_num in range(self.rows): row = [GameTile(col_num, row_num, self.values) for col_num in range(self.cols)] self.transposed_grid.append(row) self.grid = list(zip(*self.transposed_grid)) def draw(self): print(self) def draw_by_id(self): # Why does this one use self.transposed_grid instead of self.grid ? output = [] for row in self.transposed_grid: s = '| ' for node in row: s += str(node.id) + ' | ' output.append(s) return '\n'.join(output) def draw_by_id_proc(self): # Draw Procedurally output = [] for row_num in range(self.rows): s = '| ' for col_num in range(self.cols): s += (str(self.grid[col_num][row_num].id) + '(' + str(col_num) + ',' + str(row_num) + ')' + ' | ') output.append(s) return '\n'.join(output) def draw_by_id_trans(self): # Why does this one use self.grid instead of self.transposed_grid ? output = [] for col in self.grid: s = '| ' for node in col: s += str(node.id) + ' | ' output.append(s) return '\n'.join(output) def draw_by_id_trans_proc (self): # Draw Transposed & Procedurally output = [] for col_num in range(self.cols): s = '| ' for row_num in range(self.rows): s += (str(self.transposed_grid[row_num][col_num].id) + '(' + str(col_num) + ',' + str(row_num) + ')' + ' | ') output.append(s) return '\n'.join(output) def find_eliminations(self): #First Down the columns. i = 0 for col_list in self.grid: while True: try: if self.check_total(col_list[i: i + 3]): self.eliminate(col_list[i: i + 3]) i += 1 except ValueError: i = 0 break # Now across the rows. for row_list in self.transposed_grid: while True: try: if self.check_total(row_list[i: i + 3]): self.eliminate(row_list[i: i + 3]) i += 1 except ValueError: i = 0 break # Set all eliminated nodes to a value of 0. for col in self.transposed_grid: for node in col: if node.eliminated is True: node.eliminated = False node.value = 0 def check_total(self, slices): first, second, third = slices if first.value == second.value or second.value == third.value: total = first.
Re: [Tutor] Improving My Simple Game Code for Speed, Memory and Learning
Updated the code to now allow for a fill_rows optional argument for Grid, that determines how many rows are filled with values. I have also added some experimental code to invert the dropping, as in all of the values can float to the top. Other code is even more experimental and not yet working right that pulls the nodes to the right or left, with hope of being able to apply gravity in all 4 directions. But I still need to work out the bugs. Any help is greatly appreciated. Thanks for all of the contributions so far. #CODE BELOW import random class GameTile(): def __init__(self, col, row, values=None, value=None, **kwargs): # values is not required because the value can be directly set. # This is to support a future feature that will allow me to build a # board off of a list. # id is grid(X,Y) which is equal to grid(col,row) self.id = str(col) + ',' + str(row) self.col = col self.row = row if value is None: value = random.choice(values) self.value = value self.eliminated = False # hide_anim = hidden for animation purposes self.hide_anim = False # drop_value = value to be dropped during animation self.drop_value = None # drop_to could have inversely been a drop_from # drop_to = the id of where the value should be dropped too. self.drop_to = None def __str__(self): return "%2d" % self.value class GameGrid(): def __init__(self, cols=8, rows=7, fill_rows=None, **kwargs): if cols < 3 or rows < 3: raise ValueError('Minimum board size is 3x3! %sx%s is too small.' % (cols, rows)) if fill_rows > rows: string = 'Can not fill more rows than actual rows ' + \ 'exist. fill_rows=%s rows=%s' raise ValueError(string % (fill_rows, rows)) self.cols = cols self.rows = rows self.values = [5, 6, 11, 19, 20] self.make_grid(fill_rows) def __str__(self): output = [] for row in self.transposed_grid: s = '| ' for node in row: s += str(node) + ' | ' output.append(s) return '\n'.join(output) def make_grid(self, fill_rows=None): # grid is 2d array as x, y ie [x][y]. # transposed_grid is 2d array as y, x ie [y][x] self.transposed_grid = [] for row_num in range(self.rows): if fill_rows is None: values = self.values elif row_num < self.rows - fill_rows: values = [0, ] else: values = self.values row = [GameTile(col_num, row_num, values) for col_num in range(self.cols)] self.transposed_grid.append(row) self.grid = list(zip(*self.transposed_grid)) def draw(self): print(self) def draw_by_id(self): # Why does this one use self.transposed_grid instead of self.grid ? output = [] for row in self.transposed_grid: s = '| ' for node in row: s += str(node.id) + ' | ' output.append(s) return '\n'.join(output) def draw_by_id_proc(self): # Draw Procedurally output = [] for row_num in range(self.rows): s = '| ' for col_num in range(self.cols): s += (str(self.grid[col_num][row_num].id) + '(' + str(col_num) + ',' + str(row_num) + ')' + ' | ') output.append(s) return '\n'.join(output) def draw_by_id_trans(self): # Why does this one use self.grid instead of self.transposed_grid ? output = [] for col in self.grid: s = '| ' for node in col: s += str(node.id) + ' | ' output.append(s) return '\n'.join(output) def draw_by_id_trans_proc (self): # Draw Transposed & Procedurally output = [] for col_num in range(self.cols): s = '| ' for row_num in range(self.rows): s += (str(self.transposed_grid[row_num][col_num].id) + '(' + str(col_num) + ',' + str(row_num) + ')' + ' | ') output.append(s) return '\n'.join(output) def find_eliminations(self): #First Down the columns. i = 0 for col_list in self.grid: while True: try: if self.check_total(col_list[i: i + 3]): self.eliminate(col_list[i: i + 3]) i += 1 except ValueError: i = 0 break # Now across the rows. for row_list in self.transposed_grid: while True: try: if self.check_total(row_list[i: i + 3]): self.eliminate(ro
Re: [Tutor] Improving My Simple Game Code for Speed, Memory and Learning
On 01/12/2015 04:47 PM, Mark Lawrence wrote: I haven't looked carefully at your code but there's always a smell in Python when you see structure[x][y]. Can you change the grid so you always write something like:- for row in grid: for cell in row: process(cell) I say this as I'm all for short term pain, long term gain, especially when it's guaranteed to eliminate "list index out of range" errors. Revisiting this, I think I will write a function specifically to perform look-ups, kind of like your process() function. My purpose is going to be to prevent out of bounds look-ups. Although none of my posted code has had potential for this so far, I am writing more code to help play the game and one of the things I am needing now is to look at the neighbours of a selected node. This look-up can provide me two errors, one is the index out of range the and the more subtle error is going backwards in the list and giving me the end of the list which is not a valid neighbour. I will also use this look-up throughout the rest of my code where possible. Thank you Mark. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Idle - ImportError: No module named numpy
Well on the python interpretor did you use python3 or just python? On 03/06/2015 01:27 PM, Markos wrote: Hi, I'm beginning to study the numpy. When I open a terminal (Debian Squeeze) and run the python interpreter the command "import numpy as np" run without errors. But when I run the same command on idle3 the following error appears. >>> import numpy as np Traceback (most recent call last): File "", line 1, in import numpy as np ImportError: No module named numpy How configure idle to load the numpy module? Thanks, Markos ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
[Tutor] Functional Programming in Python
These are just some questions that I have regarding the topic of Functional Programming. I am working towards a more functional approach to programming but acknowledge that it is far from Functional, especially since this is mostly impossible in Python. Questions: What are the best practices to create more Functional Python? What are your thoughts on Functional in Python? Currently I am re-writing functions to reduce their side effects. I am also removing the state from objects and putting it into a closure type function. However with callback based systems (GUI) this seemed impossible, so instead I am abusing a coroutine to maintain the state of the application. But is it abuse or does it seem like a good way to handle the callback system? The benefit to me at this time is limited, but any errors in state are confined to a single location, which is nice. What do you think about using a coroutine to handle state, how would you do it better in a callback based system. Thank you for your insights. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Functional Programming in Python
On 04/02/2015 01:07 PM, Alan Gauld wrote: I'm not sure what you mean is impossible? The specific issues you are having or the general FP paradigm? I mean achieving truely functional code, atleast to the extent of some of the things that I have read. But in general I do not need nor want any of those special features. I.E. single assignment, optimized tail call, etc. Python has fairly good support for FP, much better than most non-FP-specific languages. I agree. Everything goes in functions which do not change their inputs and return outputs. I am getting better at this. Use tools like itertools and functools to avoid explicit loops. I am beginning to use them more. What are your thoughts on Functional in Python? It's good enough to use where the problem suits FP. It's no more a pure FP language than it is a pure OOP language. But in both cases you can get close enough for practical purposes. What is your problem scenario that makes FP seem like the best idiom? Since I am making a game, three things got out of control. 1. Managing transitions and instances of objects between transitions. Like loading the Main Menu then starting a Game, then returning to the Menu and Starting a New Game, the old game was still hanging around in memory which becomes a problem on Phones. 2. Side effects have gotten out of hand, and so adding a feature often meant adding bugs. 3. Duplication of code got out of hand. Several functions doing similar things but slightly different. I turned this into pipe-lining to reduce out the different cases and eliminate the duplication. But since it is a game the amount of state does make FP seem very difficult and thus the game is a mixture of OOP and FP, which I am glad to see people saying mix as needed. Currently I am re-writing functions to reduce their side effects. Good, nearly always the best way. I am also removing the state from objects and putting it into a closure type function. That may or may not be a good idea. FP object handling can get awfully messy and awfully inefficient. However with callback based systems (GUI) this seemed impossible, so instead I am abusing a coroutine to maintain the state of the application. Trying to force a non-FP framework(eg a GUI)_ to work in an FP way is usually an exercise in frustration. Yeah, it took me awhile to think about what to do in this case. Thus I decided it was best to accept that the interface between the GUI and my code had to be more OOP. But is it abuse or does it seem like a good way to handle the callback system? The benefit to me at this time is limited, but any errors in state are confined to a single location, which is nice. That should be true in an OOP based system too. The whole point of OOP is to contain and hide state (as opposed to eliminating it) I think since I am mostly self taught I perhaps failed to learn this containment of state until recently. So before now it was fairly common for my state to be spread out amongst several objects. It seems hard for me to contain state in a OOP manor, just because it is so easy to use self. What do you think about using a coroutine to handle state, how would you do it better in a callback based system. Without seeing how you are doing it we can't comment on *better*. We need a baseline. Your approach may be brilliant, or it may be awful, we can't tell. Yeah probably not brilliant. More like hopefully not completely stupid. But remember that there is no such thing as the perfect paradigm. FP has many strengths but it has many weaknesses too. As does OOP. Even procedural programming has advantages over OOP and FP in some circumstances. By all means learn the paradigms, but don't get hung up on any one. They all play a part. Agreed. I am still trying to learn the right mixture. The GUI is Kivy, but I could probably apply the same concept to QT. Example of my Abused coroutine: def coroutine(func): # A decorator function that takes care of starting a coroutine # automatically on call. def start(*args, **kwargs): cr = func(*args, **kwargs) cr.send(None) return cr return start @coroutine def app_state(APP): # APP = kivy.app.App.get_running_app() # So you know what APP is. while True: signal = yield # Pass if signal is None or less than 1. if signal >= 0 and signal < 1: pass # Ignore this range elif signal >= 1 and signal < 2: if signal == 1.01: # Load Main Menu print('Load File for Displaying Main Menu') # This acts as a callback with the benefit of yielding # to Kivy's main loop. kivy.clock.Clock.schedule_once(APP.signal, 0) yield 1.02 print('Add Main Menu to ScreenManager.') kivy.clock.Clock.schedule_once(APP.signal, 0) yield 1.03 print('Start Music for Main Menu')
Re: [Tutor] Functional Programming in Python
On 04/02/2015 02:07 PM, Steven D'Aprano wrote: What are the best practices to create more Functional Python? Best practices: * Don't force your code to use one style exclusively. Use the most natural style for the task. Python makes it easy to mix functional, procedural, imperative and object oriented code in the one application. Use whatever is most natural for your task. Good point, but still trying to understand how this is best determined beyond trial and error, and to make sure that my assumptions are correct about this decision. * Where possible, write your functions and methods in a functional style. That means: - Avoid global variables. I have got this down. - Avoid side-effects where possible. Now getting better at this. - Separate the logic of your algorithm from the display of results (e.g. don't have a method that calculates a result AND prints it; have the method calculate the result, and then have the caller print it). Need to always do this and do it first rather than during re-factoring. - Many uses of map() and filter() are better written as generator expressions; e.g. instead of: I now understand generators and I am now using them whenever I see the opportunity. filter(lambda s: s.lower().startswith("a"), map(str, mylist)) you can use: (str(x) for x in mylist if s.lower().startswith("a")) - Where useful, write your code to take advantage of "pipelining" style, e.g. using lazy iterators rather than lists. You can then chain iterators together to get the desired result. Yes I have started to do this since seeing the power of pipe-lining. What do you mean? Can you show an example? I added an example in the reply to Alan. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Functional Programming in Python
On 04/02/2015 02:52 PM, Danny Yoo wrote: This is not to say that closures are bad. It's just to point out that just because functional programs use closures quite a lot, doesn't automatically mean closures are the most appropriate tool for everything. If there are parts of the language that already do the sort of thing you're trying to accomplish, it might be good to reuse those parts, rather than reinvent the universe. I agree that closures are not the best tool for every job. And in the case of a callback based GUI they simply do not work, since execution needs to leave a function in order to run the GUI's main loop. Thus I abused a coroutine. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Functional Programming in Python
On 04/02/2015 03:08 PM, Tim Johnson wrote: You have already received valuable replies from two advanced python experts. If you are looking for a book (available digitally for kindle) I would recommend Guide To: Functional Python & Comprehension Constructs by Matt Harrison Thanks I will look into this book. I have been reading a lot of articles on the topic lately. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Functional Programming in Python
So I was surprised I did not get more feedback on my abused coroutine, maybe that is good or bad, not sure. Any ways I am on to trying to make that coroutine act more like the State Pattern from Gang of Four. And well reading this: http://gameprogrammingpatterns.com/state.html I am not sure how to do this: class Heroine { public: virtual void handleInput(Input input) { state_->handleInput(*this, input); } virtual void update() { state_->update(*this); } // Other methods... private: HeroineState* state_; }; (Pointing to the different classes. Since C++ has virtual methods but Python does not?) in Python? Do I just reference the new method? Because state_ will always be the correct object? ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor