I'm not sure if we ever covered ALL of the formatters for substitution, but like absolutely everything else, it's covered in the Python Documentation. From the link provided, scroll down a bit, and check "coversion types." There's a lot more than I use in any of the examples that are available. One of the ones that's really nice is the %r, which outputs raw data. This can be useful for debugging programs.
The line is actually broken like that. It will work, and as I move on you'll see much more pep8 compliance, as I simply have improved in my formatting a lot recently. Lines over 79 characters are a big NO-NO!
OK, so I'll look at substitutions as a learn as I go idea if there are that many.
No sense in choking on "non-baby food" at this level.
Thanks for the link ...
You talked about "pep8" & '79' being a magic number on the first page. So I 'should' have known.
I stopped at the end of Page 1 for a bit to do my thing: Conky
BunsenLabs Forums now Open for Registration
I've benefited from your lessons here tremendously! Thank you.
*( See  at bottom which qualifies the following)*
In the scripts where you use the while loop;
while 1: #make a loop to handle shutting down if we just hit "close" for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit()
My comp would heat up. I found these scripts were running one core after another up to 100% and my Temps were getting dangerously high.
I found a solution while reading this (for anybody else who might have had this prob)
I changed your while loop just a tad and my comp stays nice and cool while Zorg plays now;
while 1: for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit() clock.tick(60) # limits it to (xx) frames per second """ 'pygame.time.delay(100)' stops the prog for 1/10 secs, (1) stops the prog for 1/1000, more importaintly both keep the 'while loop' from exponentially revving up your core temps. (at least this worked for mine) """ pygame.time.delay(1)
I hope to see more lessons soon
I was thinking about my sloppy debugging method and I realized that debianJoe had mentioned that
the line "clock.tick(60)" limited the programs speed which should have kept the while loop it is in from running wild like it was doing on my system.
One of the things I had done when I added and experimented with the workaround line "pygame.time.delay(1)" was to set the 'clock.tick(60)' line back on the same tab-indent as the "if" statement. (it had been part of the if statement for some reason instead of following the if statement in the while loop). I thought that maybe I should have tested that "clock.tick(60)" in its new position before duct-tapping in the "pygame.time.delay(1)" line to see if that effected the cpu load and consequent heating I experienced.
SSOooo, I went back to my script, commented out the "pygame.time.delay(1)" line and tried it again.
with the "clock.tick(60)" line removed from, and thus following, the 'if' statement my first cpu core still briefly hit 100% load but it imediatly went back down to about 8% to 11% and then floated around in the 1 - 3 % load area. With that line "pygame.time.delay(1)" in the while loop my cpu cores never aproach anything above 11% (and that was only for a moment) and my temp doesn't move up at all.
I don't know much about this stuff so I probably have this figured out bassakwards some how but there's what I experienced, what I did to change it, and how it is acting now. (I'm hopping somebody will set me straight and tell me if I got any of it right).
Cheers, I'm looking forward to learning more of this
Last edited by dan158 (2013-07-27 10:32:33)
Hopefully, someone else would be willing to pick up this thread. I've recently picked up far to much work beyond teaching to really do it justice. If anyone would like to take over, send me an e-mail, & I'll send you what I was working on and leading up to the last lesson. Should the day come where I have more time, I'll be back.
dan158, I believe you solved that with proper indentation.
Code blocks are defined by their indentation. By "code block", I mean functions, if statements, for loops, while loops, and so forth. Indenting starts a block and unindenting ends it.
time.delay has its uses but it will give you different results on other machines - it always pauses the same amount of time, where the clock.tick will adjust itself depending on each system's performance.
DebianJoe I know how you feel on picking up the extra work 8) If you like you can tar what you have and link it here, who know it might spark! If we can get it to a working state, and let it loose on your class for anyone to self-learn by hacking in their own features.
I'll tell you what, I'll knock out the rest of the code to be functional and throw it up on on the "Beginner's Repo" that hasn't been used yet. What happens after that? I'll probably give you and Frostlock, and anyone else that you guys suggest full access to it. I'll look over any pull requests that come in to possibly catch any errors that would make it unusable for others, and it'll be available for anyone to use as they see fit.
I found a nice little memory puzzle that's right along the lines of what I'd been doing and simply made the code work with a lot of what we already had. Hack away at this. Make it good.
Beyond that, best of coding to you guys!
The week's coding C# at work left my brain a gooey mush - as would any language with so many curly braces and semi-colons. We love Python for it's kind consideration of your sanity where curly's and semi-colons are concerned.
Following up on DebianJoe's release of the memory puzzle game above, you can find a great post-mortem and detailed discussion about the whole of it at http://inventwithpython.com/pygame/chapter3.html
Now those who are new to hacking features into somebody else's code, I thought it would be nice to give a basic run through how you go about getting to know a piece of code.
At this point you are familiar with what functions and methods are: pieces of reusable code.
So how does one go about hacking features into someone else's code? By reading through the program, become familiar with what the various functions do, and how they are glued together. Easy enough? Well it is, and the more you do this, the easier it gets and the more complex code-bases you can dissect.
# A note on the code editor
Crunchbang comes with Geany out the box, I'll point out a couple of navigation commands for easy code navigation, listed below with suggested keyboard shortcuts that you can set up under the "Help - Keyboard Shortcuts" menu. I will leave you up to discover them.
* Search -> Go to Line (Ctrl-L)
* Search -> More -> Go to tag definition (Alt-F2)
* Go to -> Navigate back / forward a location (Alt-Left/Right)
* Go to -> Toggle marker (Ctrl-M), Go to previous marker (Ctrl-,), Go to next marker (Ctrl-.)
Write these down on a note and stick them to your face or monitor. It helps. Avoid contact glue if possible.
# a note on your brain
Computers are exceptionally good at keeping a list of what instructions it ran, when reading code our brains do the same, a mental list of where we are in our program's call stack. But our brains do not have such a great memory to store lots and lots of jumps from one position to another, but brains are very exceptional at glueing these abstract ideas as a whole. So when reading unfamiliar code we do not read it from top to bottom.
What we do instead is:
1. skim over the foundation on which it is built: imported libraries and constants.
2. find the code entry point and skim through that, once, to get a blueprint of the structure.
3. go back over the code entry, this time descending deeper into other calls of interest.
The first lines import additional libraries used, we see `import random, pygame, sys` and immediately know that any calls prefixed with these keywords reference our imports.
We also see `from pygame.locals import *` and this makes available all the definitions within pygame.locals accessible without requiring any prefix, so `pygame.K_CAPSLOCK` becomes `K_CAPSLOCK`.
A note on import * jargon: This is called polluting the namespace as it introduces a multitude of new variables and functions that do not live within the calling file. This particular case is acceptable because the locals namespace only contains constants that are named in uppercase and do not introduce too much ambiguity about where these new constants originate from.
Next we read over the constants defined in the source, these are defined near the top of the file by convention. Don't bother memorizing their values at this time, or even the name of each one - skim over them to get a feel of what type of data they house:
1. a couple of integers
2. some tuples
3. a few that point to other constants
4. some string constants
5. a list of tuples pointing to other constants
All good so far. Try not get hung up too much here. Take solace in the fact that if we run into a constant later that we need to know the value of, we already know where to look for it.
# the entry point
Python programs start by running everything that has no indentation, particularly this line:
if __name__ == '__main__':
It is a test that passes if the code is being run through the Python interpreter as apposed to being imported as a module in another code file. We search for "__main__" and find it near the end of the file, and it does one thing and does it very well: it calls main().
We cursor over this main() call and hit the "Go to tag definition" shortcut and we jump to the definition. We just entered deep space.
I read through the main() definition without jumping to other function calls. Here is a running commentary of what I see, hmmm...
1. some global variables are loaded, pygame is initialized and some variables are initialized to 0.
2. mainBoard and revealedBoxes are created via function calls.
3. startGameAnimation() is called and then the main game loop kicks in with `while True:`.
4. each loop the display is filled with a color, the board is drawn with drawBoard() and mouse events are handled.
5. tests against revealedBoxes[boxx][boxy], we see the way that variable is accessed that it must be a list of lists, a 2-dimensional array if you will. Good good.
6. tests for mouse over a box, draws highlights, no problems yet.
7. ah, firstSelection stores a tuple of the previously selected box (x, y) position. Nice nice.
8. if there is a firstSelection set we grab the box shapes and colors from both firstSelection and the one under the mouse.
9. if the shapes and colours match it does a little animation dance and resets the revealedBoxes[boxx][boxy] value from earlier.
10. else it tests hasWon(revealedBoxes). this call is a bit vague to me and I'd like to know more about what it does, so I set a marker to look at it later, and continue.
11. a winning move does an animation and resets the game board, the same ones we saw in #2, and the start animation fom #3.
12. unindent from the if-logic and back in the main game loop, pygame does an update() and a clock tick()
# digging deeper
Hey that was pretty painless :-) We found one call of interest at #10, so we jump to our marker and then jump to the hasWon() definition:
It loops through revealedBoxes and tests if each iteration contains False. The `in` keyword indicates that revealedBoxes is most likely a list of values. And if any one of them is False, the function returns False. If the loop passes through unhindered, it returns True. Beautiful like a strawberry.
This opens up curiosity about the structure of revealedBoxes, to confirm our thought on it being a list of spam-values. We recall revealedBoxes being set earlier in the main() call at #2, we navigate there, position our cursor over the getRandomizedBoard() call and hit our Go to tag definition.
The function comment is nicely revealing:
# Get a list of every possible shape in every possible color.
Reading more we see a list is built from each colour and each shape. Essentially a many-to-many relationship of the two lists, known as a cross-join of values. A combination of each possible pair.
This list is then random.shuffle()d, and culled via list slicing to half the number of items to match our game board:
random.shuffle(icons) # randomize the order of the icons list numIconsUsed = int(BOARDWIDTH * BOARDHEIGHT / 2) # calculate how many icons are needed icons = icons[:numIconsUsed] * 2 # make two of each random.shuffle(icons)
It makes sense to only take half, since we double them up to make pairs. The result gets shuffled again after because when they are doubled-up the pairs live in a predictable pattern, easily visualized as such:
>>> l = range(1, 5) >>> l * 2 [1, 2, 3, 4, 1, 2, 3, 4, ]
Then the board data is constructed via looping each row (x) and column (y). It grabs the first icon for each combined iteration, adds it to the list of the current column, and removes that icon with the `del` command.
To visualize the result you could print() out the board, this may be overwhelming with the amount of items though. I find it more understandable to spend 5 minutes to knock out a test application that mimics the functionality - this teaches your brain the code interactively and it sticks better, trust me!
I wrote this up using bpython to see the resulting board data, using mock colors and shapes:
icons =  for color in ('red', 'green', 'blue'): for shape in ('square', 'circle', 'oval'): icons.append((shape, color)) icons # OUT: [('square', 'red'), ('circle', 'red'), ('oval', 'red'), ('square', 'green'), ('circle', 'green'), ('oval', 'green'), ('square', 'blue'), ('circle', 'blue'), ('oval', 'blue')] board =  for x in range(0, 3): column =  for y in range(0, 3): column.append(icons) del icons board.append(column) board # OUT: [[('square', 'red'), ('circle', 'red'), ('oval', 'red')], [('square', 'green'), ('circle', 'green'), ('oval', 'green')], [('square', 'blue'), ('circle', 'blue'), ('oval', 'blue')]]
If I had to indent the board output for readability it would look so:
[ [('square', 'red'), ('circle', 'red'), ('oval', 'red')], [('square', 'green'), ('circle', 'green'), ('oval', 'green')], [('square', 'blue'), ('circle', 'blue'), ('oval', 'blue')] ]
Yup as we thought: a list of lists accessible like a 2D array, board[x][y].
# What next?
It's interesting to browse code like this if you have no particular aim, but is the modus operandi if you are wanting to add a specific feature and need to find out where your new code needs to live.
Want to make the background flash another color when a successful match is made?
You now know where matches are done.
Like to draw images instead of shapes?
Start by writing a test of loading images and drawing them in pygame. You already know where the color and shape constants live, perhaps you can map these to equivalent image files. And we know where the drawBoard() is called from (#4), using the process I described you step back into the calls, until you get to the appropriate draw method, and apply the image drawing.
There are a good couple other functions to dissect. I believe in hands-on learning and will leave you here, dear cookie-munching reader, to apply this process to the other calls. This space intentionally left lacking because I want you to write your own story from here.
Have a feature idea? Write a todo list of what you want to achieve. Then dissect the code, and note down methods and lines where you potentially need to hack in. A little planning goes a long way. And the more you dissect, the more you understand the code, and the better you know where changes will go.
There is no magic here, your brain is an exquisite learning machine and practice is the best teacher.
Now go, fly, fly monkeys and hack away 8o
Stopping in just to say:
"Man, it would sure be cool if I could tell how good I was at memory by having a score based on Correct Guesses / Total guesses (then perhaps set against a multiplier to make it a big number)....like a way to keep score between my games."
*wanders back off into the sunset*
Reading up on this thread again I see there is some juicy code waiting for me in the beginner repo. I'll be sure to take a look :-)
In the spirit of this class I have been busy learning more python. I had some fun by combining the subject of Magic The Gathering with python, Tkinter, SQLite and HTML parsing. Behold my own little database of Magic Cards... ALL Magic Cards, images included. Muhaha 8)
Not sure were I want to go with this particular side project but me and my inner nerd had a lot of fun and thats what it is all about.
Keep it up everyone!
Sounds cool Frostlock! It's been a while since I played MTG (Return to Ravnica core) and it gave me ideas to make a turn based tabletop like app to play card games with mates via the net - then I found there are quite a few of those around already. I have been working on my cyberspace themed rpg with roguelike elements and have no plans for a tabletop card game engine yet.
It feels like this thread has passed way in front of the peeps following it, can we get a reply from all still following the see where you are, any questions or ideas? How about we build a small feature list for the next version of the Memory Puzzle game?
I had a look at that memory game in the beginner repo. Very nice!!!
For such a small number of lines of code it is a really nifty app
If you are still new at all this python stuff (and I'm hoping we still have some beginners following the thread) I would recommend to just grab a copy of the code and:
1. make it run (and try to beat the game )
2. change some colors, put your mark on it in some way, big or small.
3. keep at it until it breaks, then fix it rinse and repeat!